Repository: fairygui/FairyGUI-unreal Branch: master Commit: 2e2a5dd5f851 Files: 197 Total size: 810.9 KB Directory structure: gitextract_s53mm5l5/ ├── .gitignore ├── FairyGUI.uplugin ├── LICENSE ├── README.md └── Source/ ├── FairyGUI/ │ ├── FairyGUI.Build.cs │ ├── Private/ │ │ ├── Event/ │ │ │ ├── EventContext.cpp │ │ │ └── EventTypes.cpp │ │ ├── FairyApplication.cpp │ │ ├── FairyBlueprintLibrary.cpp │ │ ├── FairyCommons.cpp │ │ ├── FairyGUIModule.cpp │ │ ├── Tween/ │ │ │ ├── EaseManager.cpp │ │ │ ├── GPath.cpp │ │ │ ├── GTween.cpp │ │ │ ├── GTweener.cpp │ │ │ ├── TweenManager.cpp │ │ │ └── TweenValue.cpp │ │ ├── UI/ │ │ │ ├── ControllerAction/ │ │ │ │ ├── ChangePageAction.cpp │ │ │ │ ├── ControllerAction.cpp │ │ │ │ └── PlayTransitionAction.cpp │ │ │ ├── DragDropManager.cpp │ │ │ ├── GButton.cpp │ │ │ ├── GComboBox.cpp │ │ │ ├── GComponent.cpp │ │ │ ├── GController.cpp │ │ │ ├── GGraph.cpp │ │ │ ├── GGroup.cpp │ │ │ ├── GImage.cpp │ │ │ ├── GLabel.cpp │ │ │ ├── GList.cpp │ │ │ ├── GLoader.cpp │ │ │ ├── GLoader3D.cpp │ │ │ ├── GMovieClip.cpp │ │ │ ├── GObject.cpp │ │ │ ├── GObjectPool.cpp │ │ │ ├── GProgressBar.cpp │ │ │ ├── GRichTextField.cpp │ │ │ ├── GRoot.cpp │ │ │ ├── GScrollBar.cpp │ │ │ ├── GSlider.cpp │ │ │ ├── GTextField.cpp │ │ │ ├── GTextInput.cpp │ │ │ ├── GTree.cpp │ │ │ ├── GTreeNode.cpp │ │ │ ├── GWindow.cpp │ │ │ ├── Gears/ │ │ │ │ ├── GearAnimation.cpp │ │ │ │ ├── GearBase.cpp │ │ │ │ ├── GearColor.cpp │ │ │ │ ├── GearDisplay.cpp │ │ │ │ ├── GearDisplay2.cpp │ │ │ │ ├── GearFontSize.cpp │ │ │ │ ├── GearIcon.cpp │ │ │ │ ├── GearLook.cpp │ │ │ │ ├── GearSize.cpp │ │ │ │ ├── GearText.cpp │ │ │ │ └── GearXY.cpp │ │ │ ├── PackageItem.cpp │ │ │ ├── PopupMenu.cpp │ │ │ ├── RelationItem.cpp │ │ │ ├── Relations.cpp │ │ │ ├── ScrollPane.cpp │ │ │ ├── Transition.cpp │ │ │ ├── TranslationHelper.cpp │ │ │ ├── UIConfig.cpp │ │ │ ├── UIObjectFactory.cpp │ │ │ └── UIPackage.cpp │ │ ├── UIPackageAsset.cpp │ │ ├── Utils/ │ │ │ ├── ByteBuffer.cpp │ │ │ ├── HTMLElement.cpp │ │ │ ├── HTMLParser.cpp │ │ │ ├── NVariant.cpp │ │ │ ├── UBBParser.cpp │ │ │ ├── XMLAttributes.cpp │ │ │ └── XMLIterator.cpp │ │ └── Widgets/ │ │ ├── BitmapFont.cpp │ │ ├── BitmapFontRun.cpp │ │ ├── HitTest.cpp │ │ ├── LoaderRun.cpp │ │ ├── Mesh/ │ │ │ ├── EllipseMesh.cpp │ │ │ ├── FillMesh.cpp │ │ │ ├── MeshFactory.cpp │ │ │ ├── PolygonMesh.cpp │ │ │ ├── RectMesh.cpp │ │ │ ├── RegularPolygonMesh.cpp │ │ │ ├── RoundedMesh.cpp │ │ │ └── VertexHelper.cpp │ │ ├── NGraphics.cpp │ │ ├── NTextFormat.cpp │ │ ├── NTexture.cpp │ │ ├── SContainer.cpp │ │ ├── SDisplayObject.cpp │ │ ├── SFImage.cpp │ │ ├── SMovieClip.cpp │ │ ├── SShape.cpp │ │ ├── STextField.cpp │ │ └── STextInput.cpp │ └── Public/ │ ├── Event/ │ │ ├── EventContext.h │ │ └── EventTypes.h │ ├── FairyApplication.h │ ├── FairyBlueprintLibrary.h │ ├── FairyCommons.h │ ├── FairyGUI.h │ ├── FairyGUIModule.h │ ├── Tween/ │ │ ├── EaseManager.h │ │ ├── EaseType.h │ │ ├── GPath.h │ │ ├── GTween.h │ │ ├── GTweener.h │ │ ├── TweenManager.h │ │ ├── TweenValue.h │ │ └── TweenerHandle.h │ ├── UI/ │ │ ├── ControllerAction/ │ │ │ ├── ChangePageAction.h │ │ │ ├── ControllerAction.h │ │ │ └── PlayTransitionAction.h │ │ ├── DragDropManager.h │ │ ├── FieldTypes.h │ │ ├── GButton.h │ │ ├── GComboBox.h │ │ ├── GComponent.h │ │ ├── GController.h │ │ ├── GGraph.h │ │ ├── GGroup.h │ │ ├── GImage.h │ │ ├── GLabel.h │ │ ├── GList.h │ │ ├── GLoader.h │ │ ├── GLoader3D.h │ │ ├── GMovieClip.h │ │ ├── GObject.h │ │ ├── GObjectPool.h │ │ ├── GProgressBar.h │ │ ├── GRichTextField.h │ │ ├── GRoot.h │ │ ├── GScrollBar.h │ │ ├── GSlider.h │ │ ├── GTextField.h │ │ ├── GTextInput.h │ │ ├── GTree.h │ │ ├── GTreeNode.h │ │ ├── GWindow.h │ │ ├── Gears/ │ │ │ ├── GearAnimation.h │ │ │ ├── GearBase.h │ │ │ ├── GearColor.h │ │ │ ├── GearDisplay.h │ │ │ ├── GearDisplay2.h │ │ │ ├── GearFontSize.h │ │ │ ├── GearIcon.h │ │ │ ├── GearLook.h │ │ │ ├── GearSize.h │ │ │ ├── GearText.h │ │ │ └── GearXY.h │ │ ├── PackageItem.h │ │ ├── PopupMenu.h │ │ ├── RelationItem.h │ │ ├── Relations.h │ │ ├── ScrollPane.h │ │ ├── Transition.h │ │ ├── TranslationHelper.h │ │ ├── UIConfig.h │ │ ├── UIObjectFactory.h │ │ └── UIPackage.h │ ├── UIPackageAsset.h │ ├── Utils/ │ │ ├── ByteBuffer.h │ │ ├── HTMLElement.h │ │ ├── HTMLParser.h │ │ ├── NVariant.h │ │ ├── UBBParser.h │ │ ├── XMLAttributes.h │ │ └── XMLIterator.h │ └── Widgets/ │ ├── BitmapFont.h │ ├── BitmapFontRun.h │ ├── HitTest.h │ ├── LoaderRun.h │ ├── Mesh/ │ │ ├── EllipseMesh.h │ │ ├── FillMesh.h │ │ ├── MeshFactory.h │ │ ├── PolygonMesh.h │ │ ├── RectMesh.h │ │ ├── RegularPolygonMesh.h │ │ ├── RoundedRectMesh.h │ │ └── VertexHelper.h │ ├── MeshFactory.h │ ├── NGraphics.h │ ├── NTextFormat.h │ ├── NTexture.h │ ├── SContainer.h │ ├── SDisplayObject.h │ ├── SFImage.h │ ├── SMovieClip.h │ ├── SShape.h │ ├── STextField.h │ └── STextInput.h └── FairyGUIEditor/ ├── FairyGUIEditor.Build.cs ├── Private/ │ ├── FairyGUIEditor.cpp │ └── FairyGUIFactory.cpp └── Public/ ├── FairyGUIEditor.h └── FairyGUIFactory.h ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Visual Studio 2015 user specific files .vs/ # Compiled Object files *.slo *.lo *.o *.obj # Precompiled Headers *.gch *.pch # Compiled Dynamic libraries *.so *.dylib *.dll # Fortran module files *.mod # Compiled Static libraries *.lai *.la *.a *.lib # Executables *.exe *.out *.app *.ipa # These project files can be generated by the engine *.xcodeproj *.xcworkspace *.sln *.suo *.opensdf *.sdf *.VC.db *.VC.opendb # Precompiled Assets SourceArt/**/*.png SourceArt/**/*.tga # Binary Files Binaries/* Plugins/*/Binaries/* # Builds Build/* # Whitelist PakBlacklist-.txt files !Build/*/ Build/*/** !Build/*/PakBlacklist*.txt # Don't ignore icon files in Build !Build/**/*.ico # Built data for maps *_BuiltData.uasset # Configuration files generated by the Editor Saved/* # Compiled source files for the engine to use Intermediate/* Plugins/*/Intermediate/* # Cache files for the editor to use DerivedDataCache/* ================================================ FILE: FairyGUI.uplugin ================================================ { "FileVersion": 3, "Version": 1, "VersionName": "1.0", "FriendlyName": "FairyGUI", "Description": "FairyGUI is a cross-engine UI Solution", "Category": "UI", "CreatedBy": "fairygui.com", "CreatedByURL": "https://fairygui.com", "DocsURL": "", "MarketplaceURL": "", "SupportURL": "", "CanContainContent": true, "IsBetaVersion": false, "IsExperimentalVersion": false, "Installed": false, "Modules": [ { "Name": "FairyGUI", "Type": "Runtime", "LoadingPhase": "Default" }, { "Name": "FairyGUIEditor", "Type": "Editor", "LoadingPhase": "Default" } ] } ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2021 FairyGUI Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # FairyGUI-unreal A flexible UI framework for Unreal Engine Suggest to start from [Examples](https://github.com/fairygui/FairyGUI-unreal-example) ================================================ FILE: Source/FairyGUI/FairyGUI.Build.cs ================================================ // Copyright 1998-2019 Epic Games, Inc. All Rights Reserved. using UnrealBuildTool; public class FairyGUI : ModuleRules { public FairyGUI(ReadOnlyTargetRules Target) : base(Target) { PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; PublicIncludePaths.AddRange( new string[] { // ... add public include paths required here ... } ); PrivateIncludePaths.AddRange( new string[] { // ... add other private include paths required here ... } ); PublicDependencyModuleNames.AddRange( new string[] { "Core", // ... add other public dependencies that you statically link with here ... } ); PrivateDependencyModuleNames.AddRange( new string[] { "CoreUObject", "Engine", "InputCore", "Slate", "SlateCore", // ... add private dependencies that you statically link with here ... } ); if (Target.bBuildEditor == true) { PrivateDependencyModuleNames.Add("UnrealEd"); } DynamicallyLoadedModuleNames.AddRange( new string[] { // ... add any modules that your module loads dynamically here ... } ); } } ================================================ FILE: Source/FairyGUI/Private/Event/EventContext.cpp ================================================ #include "Event/EventContext.h" ================================================ FILE: Source/FairyGUI/Private/Event/EventTypes.cpp ================================================ #include "Event/EventTypes.h" const FName FUIEvents::Click("Click"); const FName FUIEvents::TouchBegin("TouchBegin"); const FName FUIEvents::TouchMove("TouchMove"); const FName FUIEvents::TouchEnd("TouchEnd"); const FName FUIEvents::RollOver("RollOver"); const FName FUIEvents::RollOut("RollOut"); const FName FUIEvents::MouseWheel("MouseWheel"); const FName FUIEvents::DragStart("DragStart"); const FName FUIEvents::DragMove("DragMove"); const FName FUIEvents::DragEnd("DragEnd"); const FName FUIEvents::Drop("Drop"); const FName FUIEvents::AddedToStage("AddedToStage"); const FName FUIEvents::RemovedFromStage("RemovedFromStage"); const FName FUIEvents::Changed("Changed"); const FName FUIEvents::ClickItem("ClickItem"); const FName FUIEvents::ClickLink("ClickLink"); const FName FUIEvents::GearStop("GearStop"); const FName FUIEvents::Scroll("Scroll"); const FName FUIEvents::ScrollEnd("ScrollEnd"); const FName FUIEvents::PullDownRelease("PullDownRelease"); const FName FUIEvents::PullUpRelease("PullUpRelease"); const FName FUIEvents::Submit("Submit"); ================================================ FILE: Source/FairyGUI/Private/FairyApplication.cpp ================================================ #include "FairyApplication.h" #include "Framework/Application/SlateApplication.h" #include "Slate/SGameLayerManager.h" #include "UIPackageAsset.h" #include "UI/GRoot.h" #include "UI/UIPackage.h" #include "UI/UIObjectFactory.h" #include "UI/PackageItem.h" #include "UI/GWindow.h" #include "UI/PopupMenu.h" #include "UI/DragDropManager.h" #include "Tween/TweenManager.h" #include "Widgets/NTexture.h" #include "Utils/ByteBuffer.h" TMap UFairyApplication::Instances; struct FMyScopedSwitchWorldHack { FMyScopedSwitchWorldHack(UWorld* World) { PrevWorld = GWorld; GWorld = World; } ~FMyScopedSwitchWorldHack() { GWorld = PrevWorld; } UWorld* PrevWorld; }; UFairyApplication::FTouchInfo::FTouchInfo() : UserIndex(0), PointerIndex(0), bDown(false), DownPosition(0, 0), bClickCancelled(false), ClickCount(0) { } UFairyApplication::FInputProcessor::FInputProcessor(UFairyApplication* InApplication) { Application = InApplication; } void UFairyApplication::FInputProcessor::Tick(const float DeltaTime, FSlateApplication& SlateApp, TSharedRef Cursor) { } bool UFairyApplication::FInputProcessor::HandleMouseButtonDownEvent(FSlateApplication& SlateApp, const FPointerEvent& MouseEvent) { Application->PreviewDownEvent(MouseEvent); return false; } bool UFairyApplication::FInputProcessor::HandleMouseButtonUpEvent(FSlateApplication& SlateApp, const FPointerEvent& MouseEvent) { Application->PreviewUpEvent(MouseEvent); return false; } bool UFairyApplication::FInputProcessor::HandleMouseMoveEvent(FSlateApplication& SlateApp, const FPointerEvent& MouseEvent) { Application->PreviewMoveEvent(MouseEvent); return false; } UFairyApplication* UFairyApplication::Get(UObject* WorldContextObject) { UWorld* World = WorldContextObject->GetWorld(); verifyf(World != nullptr, TEXT("Null World?")); verifyf(World->IsGameWorld(), TEXT("Not a Game World?")); UFairyApplication* Instance = Instances.FindRef(World->GetGameInstance()->GetUniqueID()); if (Instance == nullptr) { Instance = NewObject(); Instances.Add(World->GetGameInstance()->GetUniqueID(), Instance); Instance->GameInstance = World->GetGameInstance(); Instance->AddToRoot(); Instance->OnCreate(); } return Instance; } void UFairyApplication::Destroy() { FUIObjectFactory::PackageItemExtensions.Reset(); FUIObjectFactory::LoaderExtension = nullptr; UNTexture::DestroyWhiteTexture(); UUIPackageStatic::Destroy(); FUIConfig::Config = FUIConfig(); //Reset Configuration to default values for (auto& it : Instances) { it.Value->RemoveFromRoot(); it.Value->OnDestroy(); } Instances.Reset(); } UFairyApplication::UFairyApplication() : bSoundEnabled(true), SoundVolumeScale(1) { LastTouch = new FTouchInfo(); Touches.Add(LastTouch); } void UFairyApplication::OnCreate() { ViewportClient = GameInstance->GetWorld()->GetGameViewport(); if (ViewportClient == nullptr) return; ViewportWidget = ViewportClient->GetGameViewportWidget(); DragDropManager = NewObject(this); DragDropManager->CreateAgent(); PostTickDelegateHandle = FSlateApplication::Get().OnPostTick().AddUObject(this, &UFairyApplication::OnSlatePostTick); InputProcessor = MakeShareable(new FInputProcessor(this)); FSlateApplication::Get().RegisterInputPreProcessor(InputProcessor); } void UFairyApplication::OnDestroy() { FTweenManager::Singleton.Reset(); if (InputProcessor.IsValid()) FSlateApplication::Get().UnregisterInputPreProcessor(InputProcessor); if (PostTickDelegateHandle.IsValid()) FSlateApplication::Get().OnPostTick().Remove(PostTickDelegateHandle); } UGRoot* UFairyApplication::GetUIRoot() const { if (UIRoot == nullptr) { UFairyApplication* This = const_cast(this); This->UIRoot = NewObject(This); This->UIRoot->AddToViewport(); } return UIRoot; } void UFairyApplication::CallAfterSlateTick(FSimpleDelegate Callback) { PostTickMulticastDelegate.Add(Callback); } void UFairyApplication::OnSlatePostTick(float DeltaTime) { if (PostTickMulticastDelegate.IsBound()) { FSimpleMulticastDelegate Clone = PostTickMulticastDelegate; PostTickMulticastDelegate.Clear(); Clone.Broadcast(); } if (bNeedCheckPopups) { bNeedCheckPopups = false; if (UIRoot != nullptr) UIRoot->CheckPopups(nullptr); } } FVector2D UFairyApplication::GetTouchPosition(int32 InUserIndex, int32 InPointerIndex) { FTouchInfo* TouchInfo = GetTouchInfo(InUserIndex, InPointerIndex); if (TouchInfo != nullptr) return TouchInfo->Event.GetScreenSpacePosition(); else return FVector2D::ZeroVector; } int32 UFairyApplication::GetTouchCount() const { int32 Count = 0; for (auto& it : Touches) { if (it.bDown) Count++; } return Count; } UGObject* UFairyApplication::GetObjectUnderPoint(const FVector2D& ScreenspacePosition) { TArray> Windows; Windows.Add(ViewportClient->GetWindow().ToSharedRef()); FWidgetPath WidgetPath = FSlateApplication::Get().LocateWindowUnderMouse(ScreenspacePosition, Windows, false); if (WidgetPath.IsValid()) return SDisplayObject::GetWidgetGObject(WidgetPath.GetLastWidget()); else return nullptr; } void UFairyApplication::CancelClick(int32 InUserIndex, int32 InPointerIndex) { FTouchInfo* TouchInfo = GetTouchInfo(InUserIndex, InPointerIndex); if (TouchInfo != nullptr) TouchInfo->bClickCancelled = true; } void UFairyApplication::PlaySound(const FString& URL, float VolumnScale) { if (!bSoundEnabled) return; TSharedPtr SoundItem = UUIPackage::GetItemByURL(URL); if (SoundItem.IsValid()) { SoundItem->Load(); FSlateApplication::Get().PlaySound(*SoundItem->Sound); } } void UFairyApplication::SetSoundEnabled(bool bEnabled) { bSoundEnabled = bEnabled; } void UFairyApplication::SetSoundVolumeScale(float VolumnScale) { SoundVolumeScale = VolumnScale; } bool UFairyApplication::DispatchEvent(const FName& EventType, const TSharedRef& Initiator, const FNVariant& Data) { UGObject* Obj = SDisplayObject::GetWidgetGObject(Initiator); if (Obj == nullptr) return false; UEventContext* Context = BorrowEventContext(); Context->Type = EventType; Context->Initiator = Obj; Context->Sender = Obj; Context->Data = Data; Context->Sender->InvokeEventDelegate(Context); ReturnEventContext(Context); return Context->bDefaultPrevented; } void UFairyApplication::BubbleEvent(const FName& EventType, const TSharedRef& Initiator, const FNVariant& Data) { TArray CallChain; SDisplayObject::GetWidgetPathToRoot(Initiator, CallChain); if (CallChain.Num() == 0) return; InternalBubbleEvent(EventType, CallChain, Data); } void UFairyApplication::InternalBubbleEvent(const FName& EventType, const TArray& CallChain, const FNVariant& Data) { UEventContext* Context = BorrowEventContext(); Context->Type = EventType; Context->Initiator = CallChain[0]; Context->Data = Data; for (auto& it : CallChain) { Context->Sender = it; it->InvokeEventDelegate(Context); if (Context->bIsMouseCaptor) { Context->bIsMouseCaptor = false; AddMouseCaptor(Context->GetUserIndex(), (int32)Context->GetPointerIndex(), it); } if (Context->IsPropagationStopped()) break; } ReturnEventContext(Context); } void UFairyApplication::BroadcastEvent(const FName& EventType, const TSharedRef& Initiator, const FNVariant& Data) { TArray CallChain; SDisplayObject::GetWidgetDescendants(Initiator, CallChain); if (CallChain.Num() == 0) return; UEventContext* Context = BorrowEventContext(); Context->Type = EventType; Context->Data = Data; for (auto& it : CallChain) { Context->Sender = it; Context->Initiator = it; it->InvokeEventDelegate(Context); } ReturnEventContext(Context); } UEventContext* UFairyApplication::BorrowEventContext() { UEventContext* Context; if (EventContextPool.Num() > 0) { Context = EventContextPool.Pop(); Context->bDefaultPrevented = false; Context->bStopped = false; Context->bIsMouseCaptor = false; } else Context = NewObject(this); Context->PointerEvent = &LastTouch->Event; Context->ClickCount = LastTouch->ClickCount; //Context->KeyEvent = &LastKeyEvent; return Context; } void UFairyApplication::ReturnEventContext(UEventContext* Context) { Context->Data.Reset(); EventContextPool.Add(Context); } void UFairyApplication::AddMouseCaptor(int32 InUserIndex, int32 InPointerIndex, UGObject* InTarget) { FTouchInfo* TouchInfo = GetTouchInfo(InUserIndex, InPointerIndex); if (TouchInfo != nullptr && !TouchInfo->MouseCaptors.Contains(InTarget)) TouchInfo->MouseCaptors.Add(InTarget); } void UFairyApplication::RemoveMouseCaptor(int32 InUserIndex, int32 InPointerIndex, UGObject* InTarget) { FTouchInfo* TouchInfo = GetTouchInfo(InUserIndex, InPointerIndex); if (TouchInfo != nullptr) TouchInfo->MouseCaptors.Remove(InTarget); } bool UFairyApplication::HasMouseCaptor(int32 InUserIndex, int32 InPointerIndex) { FTouchInfo* TouchInfo = GetTouchInfo(InUserIndex, InPointerIndex); return TouchInfo != nullptr && TouchInfo->MouseCaptors.Num() > 0; } UFairyApplication::FTouchInfo* UFairyApplication::GetTouchInfo(const FPointerEvent& MouseEvent) { FTouchInfo* TouchInfo = nullptr; for (auto& it : Touches) { if (it.UserIndex == MouseEvent.GetUserIndex() && it.PointerIndex == (int32)MouseEvent.GetPointerIndex()) { TouchInfo = ⁢ break; } } if (TouchInfo == nullptr) { TouchInfo = new FTouchInfo(); Touches.Add(TouchInfo); TouchInfo->UserIndex = MouseEvent.GetUserIndex(); TouchInfo->PointerIndex = (int32)MouseEvent.GetPointerIndex(); } LastTouch = TouchInfo; return TouchInfo; } UFairyApplication::FTouchInfo* UFairyApplication::GetTouchInfo(int32 InUserIndex, int32 InPointerIndex) { if (InUserIndex == -1 && InPointerIndex == -1) return LastTouch; for (auto& it : Touches) { if (it.UserIndex == InUserIndex && it.PointerIndex == InPointerIndex) { return ⁢ } } return nullptr; } void UFairyApplication::PreviewDownEvent(const FPointerEvent& MouseEvent) { FTouchInfo* TouchInfo = GetTouchInfo(MouseEvent); TouchInfo->Event = MouseEvent; TouchInfo->bDown = true; TouchInfo->DownPosition = MouseEvent.GetScreenSpacePosition(); TouchInfo->bClickCancelled = false; TouchInfo->ClickCount = 1; TouchInfo->MouseCaptors.Reset(); TouchInfo->bToClearCaptors = false; TouchInfo->DownPath.Reset(); bNeedCheckPopups = true; } void UFairyApplication::PreviewUpEvent(const FPointerEvent& MouseEvent) { FTouchInfo* TouchInfo = GetTouchInfo(MouseEvent); TouchInfo->Event = MouseEvent; TouchInfo->bDown = false; TouchInfo->bToClearCaptors = true; if (TouchInfo->MouseCaptors.Num() > 0) { FMyScopedSwitchWorldHack SwitchWorld(GameInstance->GetWorld()); int32 cnt = TouchInfo->MouseCaptors.Num(); for (int32 i = 0; i < cnt; i++) { auto& Captor = TouchInfo->MouseCaptors[i]; if (Captor.IsValid() && Captor->OnStage()) { DispatchEvent(FUIEvents::TouchEnd, Captor->GetDisplayObject()); } } } } void UFairyApplication::PreviewMoveEvent(const FPointerEvent& MouseEvent) { FTouchInfo* TouchInfo = GetTouchInfo(MouseEvent); TouchInfo->Event = MouseEvent; if ((TouchInfo->DownPosition - MouseEvent.GetScreenSpacePosition()).GetAbsMax() > 50) TouchInfo->bClickCancelled = true; if (!TouchInfo->bToClearCaptors && TouchInfo->MouseCaptors.Num() > 0) { FMyScopedSwitchWorldHack SwitchWorld(GameInstance->GetWorld()); int32 cnt = TouchInfo->MouseCaptors.Num(); for (int32 i = 0; i < cnt; i++) { auto& Captor = TouchInfo->MouseCaptors[i]; if (Captor.IsValid() && Captor->OnStage()) { DispatchEvent(FUIEvents::TouchMove, Captor->GetDisplayObject()); } } } } FReply UFairyApplication::OnWidgetMouseButtonDown(const TSharedRef& Widget, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { FMyScopedSwitchWorldHack SwitchWorld(GameInstance->GetWorld()); FTouchInfo* TouchInfo = GetTouchInfo(MouseEvent); UGObject* InitialGObject = nullptr; TSharedPtr Ptr = Widget; while (Ptr.IsValid() && Ptr != ViewportWidget) { TouchInfo->DownPath.Add(Ptr); if (InitialGObject == nullptr && Ptr->GetTag() == SDisplayObject::SDisplayObjectTag) { InitialGObject = StaticCastSharedPtr(Ptr)->GObject.Get(); } Ptr = Ptr->GetParentWidget(); } bNeedCheckPopups = false; if (UIRoot != nullptr) UIRoot->CheckPopups(&Widget.Get()); BubbleEvent(FUIEvents::TouchBegin, Widget); return FReply::Handled(); } FReply UFairyApplication::OnWidgetMouseButtonUp(const TSharedRef& Widget, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { FMyScopedSwitchWorldHack SwitchWorld(GameInstance->GetWorld()); FTouchInfo* TouchInfo = GetTouchInfo(MouseEvent); if (TouchInfo == nullptr) return FReply::Handled().ReleaseMouseCapture(); TArray CallChain; SDisplayObject::GetWidgetPathToRoot(Widget, CallChain); if (CallChain.Num() > 0) { for (auto& it : TouchInfo->MouseCaptors) { if (it.IsValid()) CallChain.RemoveSingle(it.Get()); } if (CallChain.Num() > 0) InternalBubbleEvent(FUIEvents::TouchEnd, CallChain, FNVariant::Null); } TouchInfo->MouseCaptors.Reset(); if (!TouchInfo->bClickCancelled) { TSharedPtr Ptr = Widget; while (Ptr.IsValid() && Ptr != ViewportWidget) { if (TouchInfo->DownPath.Contains(Ptr)) { BubbleEvent(FUIEvents::Click, Ptr.ToSharedRef()); break; } Ptr = Ptr->GetParentWidget(); } } TouchInfo->DownPath.Reset(); return FReply::Handled().ReleaseMouseCapture(); } FReply UFairyApplication::OnWidgetMouseMove(const TSharedRef& Widget, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { return FReply::Handled(); } FReply UFairyApplication::OnWidgetMouseButtonDoubleClick(const TSharedRef& Widget, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { FTouchInfo* TouchInfo = GetTouchInfo(MouseEvent); TouchInfo->ClickCount = 2; return OnWidgetMouseButtonDown(Widget, MyGeometry, MouseEvent); } void UFairyApplication::OnWidgetMouseEnter(const TSharedRef& Widget, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { FMyScopedSwitchWorldHack SwitchWorld(GameInstance->GetWorld()); FTouchInfo* TouchInfo = GetTouchInfo(MouseEvent); DispatchEvent(FUIEvents::RollOver, Widget); } void UFairyApplication::OnWidgetMouseLeave(const TSharedRef& Widget, const FPointerEvent& MouseEvent) { FMyScopedSwitchWorldHack SwitchWorld(GameInstance->GetWorld()); FTouchInfo* TouchInfo = GetTouchInfo(MouseEvent); DispatchEvent(FUIEvents::RollOut, Widget); } FReply UFairyApplication::OnWidgetMouseWheel(const TSharedRef& Widget, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { FMyScopedSwitchWorldHack SwitchWorld(GameInstance->GetWorld()); FTouchInfo* TouchInfo = GetTouchInfo(MouseEvent); TouchInfo->Event = MouseEvent; BubbleEvent(FUIEvents::MouseWheel, Widget); return FReply::Handled(); } ================================================ FILE: Source/FairyGUI/Private/FairyBlueprintLibrary.cpp ================================================ #include "FairyBlueprintLibrary.h" #include "UI/UIConfig.h" #include "UI/UIObjectFactory.h" #include "Tween/GTween.h" const FUIConfig& UFairyBlueprintLibrary::GetUIConfig() { return FUIConfig::Config; } void UFairyBlueprintLibrary::SetUIConfig(const FUIConfig& InConfig) { FUIConfig::Config = InConfig; } bool UFairyBlueprintLibrary::GetVariantAsBool(UPARAM(ref) FNVariant& InVariant) { return InVariant.AsBool(); } int32 UFairyBlueprintLibrary::GetVariantAsInt(UPARAM(ref) FNVariant& InVariant) { return InVariant.AsInt(); } float UFairyBlueprintLibrary::GetVariantAsFloat(UPARAM(ref) FNVariant& InVariant) { return InVariant.AsFloat(); } FString UFairyBlueprintLibrary::GetVariantAsString(UPARAM(ref) FNVariant& InVariant) { return InVariant.AsString(); } FColor UFairyBlueprintLibrary::GetVariantAsColor(UPARAM(ref) FNVariant& InVariant) { return InVariant.AsColor(); } UObject* UFairyBlueprintLibrary::GetVariantAsUObject(UPARAM(ref) FNVariant& InVariant, TSubclassOf ClassType) { return InVariant.AsUObject(); } FNVariant& UFairyBlueprintLibrary::SetVariantBool(UPARAM(ref) FNVariant& InVariant, bool bInValue) { InVariant = bInValue; return InVariant; } FNVariant& UFairyBlueprintLibrary::SetVariantInt(UPARAM(ref) FNVariant& InVariant, int32 InValue) { InVariant = InValue; return InVariant; } FNVariant& UFairyBlueprintLibrary::SetVariantFloat(UPARAM(ref) FNVariant& InVariant, float InValue) { InVariant = InValue; return InVariant; } FNVariant& UFairyBlueprintLibrary::SetVariantString(UPARAM(ref) FNVariant& InVariant, const FString& InValue) { InVariant = InValue; return InVariant; } FNVariant& UFairyBlueprintLibrary::SetVariantColor(UPARAM(ref) FNVariant& InVariant, const FColor& InValue) { InVariant = InValue; return InVariant; } FNVariant& UFairyBlueprintLibrary::SetVariantUObject(UPARAM(ref) FNVariant& InVariant, UObject* InValue) { InVariant = (void*)InValue; return InVariant; } FTweenerHandle UFairyBlueprintLibrary::TweenFloat(float StartValue, float EndValue, EEaseType EaseType, float Duration, int32 Repeat, const FTweenUpdateDynDelegate& OnUpdate, const FSimpleDynDelegate& OnComplete) { const UObject* Target = nullptr; if (OnUpdate.IsBound()) Target = OnUpdate.GetUObject(); else Target = OnComplete.GetUObject(); if (Target == nullptr) return FTweenerHandle(); FGTweener* Tweener = FGTween::To(StartValue, EndValue, Duration) ->SetEase(EaseType) ->SetRepeat(Repeat) ->SetTarget(const_cast(Target)); if (OnUpdate.IsBound()) { Tweener->OnUpdate(FTweenDelegate::CreateLambda([OnUpdate](FGTweener* Tweener) { OnUpdate.ExecuteIfBound(Tweener->Value, Tweener->DeltaValue); })); } if (OnComplete.IsBound()) { Tweener->OnComplete(FSimpleDelegate::CreateLambda([OnComplete]() { OnComplete.ExecuteIfBound(); })); } return Tweener->GetHandle(); } FTweenerHandle UFairyBlueprintLibrary::TweenVector2(const FVector2D& StartValue, const FVector2D& EndValue, EEaseType EaseType, float Duration, int32 Repeat, const FTweenUpdateDynDelegate& OnUpdate, const FSimpleDynDelegate& OnComplete) { const UObject* Target = nullptr; if (OnUpdate.IsBound()) Target = OnUpdate.GetUObject(); else Target = OnComplete.GetUObject(); if (Target == nullptr) return FTweenerHandle(); FGTweener* Tweener = FGTween::To(StartValue, EndValue, Duration) ->SetEase(EaseType) ->SetRepeat(Repeat) ->SetTarget(const_cast(Target)); if (OnUpdate.IsBound()) { Tweener->OnUpdate(FTweenDelegate::CreateLambda([OnUpdate](FGTweener* Tweener) { OnUpdate.ExecuteIfBound(Tweener->Value, Tweener->DeltaValue); })); } if (OnComplete.IsBound()) { Tweener->OnComplete(FSimpleDelegate::CreateLambda([OnComplete]() { OnComplete.ExecuteIfBound(); })); } return Tweener->GetHandle(); } void UFairyBlueprintLibrary::KillTween(UPARAM(ref) FTweenerHandle& Handle, bool bSetComplete) { FGTween::Kill(Handle, bSetComplete); } void UFairyBlueprintLibrary::SetPackageItemExtension(const FString& URL, TSubclassOf ClassType) { FUIObjectFactory::SetExtension(URL, ClassType); } ================================================ FILE: Source/FairyGUI/Private/FairyCommons.cpp ================================================ #include "FairyCommons.h" #include "Framework/Application/SlateApplication.h" DEFINE_LOG_CATEGORY(LogFairyGUI); const FString G_EMPTY_STRING(""); ================================================ FILE: Source/FairyGUI/Private/FairyGUIModule.cpp ================================================ // Copyright 1998-2019 Epic Games, Inc. All Rights Reserved. #include "FairyGUIModule.h" #if WITH_EDITOR #include "Editor.h" #include "FairyApplication.h" #endif #include "UI/UIConfig.h" #define LOCTEXT_NAMESPACE "FFairyGUIModule" void FFairyGUIModule::StartupModule() { // This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module #if WITH_EDITOR EndPieDelegateHandle = FEditorDelegates::EndPIE.AddLambda([](bool boolSent) { UE_LOG(LogFairyGUI, Log, TEXT("Application destroy")); UFairyApplication::Destroy(); }); #endif } void FFairyGUIModule::ShutdownModule() { // This function may be called during shutdown to clean up your module. For modules that support dynamic reloading, // we call this function before unloading the module. #if WITH_EDITOR FEditorDelegates::EndPIE.Remove(EndPieDelegateHandle); #endif } #undef LOCTEXT_NAMESPACE IMPLEMENT_MODULE(FFairyGUIModule, FairyGUI) ================================================ FILE: Source/FairyGUI/Private/Tween/EaseManager.cpp ================================================ #include "Tween/EaseManager.h" static const float _PiOver2 = (PI * 0.5f); static const float _TwoPi = (PI * 2); class Bounce { public: static float EaseIn(float Time, float Duration); static float EaseOut(float Time, float Duration); static float EaseInOut(float Time, float Duration); }; float EaseManager::Evaluate(EEaseType EaseType, float Time, float Duration, float OvershootOrAmplitude, float Period) { switch (EaseType) { case EEaseType::Linear: return Time / Duration; case EEaseType::SineIn: return -FMath::Cos(Time / Duration * _PiOver2) + 1; case EEaseType::SineOut: return FMath::Sin(Time / Duration * _PiOver2); case EEaseType::SineInOut: return -0.5f * (FMath::Cos(PI * Time / Duration) - 1); case EEaseType::QuadIn: Time /= Duration; return Time * Time; case EEaseType::QuadOut: Time /= Duration; return -Time * (Time - 2); case EEaseType::QuadInOut: Time /= Duration * 0.5f; if (Time < 1) return 0.5f * Time * Time; --Time; return -0.5f * (Time * (Time - 2) - 1); case EEaseType::CubicIn: Time /= Duration; return Time * Time * Time; case EEaseType::CubicOut: Time = Time / Duration - 1; return Time * Time * Time + 1; case EEaseType::CubicInOut: Time /= Duration * 0.5f; if (Time < 1) return 0.5f * Time * Time * Time; Time -= 2; return 0.5f * (Time * Time * Time + 2); case EEaseType::QuartIn: Time /= Duration; return Time * Time * Time * Time; case EEaseType::QuartOut: Time = Time / Duration - 1; return -(Time * Time * Time * Time - 1); case EEaseType::QuartInOut: Time /= Duration * 0.5f; if (Time < 1) return 0.5f * Time * Time * Time * Time; Time -= 2; return -0.5f * (Time * Time * Time * Time - 2); case EEaseType::QuintIn: Time /= Duration; return Time * Time * Time * Time * Time; case EEaseType::QuintOut: Time = Time / Duration - 1; return (Time * Time * Time * Time * Time + 1); case EEaseType::QuintInOut: Time /= Duration * 0.5f; if (Time < 1) return 0.5f * Time * Time * Time * Time * Time; Time -= 2; return 0.5f * (Time * Time * Time * Time * Time + 2); case EEaseType::ExpoIn: return (Time == 0) ? 0 : FMath::Pow(2, 10 * (Time / Duration - 1)); case EEaseType::ExpoOut: if (Time == Duration) return 1; return (-FMath::Pow(2, -10 * Time / Duration) + 1); case EEaseType::ExpoInOut: if (Time == 0) return 0; if (Time == Duration) return 1; if ((Time /= Duration * 0.5f) < 1) return 0.5f * FMath::Pow(2, 10 * (Time - 1)); return 0.5f * (-FMath::Pow(2, -10 * --Time) + 2); case EEaseType::CircIn: Time /= Duration; return -(FMath::Sqrt(1 - Time * Time) - 1); case EEaseType::CircOut: Time = Time / Duration - 1; return FMath::Sqrt(1 - Time * Time); case EEaseType::CircInOut: Time /= Duration * 0.5f; if (Time < 1) return -0.5f * (FMath::Sqrt(1 - Time * Time) - 1); Time -= 2; return 0.5f * (FMath::Sqrt(1 - Time * Time) + 1); case EEaseType::ElasticIn: float s0; if (Time == 0) return 0; if ((Time /= Duration) == 1) return 1; if (Period == 0) Period = Duration * 0.3f; if (OvershootOrAmplitude < 1) { OvershootOrAmplitude = 1; s0 = Period / 4; } else s0 = Period / _TwoPi * FMath::Asin(1 / OvershootOrAmplitude); Time -= 1; return -(OvershootOrAmplitude * FMath::Pow(2, 10 * Time) * FMath::Sin((Time * Duration - s0) * _TwoPi / Period)); case EEaseType::ElasticOut: float s1; if (Time == 0) return 0; if ((Time /= Duration) == 1) return 1; if (Period == 0) Period = Duration * 0.3f; if (OvershootOrAmplitude < 1) { OvershootOrAmplitude = 1; s1 = Period / 4; } else s1 = Period / _TwoPi * FMath::Asin(1 / OvershootOrAmplitude); return (OvershootOrAmplitude * FMath::Pow(2, -10 * Time) * FMath::Sin((Time * Duration - s1) * _TwoPi / Period) + 1); case EEaseType::ElasticInOut: float s; if (Time == 0) return 0; if ((Time /= Duration * 0.5f) == 2) return 1; if (Period == 0) Period = Duration * (0.3f * 1.5f); if (OvershootOrAmplitude < 1) { OvershootOrAmplitude = 1; s = Period / 4; } else s = Period / _TwoPi * FMath::Asin(1 / OvershootOrAmplitude); if (Time < 1) { Time -= 1; return -0.5f * (OvershootOrAmplitude * FMath::Pow(2, 10 * Time) * FMath::Sin((Time * Duration - s) * _TwoPi / Period)); } Time -= 1; return OvershootOrAmplitude * FMath::Pow(2, -10 * Time) * FMath::Sin((Time * Duration - s) * _TwoPi / Period) * 0.5f + 1; case EEaseType::BackIn: Time /= Duration; return Time * Time * ((OvershootOrAmplitude + 1) * Time - OvershootOrAmplitude); case EEaseType::BackOut: Time = Time / Duration - 1; return (Time * Time * ((OvershootOrAmplitude + 1) * Time + OvershootOrAmplitude) + 1); case EEaseType::BackInOut: Time /= Duration * 0.5f; OvershootOrAmplitude *= (1.525f); if (Time < 1) return 0.5f * (Time * Time * ((OvershootOrAmplitude + 1) * Time - OvershootOrAmplitude)); Time -= 2; return 0.5f * (Time * Time * ((OvershootOrAmplitude + 1) * Time + OvershootOrAmplitude) + 2); case EEaseType::BounceIn: return Bounce::EaseIn(Time, Duration); case EEaseType::BounceOut: return Bounce::EaseOut(Time, Duration); case EEaseType::BounceInOut: return Bounce::EaseInOut(Time, Duration); default: Time /= Duration; return -Time * (Time - 2); } } float Bounce::EaseIn(float Time, float Duration) { return 1 - EaseOut(Duration - Time, Duration); } float Bounce::EaseOut(float Time, float Duration) { Time /= Duration; if (Time < (1 / 2.75f)) { return (7.5625f * Time * Time); } if (Time < (2 / 2.75f)) { Time -= (1.5f / 2.75f); return (7.5625f * Time * Time + 0.75f); } if (Time < (2.5f / 2.75f)) { Time -= (2.25f / 2.75f); return (7.5625f * Time * Time + 0.9375f); } Time -= (2.625f / 2.75f); return (7.5625f * Time * Time + 0.984375f); } float Bounce::EaseInOut(float Time, float Duration) { if (Time < Duration * 0.5f) { return EaseIn(Time * 2, Duration) * 0.5f; } return EaseOut(Time * 2 - Duration, Duration) * 0.5f + 0.5f; } ================================================ FILE: Source/FairyGUI/Private/Tween/GPath.cpp ================================================ #include "Tween/GPath.h" FGPathPoint::FGPathPoint(const FVector& InPos) { Pos = InPos; Control1 = FVector::ZeroVector; Control2 = FVector::ZeroVector; CurveType = ECurveType::CRSpline; } FGPathPoint::FGPathPoint(const FVector& InPos, const FVector& InControl) { Pos = InPos; Control1 = InControl; Control2 = FVector::ZeroVector; CurveType = ECurveType::Bezier; } FGPathPoint::FGPathPoint(const FVector& InPos, const FVector& InControl1, const FVector& InControl2) { Pos = InPos; Control1 = InControl1; Control2 = InControl2; CurveType = ECurveType::CubicBezier; } FGPathPoint::FGPathPoint(const FVector& InPos, ECurveType InCurveType) { Pos = InPos; Control1 = FVector::ZeroVector; Control2 = FVector::ZeroVector; CurveType = InCurveType; } FGPath::FGPath() : FullLength(0) { } void FGPath::Create(const FGPathPoint* InPoints, int32 Count) { Segments.Reset(); Points.Reset(); FullLength = 0; if (Count == 0) return; TArray SplinePoints; const FGPathPoint* prev = InPoints; if (prev->CurveType == FGPathPoint::ECurveType::CRSpline) SplinePoints.Add(prev->Pos); for (int32 i = 1; i < Count; i++) { const FGPathPoint* current = InPoints + i; if (prev->CurveType != FGPathPoint::ECurveType::CRSpline) { FSegment seg; seg.Type = prev->CurveType; seg.PointStart = Points.Num(); if (prev->CurveType == FGPathPoint::ECurveType::Straight) { seg.PointCount = 2; Points.Add(prev->Pos); Points.Add(current->Pos); } else if (prev->CurveType == FGPathPoint::ECurveType::Bezier) { seg.PointCount = 3; Points.Add(prev->Pos); Points.Add(current->Pos); Points.Add(prev->Control1); } else if (prev->CurveType == FGPathPoint::ECurveType::CubicBezier) { seg.PointCount = 4; Points.Add(prev->Pos); Points.Add(current->Pos); Points.Add(prev->Control1); Points.Add(prev->Control2); } seg.Length = FVector::Dist(prev->Pos, current->Pos); FullLength += seg.Length; Segments.Add(MoveTemp(seg)); } if (current->CurveType != FGPathPoint::ECurveType::CRSpline) { if (SplinePoints.Num() > 0) { SplinePoints.Add(current->Pos); CreateSplineSegment(SplinePoints); } } else SplinePoints.Add(current->Pos); prev = current; } if (SplinePoints.Num() > 1) CreateSplineSegment(SplinePoints); } void FGPath::CreateSplineSegment(TArray& SplinePoints) { int32 cnt = SplinePoints.Num(); SplinePoints.Insert(SplinePoints[0], 0); SplinePoints.Add(SplinePoints[cnt]); SplinePoints.Add(SplinePoints[cnt]); cnt += 3; FSegment seg; seg.Type = FGPathPoint::ECurveType::CRSpline; seg.PointStart = Points.Num(); seg.PointCount = cnt; for (auto& it : SplinePoints) Points.Add(it); seg.Length = 0; for (int32 i = 1; i < cnt; i++) seg.Length += FVector::Dist(SplinePoints[i - 1], SplinePoints[i]); FullLength += seg.Length; Segments.Add(MoveTemp(seg)); SplinePoints.Reset(); } void FGPath::Clear() { Segments.Reset(); Points.Reset(); } FVector FGPath::GetPointAt(float Time) { Time = FMath::Clamp(Time, 0, 1); int32 cnt = Segments.Num(); if (cnt == 0) return FVector::ZeroVector; if (Time == 1) { const FSegment& seg = Segments[cnt - 1]; if (seg.Type == FGPathPoint::ECurveType::Straight) return FMath::Lerp(Points[seg.PointStart], Points[seg.PointStart + 1], Time); else if (seg.Type == FGPathPoint::ECurveType::Bezier || seg.Type == FGPathPoint::ECurveType::CubicBezier) return OnBezierCurve(seg.PointStart, seg.PointCount, Time); else return OnCRSplineCurve(seg.PointStart, seg.PointCount, Time); } float len = Time * FullLength; FVector pt; for (int32 i = 0; i < cnt; i++) { const FSegment& seg = Segments[i]; len -= seg.Length; if (len < 0) { Time = 1 + len / seg.Length; if (seg.Type == FGPathPoint::ECurveType::Straight) pt = FMath::Lerp(Points[seg.PointStart], Points[seg.PointStart + 1], Time); else if (seg.Type == FGPathPoint::ECurveType::Bezier || seg.Type == FGPathPoint::ECurveType::CubicBezier) pt = OnBezierCurve(seg.PointStart, seg.PointCount, Time); else pt = OnCRSplineCurve(seg.PointStart, seg.PointCount, Time); break; } } return pt; } float FGPath::GetSegmentLength(int32 SegmentIndex) { return Segments[SegmentIndex].Length; } void FGPath::GetPointsInSegment(int32 SegmentIndex, float t0, float t1, TArray& OutPoints, TArray* OutTimeArray, float PointDensity) { if (OutTimeArray != nullptr) OutTimeArray->Add(t0); const FSegment& seg = Segments[SegmentIndex]; if (seg.Type == FGPathPoint::ECurveType::Straight) { OutPoints.Add(FMath::Lerp(Points[seg.PointStart], Points[seg.PointStart + 1], t0)); OutPoints.Add(FMath::Lerp(Points[seg.PointStart], Points[seg.PointStart + 1], t1)); } else if (seg.Type == FGPathPoint::ECurveType::Bezier || seg.Type == FGPathPoint::ECurveType::CubicBezier) { OutPoints.Add(OnBezierCurve(seg.PointStart, seg.PointCount, t0)); int32 SmoothAmount = FMath::Min(FMath::FloorToInt(seg.Length * PointDensity), 50); for (int32 j = 0; j <= SmoothAmount; j++) { float t = (float)j / SmoothAmount; if (t > t0 && t < t1) { OutPoints.Add(OnBezierCurve(seg.PointStart, seg.PointCount, t)); if (OutTimeArray != nullptr) OutTimeArray->Add(t); } } OutPoints.Add(OnBezierCurve(seg.PointStart, seg.PointCount, t1)); } else { OutPoints.Add(OnCRSplineCurve(seg.PointStart, seg.PointCount, t0)); int32 SmoothAmount = FMath::Min(FMath::FloorToInt(seg.Length * PointDensity), 50); for (int32 j = 0; j <= SmoothAmount; j++) { float t = (float)j / SmoothAmount; if (t > t0 && t < t1) { OutPoints.Add(OnCRSplineCurve(seg.PointStart, seg.PointCount, t)); if (OutTimeArray != nullptr) OutTimeArray->Add(t); } } OutPoints.Add(OnCRSplineCurve(seg.PointStart, seg.PointCount, t1)); } if (OutTimeArray != nullptr) OutTimeArray->Add(t1); } void FGPath::GetAllPoints(TArray& OutPoints, float PointDensity) { int32 cnt = Segments.Num(); for (int32 i = 0; i < cnt; i++) GetPointsInSegment(i, 0, 1, OutPoints, nullptr, PointDensity); } static float repeat(float t, float length) { return t - FMath::FloorToFloat(t / length) * length; } FVector FGPath::OnCRSplineCurve(int32 PointStart, int32 PointCount, float Time) { 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 FVector result; FVector p0 = Points[adjustedIndex]; FVector p1 = Points[adjustedIndex + 1]; FVector p2 = Points[adjustedIndex + 2]; FVector p3 = Points[adjustedIndex + 3]; 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); float t0 = ((-adjustedT + 2.f) * adjustedT - 1.f) * adjustedT * 0.5f; float t1 = (((3.f * adjustedT - 5.f) * adjustedT) * adjustedT + 2.f) * 0.5f; float t2 = ((-3.f * adjustedT + 4.f) * adjustedT + 1.f) * adjustedT * 0.5f; float t3 = ((adjustedT - 1.f) * adjustedT * adjustedT) * 0.5f; result.X = p0.X * t0 + p1.X * t1 + p2.X * t2 + p3.X * t3; result.Y = p0.Y * t0 + p1.Y * t1 + p2.Y * t2 + p3.Y * t3; result.Z = p0.Z * t0 + p1.Z * t1 + p2.Z * t2 + p3.Z * t3; return result; } FVector FGPath::OnBezierCurve(int32 PointStart, int32 PointCount, float Time) { float t2 = 1.0f - Time; FVector p0 = Points[PointStart]; FVector p1 = Points[PointStart + 1]; FVector cp0 = Points[PointStart + 2]; if (PointCount == 4) { FVector cp1 = Points[PointStart + 3]; return t2 * t2 * t2 * p0 + 3.f * t2 * t2 * Time * cp0 + 3.f * t2 * Time * Time * cp1 + Time * Time * Time * p1; } else return t2 * t2 * p0 + 2.f * t2 * Time * cp0 + Time * Time * p1; } ================================================ FILE: Source/FairyGUI/Private/Tween/GTween.cpp ================================================ #include "Tween/GTween.h" #include "Tween/TweenManager.h" #include "UI/GProgressBar.h" FGTweener* FGTween::To(float StartValue, float EndValue, float Duration) { return FTweenManager::Singleton.CreateTween()->To(StartValue, EndValue, Duration); } FGTweener* FGTween::To(const FVector2D& StartValue, const FVector2D & EndValue, float Duration) { return FTweenManager::Singleton.CreateTween()->To(StartValue, EndValue, Duration); } FGTweener* FGTween::To(const FVector& StartValue, const FVector & EndValue, float Duration) { return FTweenManager::Singleton.CreateTween()->To(StartValue, EndValue, Duration); } FGTweener* FGTween::To(const FVector4& StartValue, const FVector4 & EndValue, float Duration) { return FTweenManager::Singleton.CreateTween()->To(StartValue, EndValue, Duration); } FGTweener* FGTween::To(const FColor& StartValue, const FColor & EndValue, float Duration) { return FTweenManager::Singleton.CreateTween()->To(StartValue, EndValue, Duration); } FGTweener* FGTween::ToDouble(double StartValue, double EndValue, float Duration) { return FTweenManager::Singleton.CreateTween()->To(StartValue, EndValue, Duration); } FGTweener* FGTween::DelayedCall(float Delay) { return FTweenManager::Singleton.CreateTween()->SetDelay(Delay); } FGTweener* FGTween::Shake(const FVector2D& StartValue, float Amplitude, float Duration) { return FTweenManager::Singleton.CreateTween()->Shake(StartValue, Amplitude, Duration); } bool FGTween::IsTweening(const FTweenerHandle& Handle) { return FTweenManager::Singleton.IsTweening(Handle); } bool FGTween::IsTweening(UObject* Target) { return FTweenManager::Singleton.IsTweening(Target); } void FGTween::Kill(FTweenerHandle& Handle, bool bSetComplete) { FTweenManager::Singleton.KillTween(Handle, bSetComplete); } void FGTween::Kill(UObject* Target, bool bSetComplete) { FTweenManager::Singleton.KillTweens(Target, bSetComplete); } FGTweener* FGTween::GetTween(const FTweenerHandle& Handle) { return FTweenManager::Singleton.GetTween(Handle); } FGTweener* FGTween::GetTween(UObject * Target) { return FTweenManager::Singleton.GetTween(Target); } void FGTweenAction::MoveX(FGTweener* Tweener) { UGObject * target = Cast(Tweener->GetTarget()); target->SetX(Tweener->Value.X); } void FGTweenAction::MoveY(FGTweener* Tweener) { UGObject * target = Cast(Tweener->GetTarget()); target->SetY(Tweener->Value.X); } void FGTweenAction::Move(FGTweener* Tweener) { UGObject * target = Cast(Tweener->GetTarget()); target->SetPosition(Tweener->Value.GetVec2()); } void FGTweenAction::SetWidth(FGTweener* Tweener) { UGObject * target = Cast(Tweener->GetTarget()); target->SetWidth(Tweener->Value.X); } void FGTweenAction::SetHeight(FGTweener* Tweener) { UGObject * target = Cast(Tweener->GetTarget()); target->SetHeight(Tweener->Value.X); } void FGTweenAction::SetSize(FGTweener* Tweener) { UGObject * target = Cast(Tweener->GetTarget()); target->SetSize(Tweener->Value.GetVec2()); } void FGTweenAction::ScaleX(FGTweener* Tweener) { UGObject * target = Cast(Tweener->GetTarget()); target->SetScaleX(Tweener->Value.X); } void FGTweenAction::ScaleY(FGTweener* Tweener) { UGObject * target = Cast(Tweener->GetTarget()); target->SetScaleY(Tweener->Value.X); } void FGTweenAction::ScaleXY(FGTweener* Tweener) { UGObject * target = Cast(Tweener->GetTarget()); target->SetScale(Tweener->Value.GetVec2()); } void FGTweenAction::Rotate(FGTweener* Tweener) { UGObject * target = Cast(Tweener->GetTarget()); target->SetRotation(Tweener->Value.X); } void FGTweenAction::SetAlpha(FGTweener* Tweener) { UGObject * target = Cast(Tweener->GetTarget()); target->SetAlpha(Tweener->Value.X); } void FGTweenAction::SetProgress(FGTweener* Tweener) { UGProgressBar * target = Cast(Tweener->GetTarget()); target->Update(Tweener->Value.X); } ================================================ FILE: Source/FairyGUI/Private/Tween/GTweener.cpp ================================================ #include "Tween/GTweener.h" #include "Tween/EaseManager.h" #include "Tween/GPath.h" #include "UI/GObject.h" FGTweener::FGTweener() { } FGTweener::~FGTweener() { } FGTweener* FGTweener::SetDelay(float InValue) { Delay = InValue; return this; } FGTweener* FGTweener::SetDuration(float InValue) { Duration = InValue; return this; } FGTweener* FGTweener::SetBreakpoint(float InValue) { Breakpoint = InValue; return this; } FGTweener* FGTweener::SetEase(EEaseType InValue) { EaseType = InValue; return this; } FGTweener* FGTweener::SetEasePeriod(float InValue) { EasePeriod = InValue; return this; } FGTweener* FGTweener::SetEaseOvershootOrAmplitude(float InValue) { EaseOvershootOrAmplitude = InValue; return this; } FGTweener* FGTweener::SetRepeat(int32 InRepeat, bool bInYoyo) { Repeat = InRepeat; bYoyo = bInYoyo; return this; } FGTweener* FGTweener::SetTimeScale(float InValue) { TimeScale = InValue; return this; } FGTweener* FGTweener::SetSnapping(bool bInValue) { bSnapping = bInValue; return this; } FGTweener* FGTweener::SetTarget(UObject* InTarget) { Target = InTarget; return this; } FGTweener* FGTweener::SetUserData(const FNVariant& InData) { UserData = InData; return this; } FGTweener* FGTweener::SetPath(TSharedPtr InPath) { Path = InPath; return this; } FGTweener* FGTweener::OnUpdate(FTweenDelegate Callback) { OnUpdateCallback = Callback; return this; } FGTweener* FGTweener::OnStart(FTweenDelegate Callback) { OnStartCallback = Callback; return this; } FGTweener* FGTweener::OnComplete(FTweenDelegate Callback) { OnCompleteCallback = Callback; return this; } FGTweener* FGTweener::OnUpdate(FSimpleDelegate Callback) { OnUpdateCallback.BindLambda([Callback](FGTweener*) { Callback.ExecuteIfBound(); }); return this; } FGTweener* FGTweener::OnStart(FSimpleDelegate Callback) { OnStartCallback.BindLambda([Callback](FGTweener*) { Callback.ExecuteIfBound(); }); return this; } FGTweener* FGTweener::OnComplete(FSimpleDelegate Callback) { OnCompleteCallback.BindLambda([Callback](FGTweener*) { Callback.ExecuteIfBound(); }); return this; } FGTweener* FGTweener::SetPaused(bool bInPaused) { bPaused = bInPaused; return this; } void FGTweener::Seek(float Time) { if (bKilled) return; ElapsedTime = Time; if (ElapsedTime < Delay) { if (bStarted) ElapsedTime = Delay; else return; } Update(); } void FGTweener::Kill(bool bSetComplete) { if (bKilled) return; if (bSetComplete) { if (Ended == 0) { if (Breakpoint >= 0) ElapsedTime = Delay + Breakpoint; else if (Repeat >= 0) ElapsedTime = Delay + Duration * (Repeat + 1); else ElapsedTime = Delay + Duration * 2; Update(); } OnCompleteCallback.ExecuteIfBound(this); } bKilled = true; } FGTweener* FGTweener::To(float InStart, float InEnd, float InDuration) { ValueSize = 1; StartValue.X = InStart; EndValue.X = InEnd; Value.X = InStart; Duration = InDuration; return this; } FGTweener* FGTweener::To(const FVector2D& InStart, const FVector2D& InEnd, float InDuration) { ValueSize = 2; StartValue.SetVec2(InStart); EndValue.SetVec2(InEnd); Value.SetVec2(InStart); Duration = InDuration; return this; } FGTweener* FGTweener::To(const FVector& InStart, const FVector& InEnd, float InDuration) { ValueSize = 3; StartValue.SetVec3(InStart); EndValue.SetVec3(InEnd); Value.SetVec3(InStart); Duration = InDuration; return this; } FGTweener* FGTweener::To(const FVector4& InStart, const FVector4& InEnd, float InDuration) { ValueSize = 4; StartValue.SetVec4(InStart); EndValue.SetVec4(InEnd); Value.SetVec4(InStart); Duration = InDuration; return this; } FGTweener* FGTweener::To(const FColor& InStart, const FColor& InEnd, float InDuration) { ValueSize = 4; StartValue.SetColor(InStart); EndValue.SetColor(InEnd); Value.SetColor(InStart); Duration = InDuration; return this; } FGTweener* FGTweener::To(double InStart, double InEnd, float InDuration) { ValueSize = 5; StartValue.D = InStart; EndValue.D = InEnd; Value.D = InStart; Duration = InDuration; return this; } FGTweener* FGTweener::Shake(const FVector2D& InStart, float InAmplitude, float InDuration) { ValueSize = 6; StartValue.SetVec2(InStart); StartValue.W = InAmplitude; Duration = InDuration; EaseType = EEaseType::Linear; return this; } void FGTweener::Init() { Delay = 0; Duration = 0; Breakpoint = -1; EaseType = EEaseType::QuadOut; TimeScale = 1; EasePeriod = 0; EaseOvershootOrAmplitude = 1.70158f; bSnapping = false; Repeat = 0; bYoyo = false; ValueSize = 0; bStarted = false; bPaused = false; bKilled = false; ElapsedTime = 0; NormalizedTime = 0; Ended = 0; StartValue.Reset(); EndValue.Reset(); Value.Reset(); DeltaValue.Reset(); } void FGTweener::Reset() { Target.Reset(); UserData.Reset(); Path.Reset(); OnStartCallback.Unbind(); OnUpdateCallback.Unbind(); OnCompleteCallback.Unbind(); } void FGTweener::Update(float DeltaTime) { if (Ended != 0) //Maybe completed by seek { OnCompleteCallback.ExecuteIfBound(this); bKilled = true; return; } if (TimeScale != 1) DeltaTime *= TimeScale; if (DeltaTime == 0) return; ElapsedTime += DeltaTime; Update(); if (Ended != 0) { if (!bKilled) { OnCompleteCallback.ExecuteIfBound(this); bKilled = true; } } } void FGTweener::Update() { Ended = 0; if (ValueSize == 0) //DelayedCall { if (ElapsedTime >= Delay + Duration) Ended = 1; return; } if (!bStarted) { if (ElapsedTime < Delay) return; bStarted = true; OnStartCallback.ExecuteIfBound(this); if (bKilled) return; } bool reversed = false; float tt = ElapsedTime - Delay; if (Breakpoint >= 0 && tt >= Breakpoint) { tt = Breakpoint; Ended = 2; } if (Repeat != 0) { int32 round = FMath::FloorToInt(tt / Duration); tt -= Duration * round; if (bYoyo) reversed = round % 2 == 1; if (Repeat > 0 && Repeat - round < 0) { if (bYoyo) reversed = Repeat % 2 == 1; tt = Duration; Ended = 1; } } else if (tt >= Duration) { tt = Duration; Ended = 1; } NormalizedTime = EaseManager::Evaluate(EaseType, reversed ? (Duration - tt) : tt, Duration, EaseOvershootOrAmplitude, EasePeriod); Value.Reset(); DeltaValue.Reset(); if (ValueSize == 5) { double d = StartValue.D + (EndValue.D - StartValue.D) * NormalizedTime; if (bSnapping) d = round(d); DeltaValue.D = d - Value.D; Value.D = d; Value.X = (float)d; } else if (ValueSize == 6) { if (Ended == 0) { float r = StartValue.W * (1 - NormalizedTime); float rx = (FMath::RandRange(0, 1) * 2 - 1) * r; float ry = (FMath::RandRange(0, 1) * 2 - 1) * r; rx = rx > 0 ? FMath::CeilToFloat(rx) : FMath::FloorToFloat(rx); ry = ry > 0 ? FMath::CeilToFloat(ry) : FMath::FloorToFloat(ry); DeltaValue.X = rx; DeltaValue.Y = ry; Value.X = StartValue.X + rx; Value.Y = StartValue.Y + ry; } else Value.SetVec3(StartValue.GetVec3()); } else if (Path.IsValid()) { FVector vec3 = Path->GetPointAt(NormalizedTime); if (bSnapping) { vec3.X = FMath::RoundToFloat(vec3.X); vec3.Y = FMath::RoundToFloat(vec3.Y); vec3.Z = FMath::RoundToFloat(vec3.Z); } DeltaValue.SetVec3(vec3 - Value.GetVec3()); Value.SetVec3(vec3); } else { for (int32 i = 0; i < ValueSize; i++) { float n1 = StartValue[i]; float n2 = EndValue[i]; float f = n1 + (n2 - n1) * NormalizedTime; if (bSnapping) f = FMath::RoundToFloat(f); DeltaValue[i] = f - Value[i]; Value[i] = f; } Value.D = Value.X; } OnUpdateCallback.ExecuteIfBound(this); } ================================================ FILE: Source/FairyGUI/Private/Tween/TweenManager.cpp ================================================ #include "Tween/TweenManager.h" #include "Tween/GTweener.h" FTweenManager FTweenManager::Singleton; FTweenManager::FTweenManager() { TotalActiveTweens = 0; ArrayLength = 30; ActiveTweens = new FGTweener*[ArrayLength]; } FTweenManager::~FTweenManager() { Reset(); delete []ActiveTweens; } void FTweenManager::Reset() { for (auto it : TweenerPool) delete it; TweenerPool.Reset(); int32 cnt = TotalActiveTweens; for (int32 i = 0; i < cnt; i++) { FGTweener* tweener = ActiveTweens[i]; if (tweener != nullptr) delete tweener; } TotalActiveTweens = 0; } FGTweener* FTweenManager::CreateTween() { FGTweener* tweener; int32 cnt = TweenerPool.Num(); if (cnt > 0) { tweener = TweenerPool.Pop(); tweener->Handle.IncreaseSerialNumber(); } else { TweenerInstanceCount++; if (!ensureMsgf(TweenerInstanceCount != FTweenerHandle::MaxIndex, TEXT("Tweener index number has wrapped around!"))) { TweenerInstanceCount = 0; } tweener = new FGTweener(); tweener->Handle.SetIndex(TweenerInstanceCount); } tweener->Init(); ActiveTweens[TotalActiveTweens++] = tweener; if (TotalActiveTweens == ArrayLength) { int32 newLen = ArrayLength + FMath::CeilToInt(ArrayLength * 0.5f); FGTweener** newArray = new FGTweener*[newLen]; FMemory::Memcpy(newArray, ActiveTweens, ArrayLength * sizeof(FGTweener*)); delete []ActiveTweens; ActiveTweens = newArray; ArrayLength = newLen; } return tweener; } bool FTweenManager::KillTween(FTweenerHandle & Handle, bool bCompleted) { int32 cnt = TotalActiveTweens; for (int32 i = 0; i < cnt; i++) { FGTweener* tweener = ActiveTweens[i]; if (tweener != nullptr && tweener->Handle == Handle && !tweener->bKilled) { Handle.Invalidate(); tweener->Kill(bCompleted); return true; } } Handle.Invalidate(); return false; } bool FTweenManager::KillTweens(UObject* Target, bool bCompleted) { if (Target == nullptr) return false; bool flag = false; int32 cnt = TotalActiveTweens; for (int32 i = 0; i < cnt; i++) { FGTweener* tweener = ActiveTweens[i]; if (tweener != nullptr && tweener->Target.Get() == Target && !tweener->bKilled) { tweener->Kill(bCompleted); flag = true; } } return flag; } FGTweener* FTweenManager::GetTween(FTweenerHandle const& Handle) { if (!Handle.IsValid()) return nullptr; int32 cnt = TotalActiveTweens; for (int32 i = 0; i < cnt; i++) { FGTweener* tweener = ActiveTweens[i]; if (tweener != nullptr && tweener->Handle == Handle && !tweener->bKilled) { return tweener; } } return nullptr; } FGTweener* FTweenManager::GetTween(UObject* Target) { if (Target == nullptr) return nullptr; int32 cnt = TotalActiveTweens; for (int32 i = 0; i < cnt; i++) { FGTweener* tweener = ActiveTweens[i]; if (tweener != nullptr && tweener->Target.Get() == Target && !tweener->bKilled) { return tweener; } } return nullptr; } void FTweenManager::Tick(float DeltaTime) { int32 cnt = TotalActiveTweens; int32 freePosStart = -1; for (int32 i = 0; i < cnt; i++) { FGTweener* tweener = ActiveTweens[i]; if (tweener == nullptr) { if (freePosStart == -1) freePosStart = i; } else if (tweener->bKilled) { tweener->Reset(); TweenerPool.Add(tweener); ActiveTweens[i] = nullptr; if (freePosStart == -1) freePosStart = i; } else { if (tweener->Target.IsStale()) tweener->bKilled = true; else if (!tweener->bPaused) tweener->Update(DeltaTime); if (freePosStart != -1) { ActiveTweens[freePosStart] = tweener; ActiveTweens[i] = nullptr; freePosStart++; } } } if (freePosStart >= 0) { if (TotalActiveTweens != cnt) //new tweens added { int32 j = cnt; cnt = TotalActiveTweens - cnt; for (int32 i = 0; i < cnt; i++) ActiveTweens[freePosStart++] = ActiveTweens[j++]; } TotalActiveTweens = freePosStart; } } ================================================ FILE: Source/FairyGUI/Private/Tween/TweenValue.cpp ================================================ #include "Tween/TweenValue.h" FTweenValue::FTweenValue() :X(0), Y(0), Z(0), W(0), D(0) { } FVector2D FTweenValue::GetVec2() const { return FVector2D(X, Y); } void FTweenValue::SetVec2(const FVector2D & Value) { X = Value.X; Y = Value.Y; } FVector FTweenValue::GetVec3() const { return FVector(X, Y, Z); } void FTweenValue::SetVec3(const FVector & Value) { X = Value.X; Y = Value.Y; Z = Value.Z; } FVector4 FTweenValue::GetVec4() const { return FVector4(X, Y, Z, W); } void FTweenValue::SetVec4(const FVector4 & Value) { X = Value.X; Y = Value.Y; Z = Value.Z; W = Value.W; } FColor FTweenValue::GetColor() const { return FColor(X * 255, Y * 255, Z * 255, W * 255); } void FTweenValue::SetColor(const FColor & Value) { X = Value.R / 255.f; Y = Value.G / 255.f; Z = Value.B / 255.f; W = Value.A / 255.f; } float FTweenValue::operator[](int32 Index) const { verifyf(Index < 4, TEXT("Index out of bounds: %d"), Index); switch (Index) { case 0: return X; case 1: return Y; case 2: return Z; case 3: return W; default: return X; } } float& FTweenValue::operator[](int32 Index) { verifyf(Index < 4, TEXT("Index out of bounds: %d"), Index); switch (Index) { case 0: return X; case 1: return Y; case 2: return Z; case 3: return W; default: return X; } } void FTweenValue::Reset() { X = Y = Z = W = 0; D = 0; } ================================================ FILE: Source/FairyGUI/Private/UI/ControllerAction/ChangePageAction.cpp ================================================ #include "UI/ControllerAction/ChangePageAction.h" #include "UI/GController.h" #include "Utils/ByteBuffer.h" #include "UI/GComponent.h" void FChangePageAction::Setup(FByteBuffer* Buffer) { FControllerAction::Setup(Buffer); ObjectID = Buffer->ReadS(); ControllerName = Buffer->ReadS(); TargetPage = Buffer->ReadS(); } void FChangePageAction::Enter(UGController* Controller) { if (ControllerName.IsEmpty()) return; UGComponent* gcom; if (!ObjectID.IsEmpty()) gcom = Cast(Cast(Controller->GetOuter())->GetChildByID(ObjectID)); else gcom = Cast(Controller->GetOuter()); if (gcom != nullptr) { UGController* cc = gcom->GetController(ControllerName); if (cc != nullptr && cc != Controller && !cc->bChanging) { if (TargetPage.Compare("~1") == 0) { if (Controller->GetSelectedIndex() < cc->GetPageCount()) cc->SetSelectedIndex(Controller->GetSelectedIndex()); } else if (TargetPage.Compare("~2") == 0) cc->SetSelectedPage(Controller->GetSelectedPage()); else cc->SetSelectedPageID(TargetPage); } } } void FChangePageAction::Leave(UGController* Controller) { } ================================================ FILE: Source/FairyGUI/Private/UI/ControllerAction/ControllerAction.cpp ================================================ #include "UI/ControllerAction/ControllerAction.h" #include "UI/ControllerAction/ChangePageAction.h" #include "UI/ControllerAction/PlayTransitionAction.h" #include "Utils/ByteBuffer.h" FControllerAction * FControllerAction::CreateAction(int32 ActionType) { switch (ActionType) { case 0: return new FPlayTransitionAction(); case 1: return new FChangePageAction(); } return nullptr; } FControllerAction::FControllerAction() { } FControllerAction::~FControllerAction() { } void FControllerAction::Run(UGController* Controller, const FString& PreviousPage, const FString& CurrentPage) { if ((FromPage.Num() == 0 || FromPage.Contains(PreviousPage)) && (ToPage.Num() == 0 || ToPage.Contains(CurrentPage))) Enter(Controller); else Leave(Controller); } void FControllerAction::Setup(FByteBuffer * Buffer) { int32 cnt; cnt = Buffer->ReadShort(); FromPage.SetNum(cnt); for (int32 i = 0; i < cnt; i++) FromPage[i] = Buffer->ReadS(); cnt = Buffer->ReadShort(); ToPage.SetNum(cnt); for (int32 i = 0; i < cnt; i++) ToPage[i] = Buffer->ReadS(); } ================================================ FILE: Source/FairyGUI/Private/UI/ControllerAction/PlayTransitionAction.cpp ================================================ #include "UI/ControllerAction/PlayTransitionAction.h" #include "UI/GController.h" #include "UI/Transition.h" #include "UI/GComponent.h" #include "Utils/ByteBuffer.h" FPlayTransitionAction::FPlayTransitionAction() : PlayTimes(1), Delay(0), bStopOnExit(false), CurrentTransition(nullptr) { } void FPlayTransitionAction::Setup(FByteBuffer* Buffer) { FControllerAction::Setup(Buffer); TransitionName = Buffer->ReadS(); PlayTimes = Buffer->ReadInt(); Delay = Buffer->ReadFloat(); bStopOnExit = Buffer->ReadBool(); } void FPlayTransitionAction::Enter(UGController* Controller) { UTransition* trans = Cast(Controller->GetOuter())->GetTransition(TransitionName); if (trans != nullptr) { if (CurrentTransition != nullptr && CurrentTransition->IsPlaying()) trans->ChangePlayTimes(PlayTimes); else trans->Play(PlayTimes, Delay); CurrentTransition = trans; } } void FPlayTransitionAction::Leave(UGController* Controller) { if (bStopOnExit && CurrentTransition != nullptr) { CurrentTransition->Stop(); CurrentTransition = nullptr; } } ================================================ FILE: Source/FairyGUI/Private/UI/DragDropManager.cpp ================================================ #include "UI/DragDropManager.h" #include "UI/UIObjectFactory.h" #include "UI/GRoot.h" #include "FairyApplication.h" UDragDropManager::UDragDropManager() { } UDragDropManager::~UDragDropManager() { } void UDragDropManager::CreateAgent() { Agent = (UGLoader*)FUIObjectFactory::NewObject(EObjectType::Loader, this); Agent->Name = TEXT("DragDropAgent"); Agent->SetTouchable(false); Agent->SetDraggable(true); Agent->SetSize(FVector2D(100, 100)); Agent->SetPivot(FVector2D(.5f, .5f), true); Agent->SetAlign(EAlignType::Center); Agent->SetVerticalAlign(EVerticalAlignType::Middle); Agent->SetSortingOrder(INT_MAX); Agent->On(FUIEvents::DragEnd).AddUObject(this, &UDragDropManager::OnDragEnd); } void UDragDropManager::StartDrag(const FString& InIcon, const FNVariant& InUserData, int32 InUserIndex, int32 InPointerIndex) { if (Agent->GetParent() != nullptr) return; UserData = InUserData; Agent->SetURL(InIcon); Agent->SetParentToRoot(); FVector2D pt = Agent->GetUIRoot()->GlobalToLocal(Agent->GetApp()->GetTouchPosition(InUserIndex, InPointerIndex)); Agent->SetPosition(pt); Agent->GetApp()->CallAfterSlateTick(FSimpleDelegate::CreateUObject(this, &UDragDropManager::DelayStartDrag, InUserIndex, InPointerIndex)); } void UDragDropManager::DelayStartDrag(int32 InUserIndex, int32 InPointerIndex) { if (Agent->GetParent() != nullptr) Agent->StartDrag(InUserIndex, InPointerIndex); } void UDragDropManager::Cancel() { if (Agent->GetParent() != nullptr) { Agent->StopDrag(); Agent->RemoveFromParent(); UserData.Reset(); } } void UDragDropManager::OnDragEnd(UEventContext* Context) { if (Agent->GetParent() == nullptr) //canceled return; Agent->RemoveFromParent(); UGObject* obj = Agent->GetApp()->GetObjectUnderPoint(Context->GetPointerPosition()); while (obj != nullptr) { if (obj->IsA()) { if (obj->HasEventListener(FUIEvents::Drop)) { obj->DispatchEvent(FUIEvents::Drop, UserData); return; } } obj = obj->GetParent(); } } ================================================ FILE: Source/FairyGUI/Private/UI/GButton.cpp ================================================ #include "UI/GButton.h" #include "UI/GTextField.h" #include "UI/GLabel.h" #include "UI/GController.h" #include "Utils/ByteBuffer.h" #include "FairyApplication.h" const FString UGButton::UP = "up"; const FString UGButton::DOWN = "down"; const FString UGButton::OVER = "over"; const FString UGButton::SELECTED_OVER = "selectedOver"; const FString UGButton::DISABLED = "disabled"; const FString UGButton::SELECTED_DISABLED = "selectedDisabled"; UGButton::UGButton() : bChangeStateOnClick(true), DownEffectValue(0.8f) { Sound = FUIConfig::Config.ButtonSound; SoundVolumeScale = FUIConfig::Config.ButtonSoundVolumeScale; } UGButton::~UGButton() { } void UGButton::SetText(const FString& InText) { Title = InText; if (TitleObject != nullptr) TitleObject->SetText(InText); UpdateGear(6); } const FString& UGButton::GetIcon() const { if (IconObject != nullptr) return IconObject->GetIcon(); else return G_EMPTY_STRING; } void UGButton::SetIcon(const FString & InIcon) { if (IconObject != nullptr) IconObject->SetIcon(InIcon); UpdateGear(7); } void UGButton::SetSelectedTitle(const FString& InTitle) { SelectedTitle = InTitle; if (TitleObject != nullptr) TitleObject->SetText((bSelected && SelectedTitle.Len() > 0) ? SelectedTitle : Title); } void UGButton::SetSelectedIcon(const FString& InIcon) { SelectedIcon = InIcon; if (IconObject != nullptr) IconObject->SetIcon((bSelected && SelectedIcon.Len() > 0) ? SelectedIcon : Icon); } FColor UGButton::GetTitleColor() const { UGTextField* TextField = GetTextField(); if (TextField) return TextField->GetTextFormat().Color; else return FColor::Black; } void UGButton::SetTitleColor(const FColor & InColor) { UGTextField* TextField = GetTextField(); if (TextField) { TextField->GetTextFormat().Color = InColor; TextField->ApplyFormat(); } } int32 UGButton::GetTitleFontSize() const { UGTextField* TextField = GetTextField(); if (TextField) return TextField->GetTextFormat().Size; else return 0; } void UGButton::SetTitleFontSize(int32 InFontSize) { UGTextField* TextField = GetTextField(); if (TextField) { TextField->GetTextFormat().Size = InFontSize; TextField->ApplyFormat(); } } void UGButton::SetSelected(bool bInSelected) { if (Mode == EButtonMode::Common) return; if (bSelected != bInSelected) { bSelected = bInSelected; SetCurrentState(); if (!SelectedTitle.IsEmpty() && TitleObject != nullptr) TitleObject->SetText(bSelected ? SelectedTitle : Title); if (!SelectedIcon.IsEmpty()) { const FString& str = bSelected ? SelectedIcon : Icon; if (IconObject != nullptr) IconObject->SetIcon(str); } if (RelatedController != nullptr && GetParent() != nullptr && !GetParent()->bBuildingDisplayList) { if (bSelected) { RelatedController->SetSelectedPageID(RelatedPageID); if (RelatedController->bAutoRadioGroupDepth) GetParent()->AdjustRadioGroupDepth(this, RelatedController); } else if (Mode == EButtonMode::Check && RelatedController->GetSelectedPageID() == RelatedPageID) RelatedController->SetOppositePageID(RelatedPageID); } } } void UGButton::SetRelatedController(UGController* InController) { RelatedController = InController; } void UGButton::SetState(const FString& InState) { if (ButtonController != nullptr) ButtonController->SetSelectedPage(InState); if (DownEffect == 1) { int32 cnt = this->NumChildren(); if (InState == DOWN || InState == SELECTED_OVER || InState == SELECTED_DISABLED) { int32 c = DownEffectValue * 255; FNVariant Color(FColor(c, c, c, 255)); for (int32 i = 0; i < cnt; i++) { UGObject* Obj = this->GetChildAt(i); if (!Obj->IsA()) Obj->SetProp(EObjectPropID::Color, Color); } } else { FNVariant Color(FColor::White); for (int32 i = 0; i < cnt; i++) { UGObject* Obj = this->GetChildAt(i); if (!Obj->IsA()) Obj->SetProp(EObjectPropID::Color, Color); } } } else if (DownEffect == 2) { if (InState == DOWN || InState == SELECTED_OVER || InState == SELECTED_DISABLED) { if (!bDownScaled) { bDownScaled = true; SetScale(GetScale() * DownEffectValue); } } else { if (bDownScaled) { bDownScaled = false; SetScale(GetScale() / DownEffectValue); } } } } void UGButton::SetCurrentState() { if (IsGrayed() && ButtonController != nullptr && ButtonController->HasPage(DISABLED)) { if (bSelected) SetState(SELECTED_DISABLED); else SetState(DISABLED); } else { if (bSelected) SetState(bOver ? SELECTED_OVER : DOWN); else SetState(bOver ? OVER : UP); } } UGTextField * UGButton::GetTextField() const { if (TitleObject->IsA()) return Cast(TitleObject); else if (TitleObject->IsA()) return Cast(TitleObject)->GetTextField(); else if (TitleObject->IsA()) return Cast(TitleObject)->GetTextField(); else return nullptr; } FNVariant UGButton::GetProp(EObjectPropID PropID) const { switch (PropID) { case EObjectPropID::Color: return FNVariant(GetTitleColor()); case EObjectPropID::OutlineColor: { UGTextField* TextField = GetTextField(); if (TextField != nullptr) return FNVariant(TextField->GetTextFormat().OutlineColor); else return FNVariant(FColor::Black); } case EObjectPropID::FontSize: return FNVariant(GetTitleFontSize()); case EObjectPropID::Selected: return FNVariant(IsSelected()); default: return UGComponent::GetProp(PropID); } } void UGButton::SetProp(EObjectPropID PropID, const FNVariant& InValue) { switch (PropID) { case EObjectPropID::Color: SetTitleColor(InValue.AsColor()); break; case EObjectPropID::OutlineColor: { UGTextField* TextField = GetTextField(); if (TextField != nullptr) { TextField->GetTextFormat().OutlineColor = InValue.AsColor(); TextField->ApplyFormat(); } break; } case EObjectPropID::FontSize: SetTitleFontSize(InValue.AsInt()); break; case EObjectPropID::Selected: SetSelected(InValue.AsBool()); break; default: UGComponent::SetProp(PropID, InValue); break; } } void UGButton::ConstructExtension(FByteBuffer* Buffer) { Buffer->Seek(0, 6); Mode = (EButtonMode)Buffer->ReadByte(); Buffer->ReadS(Sound); SoundVolumeScale = Buffer->ReadFloat(); DownEffect = Buffer->ReadByte(); DownEffectValue = Buffer->ReadFloat(); if (DownEffect == 2) SetPivot(FVector2D(0.5f, 0.5f), IsPivotAsAnchor()); ButtonController = GetController("button"); TitleObject = GetChild("title"); IconObject = GetChild("icon"); if (TitleObject != nullptr) Title = TitleObject->GetText(); if (IconObject != nullptr) Icon = IconObject->GetIcon(); if (Mode == EButtonMode::Common) SetState(UP); On(FUIEvents::RollOver).AddUObject(this, &UGButton::OnRollOverHandler); On(FUIEvents::RollOut).AddUObject(this, &UGButton::OnRollOutHandler); On(FUIEvents::TouchBegin).AddUObject(this, &UGButton::OnTouchBeginHandler); On(FUIEvents::TouchEnd).AddUObject(this, &UGButton::OnTouchEndHandler); On(FUIEvents::Click).AddUObject(this, &UGButton::OnClickHandler); On(FUIEvents::RemovedFromStage).AddUObject(this, &UGButton::OnRemovedFromStageHandler); } void UGButton::SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos) { UGComponent::SetupAfterAdd(Buffer, BeginPos); if (!Buffer->Seek(BeginPos, 6)) return; if ((EObjectType)Buffer->ReadByte() != PackageItem->ObjectType) return; const FString* str; if ((str = Buffer->ReadSP()) != nullptr) SetTitle(*str); if ((str = Buffer->ReadSP()) != nullptr) SetSelectedTitle(*str); if ((str = Buffer->ReadSP()) != nullptr) SetIcon(*str); if ((str = Buffer->ReadSP()) != nullptr) SetSelectedIcon(*str); if (Buffer->ReadBool()) SetTitleColor(Buffer->ReadColor()); int32 iv = Buffer->ReadInt(); if (iv != 0) SetTitleFontSize(iv); iv = Buffer->ReadShort(); if (iv >= 0) RelatedController = GetParent()->GetControllerAt(iv); RelatedPageID = Buffer->ReadS(); Buffer->ReadS(Sound); if (Buffer->ReadBool()) SoundVolumeScale = Buffer->ReadFloat(); SetSelected(Buffer->ReadBool()); } void UGButton::HandleControllerChanged(UGController* Controller) { UGObject::HandleControllerChanged(Controller); if (RelatedController == Controller) SetSelected(RelatedPageID == Controller->GetSelectedPageID()); } void UGButton::OnRollOverHandler(UEventContext* Context) { if (ButtonController == nullptr || !ButtonController->HasPage(OVER)) return; bOver = true; if (bDown) return; if (IsGrayed() && ButtonController->HasPage(DISABLED)) return; SetState(bSelected ? SELECTED_OVER : OVER); } void UGButton::OnRollOutHandler(UEventContext* Context) { if (ButtonController == nullptr || !ButtonController->HasPage(OVER)) return; bOver = false; if (bDown) return; if (IsGrayed() && ButtonController->HasPage(DISABLED)) return; SetState(bSelected ? DOWN : UP); } void UGButton::OnTouchBeginHandler(UEventContext* Context) { if (Context->GetMouseButton() != EKeys::LeftMouseButton) return; bDown = true; Context->CaptureTouch(); if (Mode == EButtonMode::Common) { if (IsGrayed() && ButtonController != nullptr && ButtonController->HasPage(DISABLED)) SetState(SELECTED_DISABLED); else SetState(DOWN); } } void UGButton::OnTouchEndHandler(UEventContext* Context) { if (Context->GetMouseButton() != EKeys::LeftMouseButton) return; if (bDown) { bDown = false; if (Mode == EButtonMode::Common) { if (IsGrayed() && ButtonController != nullptr && ButtonController->HasPage(DISABLED)) SetState(DISABLED); else if (bOver) SetState(OVER); else SetState(UP); } else { if (!bOver && ButtonController != nullptr && (ButtonController->GetSelectedPage() == OVER || ButtonController->GetSelectedPage() == SELECTED_OVER)) { SetCurrentState(); } } } } void UGButton::OnClickHandler(UEventContext* Context) { if (!Sound.IsEmpty()) GetApp()->PlaySound(Sound, SoundVolumeScale); if (Mode == EButtonMode::Check) { if (bChangeStateOnClick) { SetSelected(!bSelected); DispatchEvent(FUIEvents::Changed); } } else if (Mode == EButtonMode::Radio) { if (bChangeStateOnClick && !bSelected) { SetSelected(true); DispatchEvent(FUIEvents::Changed); } } else { if (RelatedController != nullptr) RelatedController->SetSelectedPageID(RelatedPageID); } } void UGButton::OnRemovedFromStageHandler(UEventContext* Context) { if (bOver) OnRollOutHandler(Context); } ================================================ FILE: Source/FairyGUI/Private/UI/GComboBox.cpp ================================================ #include "UI/GComboBox.h" #include "UI/UIPackage.h" #include "UI/GTextField.h" #include "UI/GTextInput.h" #include "UI/GLabel.h" #include "UI/GButton.h" #include "UI/GController.h" #include "UI/GList.h" #include "UI/GRoot.h" #include "Utils/ByteBuffer.h" UGComboBox::UGComboBox() : bItemsUpdated(true), SelectedIndex(-1) { VisibleItemCount = FUIConfig::Config.DefaultComboBoxVisibleItemCount; } UGComboBox::~UGComboBox() { } const FString& UGComboBox::GetText() const { if (TitleObject != nullptr) return TitleObject->GetText(); else return G_EMPTY_STRING; } void UGComboBox::SetText(const FString& InText) { if (TitleObject != nullptr) TitleObject->SetText(InText); UpdateGear(6); } const FString& UGComboBox::GetIcon() const { if (IconObject != nullptr) return IconObject->GetIcon(); else return G_EMPTY_STRING; } void UGComboBox::SetIcon(const FString & InIcon) { if (IconObject != nullptr) IconObject->SetIcon(InIcon); UpdateGear(7); } FColor UGComboBox::GetTitleColor() const { UGTextField* TextField = GetTextField(); if (TextField) return TextField->GetTextFormat().Color; else return FColor::Black; } void UGComboBox::SetTitleColor(const FColor & InColor) { UGTextField* TextField = GetTextField(); if (TextField) { TextField->GetTextFormat().Color = InColor; TextField->ApplyFormat(); } } int32 UGComboBox::GetTitleFontSize() const { UGTextField* TextField = GetTextField(); if (TextField) return TextField->GetTextFormat().Size; else return 0; } void UGComboBox::SetTitleFontSize(int32 InFontSize) { UGTextField* TextField = GetTextField(); if (TextField) { TextField->GetTextFormat().Size = InFontSize; TextField->ApplyFormat(); } } const FString& UGComboBox::GetValue() const { if (SelectedIndex >= 0 && SelectedIndex < Values.Num()) return Values[SelectedIndex]; else return G_EMPTY_STRING; } void UGComboBox::SetValue(const FString& InValue) { SetSelectedIndex(Values.Find(InValue)); } void UGComboBox::SetSelectedIndex(int32 InIndex) { if (SelectedIndex == InIndex) return; SelectedIndex = InIndex; if (SelectedIndex >= 0 && SelectedIndex < Items.Num()) { SetText(Items[SelectedIndex]); if (Icons.Num() > 0 && SelectedIndex != -1 && SelectedIndex < Icons.Num()) SetIcon(Icons[SelectedIndex]); } else { SetTitle(G_EMPTY_STRING); if (Icons.Num() > 0) SetIcon(G_EMPTY_STRING); } UpdateSelectionController(); } void UGComboBox::Refresh() { if (Items.Num() > 0) { if (SelectedIndex >= Items.Num()) SelectedIndex = Items.Num() - 1; else if (SelectedIndex == -1) SelectedIndex = 0; SetTitle(Items[SelectedIndex]); } else { SetTitle(G_EMPTY_STRING); SelectedIndex = -1; } if (Icons.Num() > 0) { if (SelectedIndex != -1 && SelectedIndex < Icons.Num()) SetIcon(Icons[SelectedIndex]); else SetIcon(G_EMPTY_STRING); } bItemsUpdated = true; } void UGComboBox::SetState(const FString& InState) { if (ButtonController != nullptr) ButtonController->SetSelectedPage(InState); } void UGComboBox::SetCurrentState() { if (IsGrayed() && ButtonController != nullptr && ButtonController->HasPage(UGButton::DISABLED)) SetState(UGButton::DISABLED); else if (DropdownObject != nullptr && DropdownObject->GetParent() != nullptr) SetState(UGButton::DOWN); else SetState(bOver ? UGButton::OVER : UGButton::UP); } void UGComboBox::UpdateSelectionController() { if (SelectionController != nullptr && !SelectionController->bChanging && SelectedIndex < SelectionController->GetPageCount()) { UGController* c = SelectionController; SelectionController = nullptr; c->SetSelectedIndex(SelectedIndex); SelectionController = c; } } void UGComboBox::UpdateDropdownList() { if (bItemsUpdated) { bItemsUpdated = false; RenderDropdownList(); ListObject->ResizeToFit(VisibleItemCount); } } void UGComboBox::ShowDropdown() { UpdateDropdownList(); if (ListObject->GetSelectionMode() == EListSelectionMode::Single) ListObject->SetSelectedIndex(-1); DropdownObject->SetWidth(Size.X); ListObject->EnsureBoundsCorrect(); GetUIRoot()->TogglePopup(DropdownObject, this, PopupDirection); if (DropdownObject->GetParent() != nullptr) SetState(UGButton::DOWN); } void UGComboBox::RenderDropdownList() { ListObject->RemoveChildrenToPool(); int32 cnt = Items.Num(); for (int32 i = 0; i < cnt; i++) { UGObject* Obj = ListObject->AddItemFromPool(); Obj->SetText(Items[i]); Obj->SetIcon((Icons.Num() > 0 && i < Icons.Num()) ? Icons[i] : G_EMPTY_STRING); Obj->Name = i < Values.Num() ? Values[i] : G_EMPTY_STRING; } } void UGComboBox::HandleControllerChanged(UGController* Controller) { UGComponent::HandleControllerChanged(Controller); if (SelectionController == Controller) SetSelectedIndex(Controller->GetSelectedIndex()); } void UGComboBox::HandleGrayedChanged() { if (ButtonController != nullptr && ButtonController->HasPage(UGButton::DISABLED)) { if (IsGrayed()) SetState(UGButton::DISABLED); else SetState(UGButton::UP); } else UGComponent::HandleGrayedChanged(); } UGTextField* UGComboBox::GetTextField() const { if (TitleObject->IsA()) return Cast(TitleObject); else if (TitleObject->IsA()) return Cast(TitleObject)->GetTextField(); else if (TitleObject->IsA()) return Cast(TitleObject)->GetTextField(); else return nullptr; } FNVariant UGComboBox::GetProp(EObjectPropID PropID) const { switch (PropID) { case EObjectPropID::Color: return FNVariant(GetTitleColor()); case EObjectPropID::OutlineColor: { UGTextField* TextField = GetTextField(); if (TextField != nullptr) return FNVariant(TextField->GetTextFormat().OutlineColor); else return FNVariant(FColor::Black); } case EObjectPropID::FontSize: return FNVariant(GetTitleFontSize()); default: return UGComponent::GetProp(PropID); } } void UGComboBox::SetProp(EObjectPropID PropID, const FNVariant& InValue) { switch (PropID) { case EObjectPropID::Color: SetTitleColor(InValue.AsColor()); break; case EObjectPropID::OutlineColor: { UGTextField* TextField = GetTextField(); if (TextField != nullptr) { TextField->GetTextFormat().OutlineColor = InValue.AsColor(); TextField->ApplyFormat(); } break; } case EObjectPropID::FontSize: SetTitleFontSize(InValue.AsInt()); break; default: UGComponent::SetProp(PropID, InValue); break; } } void UGComboBox::ConstructExtension(FByteBuffer* Buffer) { Buffer->Seek(0, 6); ButtonController = GetController("button"); TitleObject = GetChild("title"); IconObject = GetChild("icon"); const FString& dropdownResource = Buffer->ReadS(); if (!dropdownResource.IsEmpty()) { DropdownObject = Cast(UUIPackage::CreateObjectFromURL(dropdownResource, this)); verifyf(DropdownObject != nullptr, TEXT("should be a component.")); ListObject = Cast(DropdownObject->GetChild("list")); verifyf(ListObject != nullptr, TEXT("should container a list component named list.")); ListObject->On(FUIEvents::ClickItem).AddUObject(this, &UGComboBox::OnClickItem); ListObject->AddRelation(DropdownObject, ERelationType::Width); ListObject->RemoveRelation(DropdownObject, ERelationType::Height); DropdownObject->AddRelation(ListObject, ERelationType::Height); DropdownObject->RemoveRelation(ListObject, ERelationType::Width); DropdownObject->On(FUIEvents::RemovedFromStage).AddUObject(this, &UGComboBox::OnPopupWinClosed); } On(FUIEvents::RollOver).AddUObject(this, &UGComboBox::OnRollOverHandler); On(FUIEvents::RollOut).AddUObject(this, &UGComboBox::OnRollOutHandler); On(FUIEvents::TouchBegin).AddUObject(this, &UGComboBox::OnTouchBeginHandler); On(FUIEvents::TouchEnd).AddUObject(this, &UGComboBox::OnTouchEndHandler); } void UGComboBox::SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos) { UGComponent::SetupAfterAdd(Buffer, BeginPos); if (!Buffer->Seek(BeginPos, 6)) return; if ((EObjectType)Buffer->ReadByte() != PackageItem->ObjectType) return; const FString* str; bool hasIcon = false; int32 itemCount = Buffer->ReadShort(); for (int32 i = 0; i < itemCount; i++) { int32 nextPos = Buffer->ReadShort(); nextPos += Buffer->GetPos(); Items.Add(Buffer->ReadS()); Values.Add(Buffer->ReadS()); if ((str = Buffer->ReadSP()) != nullptr) { if (!hasIcon) { for (int32 j = 0; j < Items.Num() - 1; j++) Icons.Add(G_EMPTY_STRING); } Icons.Add(*str); } Buffer->SetPos(nextPos); } if ((str = Buffer->ReadSP()) != nullptr) { SetTitle(*str); SelectedIndex = Items.Find(*str); } else if (Items.Num() > 0) { SelectedIndex = 0; SetTitle(Items[0]); } else SelectedIndex = -1; if ((str = Buffer->ReadSP()) != nullptr) SetIcon(*str); if (Buffer->ReadBool()) SetTitleColor(Buffer->ReadColor()); int32 iv = Buffer->ReadInt(); if (iv > 0) VisibleItemCount = iv; PopupDirection = (EPopupDirection)Buffer->ReadByte(); iv = Buffer->ReadShort(); if (iv >= 0) SelectionController = GetParent()->GetControllerAt(iv); } void UGComboBox::OnClickItem(UEventContext* Context) { if (DropdownObject->GetParent()->IsA()) ((UGRoot*)DropdownObject->GetParent())->HidePopup(DropdownObject); SelectedIndex = INT_MIN; SetSelectedIndex(ListObject->GetChildIndex(Cast(Context->GetData().AsUObject()))); DispatchEvent(FUIEvents::Changed); } void UGComboBox::OnRollOverHandler(UEventContext* Context) { bOver = true; if (bDown || (DropdownObject != nullptr && DropdownObject->GetParent() != nullptr)) return; SetCurrentState(); } void UGComboBox::OnRollOutHandler(UEventContext* Context) { bOver = false; if (bDown || (DropdownObject != nullptr && DropdownObject->GetParent() != nullptr)) return; SetCurrentState(); } void UGComboBox::OnTouchBeginHandler(UEventContext* Context) { if (Context->GetMouseButton() != EKeys::LeftMouseButton) return; if (Context->GetInitiator()->IsA()) return; bDown = true; if (DropdownObject != nullptr) ShowDropdown(); Context->CaptureTouch(); } void UGComboBox::OnTouchEndHandler(UEventContext* Context) { if (Context->GetMouseButton() != EKeys::LeftMouseButton) return; if (bDown) { bDown = false; if (DropdownObject != nullptr && DropdownObject->GetParent() != nullptr) SetCurrentState(); } } void UGComboBox::OnPopupWinClosed(UEventContext* Context) { SetCurrentState(); } ================================================ FILE: Source/FairyGUI/Private/UI/GComponent.cpp ================================================ #include "UI/GComponent.h" #include "UI/GButton.h" #include "UI/GGroup.h" #include "UI/Relations.h" #include "UI/TranslationHelper.h" #include "UI/UIObjectFactory.h" #include "UI/UIPackage.h" #include "UI/GController.h" #include "UI/Transition.h" #include "UI/GRoot.h" #include "Utils/ByteBuffer.h" #include "Widgets/SContainer.h" #include "Widgets/HitTest.h" #include "Tween/GTween.h" #include "FairyApplication.h" UGComponent::UGComponent() : AlignOffset(ForceInit) { DisplayObject = RootContainer = SNew(SContainer).GObject(this); DisplayObject->SetOpaque(false); Container = SNew(SContainer); Container->SetOpaque(false); RootContainer->AddChild(Container.ToSharedRef()); } UGComponent::~UGComponent() { } UGObject* UGComponent::AddChild(UGObject* Child) { AddChildAt(Child, Children.Num()); return Child; } UGObject* UGComponent::AddChildAt(UGObject* Child, int32 Index) { verifyf(Child != nullptr, TEXT("Argument must be non-nil")); verifyf(Index >= 0 && Index <= Children.Num(), TEXT("Invalid child index")); if (Child->Parent == this) { SetChildIndex(Child, Index); } else { Child->RemoveFromParent(); Child->Parent = this; int32 cnt = Children.Num(); if (Child->SortingOrder != 0) { SortingChildCount++; Index = GetInsertPosForSortingChild(Child); } else if (SortingChildCount > 0) { if (Index > (cnt - SortingChildCount)) Index = cnt - SortingChildCount; } if (Index == cnt) Children.Add(Child); else Children.Insert(Child, Index); ChildStateChanged(Child); SetBoundsChangedFlag(); } return Child; } int32 UGComponent::GetInsertPosForSortingChild(UGObject* Child) { int32 cnt = Children.Num(); int32 i; for (i = 0; i < cnt; i++) { UGObject* Obj = Children[i]; if (Obj == Child) continue; if (Child->SortingOrder < Obj->SortingOrder) break; } return i; } void UGComponent::RemoveChild(UGObject* Child) { verifyf(Child != nullptr, TEXT("Argument must be non-nil")); int32 ChildIndex = Children.Find(Child); if (ChildIndex != INDEX_NONE) RemoveChildAt(ChildIndex); } void UGComponent::RemoveChildAt(int32 Index) { verifyf(Index >= 0 && Index < Children.Num(), TEXT("Invalid child index")); UGObject* Child = Children[Index]; Child->Parent = nullptr; if (Child->SortingOrder != 0) SortingChildCount--; Child->SetGroup(nullptr); if (Child->DisplayObject->GetParentWidget().IsValid()) { Container->RemoveChild(Child->DisplayObject.ToSharedRef()); if (ChildrenRenderOrder == EChildrenRenderOrder::Arch) BuildNativeDisplayList(); } Children.RemoveAt(Index); SetBoundsChangedFlag(); } void UGComponent::RemoveChildren(int32 BeginIndex, int32 EndIndex) { if (EndIndex < 0 || EndIndex >= Children.Num()) EndIndex = Children.Num() - 1; for (int32 i = BeginIndex; i <= EndIndex; ++i) RemoveChildAt(BeginIndex); } UGObject* UGComponent::GetChildAt(int32 Index, TSubclassOf ClassType) const { verifyf(Index >= 0 && Index < Children.Num(), TEXT("Invalid child index")); return Children[Index]; } UGObject* UGComponent::GetChild(const FString& ChildName, TSubclassOf ClassType) const { for (const auto& Child : Children) { if (Child->Name.Compare(ChildName) == 0) return Child; } return nullptr; } UGObject* UGComponent::GetChildByPath(const FString& Path, TSubclassOf ClassType) const { const UGComponent* Com = this; UGObject* Obj = nullptr; int32 Index1 = 0, Index2 = -1; while ((Index2 = Path.Find(TEXT("."), ESearchCase::IgnoreCase, ESearchDir::FromStart, Index1)) != -1 || Index1 == 0) { if (Index2 == -1) Index2 = Path.Len(); if (Com == nullptr) { Com = Cast(Obj); if (Com == nullptr) { Obj = nullptr; break; } } Obj = Com->GetChild(Path.Mid(Index1, Index2 - Index1)); if (!Obj) break; Com = nullptr; Index1 = Index2 + 1; } return Obj; } UGObject* UGComponent::GetChildInGroup(const UGGroup* InGroup, const FString& ChildName, TSubclassOf ClassType) const { verifyf(InGroup != nullptr, TEXT("Argument must be non-nil")); for (const auto& Obj : Children) { if (Obj->GetGroup() == InGroup && Obj->Name.Compare(ChildName) == 0) return Obj; } return nullptr; } UGObject* UGComponent::GetChildByID(const FString& ChildID) const { for (const auto& Obj : Children) { if (Obj->ID.Compare(ChildID) == 0) return Obj; } return nullptr; } int32 UGComponent::GetChildIndex(const UGObject* Child) const { verifyf(Child != nullptr, TEXT("Argument must be non-nil")); return Children.IndexOfByKey(Child); } void UGComponent::SetChildIndex(UGObject* Child, int32 Index) { verifyf(Child != nullptr, TEXT("Argument must be non-nil")); int32 OldIndex = Children.Find(Child); verifyf(OldIndex != -1, TEXT("Not a child of this container")); if (Child->SortingOrder != 0) //no effect return; int32 cnt = Children.Num(); if (SortingChildCount > 0) { if (Index > (cnt - SortingChildCount - 1)) Index = cnt - SortingChildCount - 1; } MoveChild(Child, OldIndex, Index); } int UGComponent::SetChildIndexBefore(UGObject* Child, int32 Index) { verifyf(Child != nullptr, TEXT("Argument must be non-nil")); int32 OldIndex = Children.Find(Child); verifyf(OldIndex != -1, TEXT("Not a child of this container")); if (Child->SortingOrder != 0) //no effect return OldIndex; int32 cnt = Children.Num(); if (SortingChildCount > 0) { if (Index > (cnt - SortingChildCount - 1)) Index = cnt - SortingChildCount - 1; } if (OldIndex < Index) return MoveChild(Child, OldIndex, Index - 1); else return MoveChild(Child, OldIndex, Index); } int32 UGComponent::MoveChild(UGObject* Child, int32 OldIndex, int32 Index) { int32 cnt = Children.Num(); if (Index > cnt) Index = cnt; if (OldIndex == Index) return OldIndex; Children.RemoveAt(OldIndex); if (Index >= cnt) Children.Add(Child); else Children.Insert(Child, Index); if (Child->DisplayObject->IsParentValid()) { int32 DisplayIndex = 0; if (ChildrenRenderOrder == EChildrenRenderOrder::Ascent) { for (int32 i = 0; i < Index; i++) { UGObject* Obj = Children[i]; if (Obj->DisplayObject->IsParentValid()) DisplayIndex++; } Container->SetChildIndex(Child->DisplayObject.ToSharedRef(), DisplayIndex); } else if (ChildrenRenderOrder == EChildrenRenderOrder::Descent) { for (int32 i = cnt - 1; i > Index; i--) { UGObject* Obj = Children[i]; if (Obj->DisplayObject->IsParentValid()) DisplayIndex++; } Container->SetChildIndex(Child->DisplayObject.ToSharedRef(), DisplayIndex); } else BuildNativeDisplayList(); SetBoundsChangedFlag(); } return Index; } void UGComponent::SwapChildren(UGObject* Child1, UGObject* Child2) { verifyf(Child1 != nullptr, TEXT("Argument1 must be non-nil")); verifyf(Child2 != nullptr, TEXT("Argument2 must be non-nil")); int32 Index1 = Children.Find(Child1); int32 Index2 = Children.Find(Child2); verifyf(Index1 != -1, TEXT("Not a child of this container")); verifyf(Index2 != -1, TEXT("Not a child of this container")); SwapChildrenAt(Index1, Index2); } void UGComponent::SwapChildrenAt(int32 Index1, int32 Index2) { UGObject* Child1 = Children[Index1]; UGObject* Child2 = Children[Index2]; SetChildIndex(Child1, Index2); SetChildIndex(Child2, Index1); } int32 UGComponent::NumChildren() const { return Children.Num(); } bool UGComponent::IsAncestorOf(const UGObject* Obj) const { if (Obj == nullptr) return false; UGComponent* Com = Obj->Parent.Get(); while (Com != nullptr) { if (Com == this) return true; Com = Com->Parent.Get(); } return false; } bool UGComponent::IsChildInView(UGObject* Child) const { if (ScrollPane != nullptr) { return ScrollPane->IsChildInView(Child); } else if (DisplayObject->GetClipping() != EWidgetClipping::Inherit) { return Child->GetX() + Child->GetWidth() >= 0 && Child->GetX() <= GetWidth() && Child->GetY() + Child->GetHeight() >= 0 && Child->GetY() <= GetHeight(); } else return true; } int32 UGComponent::GetFirstChildInView() const { int32 i = 0; for (auto& Obj : Children) { if (IsChildInView(Obj)) return i; i++; } return -1; } UGController* UGComponent::GetController(const FString& ControllerName) const { for (const auto& Controller : Controllers) { if (Controller->Name.Compare(ControllerName) == 0) return Controller; } return nullptr; } void UGComponent::AddController(UGController* Controller) { verifyf(Controller != nullptr, TEXT("Argument must be non-nil")); Controllers.Add(Controller); } UGController* UGComponent::GetControllerAt(int32 Index) const { verifyf(Index >= 0 && Index < Controllers.Num(), TEXT("Invalid controller index")); return Controllers[Index]; } void UGComponent::RemoveController(UGController* Controller) { verifyf(Controller != nullptr, TEXT("Argument must be non-nil")); int32 Index = Controllers.Find(Controller); verifyf(Index != -1, TEXT("controller not exists")); ApplyController(Controller); Controllers.RemoveAt(Index); } void UGComponent::ApplyController(UGController* Controller) { ApplyingController = Controller; for (int32 i = 0; i < Children.Num(); i++) Children[i]->HandleControllerChanged(Controller); ApplyingController = nullptr; Controller->RunActions(); } void UGComponent::ApplyAllControllers() { for (const auto& Controller : Controllers) ApplyController(Controller); } UTransition* UGComponent::GetTransition(const FString& TransitionName) const { for (const auto& Transition : Transitions) { if (Transition->Name.Compare(TransitionName) == 0) return Transition; } return nullptr; } UTransition* UGComponent::GetTransitionAt(int32 Index) const { verifyf(Index >= 0 && Index < Transitions.Num(), TEXT("Invalid transition index")); return Transitions[Index]; } void UGComponent::AdjustRadioGroupDepth(UGObject* Obj, UGController* Controller) { int32 cnt = Children.Num(); int32 i; UGObject* Child; int32 myIndex = -1, maxIndex = -1; for (i = 0; i < cnt; i++) { Child = Children[i]; if (Child == Obj) { myIndex = i; } else if (Child->IsA() && ((UGButton*)Child)->GetRelatedController() == Controller) { if (i > maxIndex) maxIndex = i; } } if (myIndex < maxIndex) { if (ApplyingController != nullptr) Children[maxIndex]->HandleControllerChanged(ApplyingController); SwapChildrenAt(myIndex, maxIndex); } } bool UGComponent::IsOpaque() const { return DisplayObject->IsOpaque(); } void UGComponent::SetOpaque(bool bInOpaque) { DisplayObject->SetOpaque(bInOpaque); } void UGComponent::SetMargin(const FMargin& InMargin) { Margin = InMargin; } void UGComponent::SetChildrenRenderOrder(EChildrenRenderOrder InRenderOrder) { if (ChildrenRenderOrder != InRenderOrder) { ChildrenRenderOrder = InRenderOrder; BuildNativeDisplayList(); } } void UGComponent::SetApexIndex(int32 InApexIndex) { if (ApexIndex != InApexIndex) { ApexIndex = InApexIndex; if (ChildrenRenderOrder == EChildrenRenderOrder::Arch) BuildNativeDisplayList(); } } float UGComponent::GetViewWidth() const { if (ScrollPane != nullptr) return ScrollPane->GetViewSize().X; else return Size.X - Margin.Left - Margin.Right; } void UGComponent::SetViewWidth(float InViewWidth) { if (ScrollPane != nullptr) ScrollPane->SetViewWidth(InViewWidth); else SetWidth(InViewWidth + Margin.Left + Margin.Right); } float UGComponent::GetViewHeight() const { if (ScrollPane != nullptr) return ScrollPane->GetViewSize().Y; else return Size.Y - Margin.Top - Margin.Bottom; } void UGComponent::SetViewHeight(float InViewHeight) { if (ScrollPane != nullptr) ScrollPane->SetViewHeight(InViewHeight); else SetHeight(InViewHeight + Margin.Top + Margin.Bottom); } void UGComponent::SetHitArea(const TSharedPtr& InHitArea) { HitArea = InHitArea; DisplayObject->UpdateVisibilityFlags(); } void UGComponent::SetBoundsChangedFlag() { if (bBoundsChanged) return; if (ScrollPane == nullptr && !bTrackBounds) return; bBoundsChanged = true; GetApp()->DelayCall(UpdateBoundsTimerHandle, this, &UGComponent::EnsureBoundsCorrect); } void UGComponent::EnsureBoundsCorrect() { if (bBoundsChanged) UpdateBounds(); } void UGComponent::UpdateBounds() { float ax, ay, aw, ah; if (Children.Num() > 0) { ax = FLT_MAX; ay = FLT_MAX; float ar = -FLT_MAX, ab = -FLT_MAX; float tmp; int32 cnt = Children.Num(); for (int32 i = 0; i < cnt; ++i) { UGObject* child = Children[i]; tmp = child->GetX(); if (tmp < ax) ax = tmp; tmp = child->GetY(); if (tmp < ay) ay = tmp; tmp = child->GetX() + child->GetWidth(); if (tmp > ar) ar = tmp; tmp = child->GetY() + child->GetHeight(); if (tmp > ab) ab = tmp; } aw = ar - ax; ah = ab - ay; } else { ax = 0; ay = 0; aw = 0; ah = 0; } SetBounds(ax, ay, aw, ah); } void UGComponent::SetBounds(float ax, float ay, float aw, float ah) { bBoundsChanged = false; if (ScrollPane != nullptr) ScrollPane->SetContentSize(FVector2D(FMath::CeilToFloat(ax + aw), FMath::CeilToFloat(ay + ah))); } void UGComponent::ChildStateChanged(UGObject* Child) { if (bBuildingDisplayList) return; int32 cnt = Children.Num(); if (Cast(Child) != nullptr) { for (int32 i = 0; i < cnt; ++i) { UGObject* Obj = Children[i]; if (Obj->GetGroup() == Child) ChildStateChanged(Obj); } } if (Child->InternalVisible()) { if (!Child->DisplayObject->IsParentValid()) { if (ChildrenRenderOrder == EChildrenRenderOrder::Ascent) { int32 index = 0; for (int32 i = 0; i < cnt; i++) { UGObject* Obj = Children[i]; if (Obj == Child) break; if (Obj->DisplayObject->IsParentValid()) index++; } Container->AddChildAt(Child->DisplayObject.ToSharedRef(), index); } else if (ChildrenRenderOrder == EChildrenRenderOrder::Descent) { int32 index = 0; for (int32 i = cnt - 1; i >= 0; i--) { UGObject* Obj = Children[i]; if (Obj == Child) break; if (Obj->DisplayObject->IsParentValid()) index++; } Container->AddChildAt(Child->DisplayObject.ToSharedRef(), index); } else { BuildNativeDisplayList(); } } } else { if (Child->DisplayObject->IsParentValid()) { Container->RemoveChild(Child->DisplayObject.ToSharedRef()); if (ChildrenRenderOrder == EChildrenRenderOrder::Arch) { BuildNativeDisplayList(); } } } } void UGComponent::ChildSortingOrderChanged(UGObject* Child, int32 OldValue, int32 NewValue) { if (NewValue == 0) { SortingChildCount--; SetChildIndex(Child, Children.Num()); } else { if (OldValue == 0) SortingChildCount++; int32 OldIndex = Children.Find(Child); int32 Index = GetInsertPosForSortingChild(Child); if (OldIndex < Index) MoveChild(Child, OldIndex, Index - 1); else MoveChild(Child, OldIndex, Index); } } void UGComponent::BuildNativeDisplayList(bool bImmediatelly) { if (!bImmediatelly) { GetApp()->DelayCall(BuildDisplayListTimerHandle, this, &UGComponent::BuildNativeDisplayList, true); return; } int32 cnt = Children.Num(); if (cnt == 0) return; switch (ChildrenRenderOrder) { case EChildrenRenderOrder::Ascent: { for (int32 i = 0; i < cnt; i++) { UGObject* Child = Children[i]; if (Child->InternalVisible()) Container->AddChild(Child->DisplayObject.ToSharedRef()); } } break; case EChildrenRenderOrder::Descent: { for (int32 i = 0; i < cnt; i++) { UGObject* Child = Children[i]; if (Child->InternalVisible()) Container->AddChild(Child->DisplayObject.ToSharedRef()); } } break; case EChildrenRenderOrder::Arch: { int32 ai = FMath::Min(ApexIndex, cnt); for (int32 i = 0; i < ai; i++) { UGObject* Child = Children[i]; if (Child->InternalVisible()) Container->AddChild(Child->DisplayObject.ToSharedRef()); } for (int32 i = cnt - 1; i >= ai; i--) { UGObject* Child = Children[i]; if (Child->InternalVisible()) Container->AddChild(Child->DisplayObject.ToSharedRef()); } } break; default: break; } } FVector2D UGComponent::GetSnappingPosition(const FVector2D& InPoint) { int32 cnt = Children.Num(); if (cnt == 0) return InPoint; EnsureBoundsCorrect(); UGObject* Obj = nullptr; FVector2D ret = InPoint; int32 i = 0; if (ret.Y != 0) { for (; i < cnt; i++) { Obj = Children[i]; if (ret.Y < Obj->GetY()) { if (i == 0) { ret.Y = 0; break; } else { UGObject* prev = Children[i - 1]; if (ret.Y < prev->GetY() + prev->GetHeight() / 2) //top half part ret.Y = prev->GetY(); else //bottom half part ret.Y = Obj->GetY(); break; } } } if (i == cnt) ret.Y = Obj->GetY(); } if (ret.X != 0) { if (i > 0) i--; for (; i < cnt; i++) { Obj = Children[i]; if (ret.X < Obj->GetX()) { if (i == 0) { ret.X = 0; break; } else { UGObject* prev = Children[i - 1]; if (ret.X < prev->GetX() + prev->GetWidth() / 2) // top half part ret.X = prev->GetX(); else //bottom half part ret.X = Obj->GetX(); break; } } } if (i == cnt) ret.X = Obj->GetX(); } return ret; } void UGComponent::SetupOverflow(EOverflowType InOverflow) { if (InOverflow == EOverflowType::Hidden) { DisplayObject->SetClipping(EWidgetClipping::ClipToBoundsAlways); DisplayObject->SetCullingBoundsExtension(Margin); } Container->SetPosition(Margin.GetTopLeft()); } void UGComponent::SetupScroll(FByteBuffer* Buffer) { ScrollPane = NewObject(this); ScrollPane->Setup(Buffer); } void UGComponent::HandleSizeChanged() { UGObject::HandleSizeChanged(); if (ScrollPane != nullptr) ScrollPane->OnOwnerSizeChanged(); else Container->SetPosition(FVector2D(Margin.Left, Margin.Top)); if (DisplayObject->GetClipping() != EWidgetClipping::Inherit) DisplayObject->SetCullingBoundsExtension(Margin); } void UGComponent::HandleGrayedChanged() { UGObject::HandleGrayedChanged(); UGController* Controller = GetController("grayed"); if (Controller != nullptr) Controller->SetSelectedIndex(IsGrayed() ? 1 : 0); else { for (auto& Child : Children) Child->HandleGrayedChanged(); } } void UGComponent::HandleControllerChanged(UGController* Controller) { UGObject::HandleControllerChanged(Controller); if (ScrollPane != nullptr) ScrollPane->HandleControllerChanged(Controller); } void UGComponent::OnAddedToStageHandler(UEventContext* Context) { for (auto& Transition : Transitions) Transition->OnOwnerAddedToStage(); } void UGComponent::OnRemovedFromStageHandler(UEventContext* Context) { for (auto& Transition : Transitions) Transition->OnOwnerRemovedFromStage(); } void UGComponent::ConstructFromResource() { ConstructFromResource(nullptr, 0); } void UGComponent::ConstructFromResource(TArray* ObjectPool, int32 PoolIndex) { TSharedPtr ContentItem = PackageItem->GetBranch(); if (!ContentItem->bTranslated) { ContentItem->bTranslated = true; FTranslationHelper::TranslateComponent(ContentItem); } FByteBuffer* Buffer = ContentItem->RawData.Get(); Buffer->Seek(0, 0); bUnderConstruct = true; SourceSize.X = Buffer->ReadInt(); SourceSize.Y = Buffer->ReadInt(); InitSize = SourceSize; SetSize(SourceSize); if (Buffer->ReadBool()) { MinSize.X = Buffer->ReadInt(); MaxSize.X = Buffer->ReadInt(); MinSize.Y = Buffer->ReadInt(); MaxSize.Y = Buffer->ReadInt(); } if (Buffer->ReadBool()) { float f1 = Buffer->ReadFloat(); float f2 = Buffer->ReadFloat(); SetPivot(FVector2D(f1, f2), Buffer->ReadBool()); } if (Buffer->ReadBool()) { Margin.Top = Buffer->ReadInt(); Margin.Bottom = Buffer->ReadInt(); Margin.Left = Buffer->ReadInt(); Margin.Right = Buffer->ReadInt(); } EOverflowType overflow = (EOverflowType)Buffer->ReadByte(); if (overflow == EOverflowType::Scroll) { int32 savedPos = Buffer->GetPos(); Buffer->Seek(0, 7); SetupScroll(Buffer); Buffer->SetPos(savedPos); } else SetupOverflow(overflow); if (Buffer->ReadBool()) //clip soft Buffer->Skip(8); bBuildingDisplayList = true; Buffer->Seek(0, 1); int32 controllerCount = Buffer->ReadShort(); for (int32 i = 0; i < controllerCount; i++) { int32 nextPos = Buffer->ReadShort(); nextPos += Buffer->GetPos(); UGController* Controller = NewObject(this); Controllers.Add(Controller); Controller->Setup(Buffer); Buffer->SetPos(nextPos); } Buffer->Seek(0, 2); UGObject* Child; int32 childCount = Buffer->ReadShort(); for (int32 i = 0; i < childCount; i++) { int32 dataLen = Buffer->ReadShort(); int32 curPos = Buffer->GetPos(); if (ObjectPool != nullptr) Child = (*ObjectPool)[PoolIndex + i]; else { Buffer->Seek(curPos, 0); EObjectType type = (EObjectType)Buffer->ReadByte(); const FString& src = Buffer->ReadS(); const FString& pkgId = Buffer->ReadS(); TSharedPtr pii; if (!src.IsEmpty()) { UUIPackage* pkg; if (!pkgId.IsEmpty()) pkg = UUIPackage::GetPackageByID(pkgId); else pkg = ContentItem->Owner; if (pkg != nullptr) pii = pkg->GetItem(src); } if (pii.IsValid()) { Child = FUIObjectFactory::NewObject(pii, this); Child->ConstructFromResource(); } else Child = FUIObjectFactory::NewObject(type, this); } Child->bUnderConstruct = true; Child->SetupBeforeAdd(Buffer, curPos); Child->Parent = this; Children.Add(Child); Buffer->SetPos(curPos + dataLen); } Buffer->Seek(0, 3); Relations->Setup(Buffer, true); Buffer->Seek(0, 2); Buffer->Skip(2); for (int32 i = 0; i < childCount; i++) { int32 nextPos = Buffer->ReadShort(); nextPos += Buffer->GetPos(); Buffer->Seek(Buffer->GetPos(), 3); Children[i]->GetRelations()->Setup(Buffer, false); Buffer->SetPos(nextPos); } Buffer->Seek(0, 2); Buffer->Skip(2); for (int32 i = 0; i < childCount; i++) { int32 nextPos = Buffer->ReadShort(); nextPos += Buffer->GetPos(); Child = Children[i]; Child->SetupAfterAdd(Buffer, Buffer->GetPos()); Child->bUnderConstruct = false; Buffer->SetPos(nextPos); } Buffer->Seek(0, 4); Buffer->Skip(2); //customData SetOpaque(Buffer->ReadBool()); int32 maskId = Buffer->ReadShort(); if (maskId != -1) { bool inverted = Buffer->ReadBool(); //setMask(getChildAt(maskId)->displayObject(), inverted); } const FString& hitTestId = Buffer->ReadS(); int32 i1 = Buffer->ReadInt(); int32 i2 = Buffer->ReadInt(); if (!hitTestId.IsEmpty()) { TSharedPtr pii = ContentItem->Owner->GetItem(hitTestId); if (pii.IsValid() && pii->PixelHitTestData.IsValid()) SetHitArea(MakeShareable(new FPixelHitTest(pii->PixelHitTestData, i1, i2))); } else if (i1 != 0 && i2 != -1) { SetHitArea(MakeShareable(new FChildHitTest(GetChildAt(i2)))); } if (Buffer->Version >= 5) { const FString& enterSound = Buffer->ReadS(); if (!enterSound.IsEmpty()) { On(FUIEvents::AddedToStage).AddLambda([this, enterSound](UEventContext*) { GetApp()->PlaySound(enterSound, 1); }); } const FString& leaveSound = Buffer->ReadS(); if (!leaveSound.IsEmpty()) { On(FUIEvents::RemovedFromStage).AddLambda([this, leaveSound](UEventContext*) { GetApp()->PlaySound(leaveSound, 1); }); } } Buffer->Seek(0, 5); int32 transitionCount = Buffer->ReadShort(); for (int32 i = 0; i < transitionCount; i++) { int32 nextPos = Buffer->ReadShort(); nextPos += Buffer->GetPos(); UTransition* Transition = NewObject(this); Transitions.Add(Transition); Transition->Setup(Buffer); Buffer->SetPos(nextPos); } if (Transitions.Num() > 0) { On(FUIEvents::AddedToStage).AddUObject(this, &UGComponent::OnAddedToStageHandler); On(FUIEvents::RemovedFromStage).AddUObject(this, &UGComponent::OnRemovedFromStageHandler); } ApplyAllControllers(); bBuildingDisplayList = false; bUnderConstruct = false; BuildNativeDisplayList(); SetBoundsChangedFlag(); if (ContentItem->ObjectType != EObjectType::Component) ConstructExtension(Buffer); OnConstruct(); } void UGComponent::ConstructExtension(FByteBuffer* Buffer) { } void UGComponent::OnConstruct() { K2_OnConstruct(); } void UGComponent::SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos) { UGObject::SetupAfterAdd(Buffer, BeginPos); Buffer->Seek(BeginPos, 4); int32 pageController = Buffer->ReadShort(); if (pageController != -1 && ScrollPane != nullptr && ScrollPane->bPageMode) ScrollPane->PageController = Parent->GetControllerAt(pageController); int32 cnt = Buffer->ReadShort(); for (int32 i = 0; i < cnt; i++) { UGController* Controller = GetController(Buffer->ReadS()); const FString& PageID = Buffer->ReadS(); if (Controller != nullptr) Controller->SetSelectedPageID(PageID); } if (Buffer->Version >= 2) { cnt = Buffer->ReadShort(); for (int32 i = 0; i < cnt; i++) { FString Target = Buffer->ReadS(); EObjectPropID PropID = (EObjectPropID)Buffer->ReadShort(); FString Value = Buffer->ReadS(); UGObject* Obj = GetChildByPath(Target); if (Obj != nullptr) Obj->SetProp(PropID, FNVariant(Value)); } } } ================================================ FILE: Source/FairyGUI/Private/UI/GController.cpp ================================================ #include "UI/GController.h" #include "UI/GComponent.h" #include "UI/UIPackage.h" #include "Utils/ByteBuffer.h" UGController::UGController() : SelectedIndex(-1), PreviousIndex(-1) { } UGController::~UGController() { } void UGController::SetSelectedIndex(int32 Index) { SetSelectedIndex(Index, true); } void UGController::SetSelectedIndex(int32 Index, bool bTriggerEvent) { if (SelectedIndex != Index) { verifyf(Index < PageIDs.Num(), TEXT("Invalid selected index")); bChanging = true; PreviousIndex = SelectedIndex; SelectedIndex = Index; Cast(GetOuter())->ApplyController(this); if (bTriggerEvent) OnChangedEvent.Broadcast(this); bChanging = false; } } const FString& UGController::GetSelectedPage() const { if (SelectedIndex == -1) return G_EMPTY_STRING; else return PageNames[SelectedIndex]; } void UGController::SetSelectedPage(const FString& PageName) { SetSelectedPage(PageName, true); } void UGController::SetSelectedPage(const FString& PageName, bool bTriggerEvent) { int32 i = PageNames.Find(PageName); if (i == INDEX_NONE) i = 0; SetSelectedIndex(i, bTriggerEvent); } const FString& UGController::GetSelectedPageID() const { if (SelectedIndex == -1) return G_EMPTY_STRING; else return PageIDs[SelectedIndex]; } void UGController::SetSelectedPageID(const FString& PageID, bool bTriggerEvent) { int32 i = PageIDs.Find(PageID); if (i != INDEX_NONE) SetSelectedIndex(i, bTriggerEvent); } const FString& UGController::GetPreviousPage() const { if (PreviousIndex == -1) return G_EMPTY_STRING; else return PageNames[PreviousIndex]; } const FString& UGController::GetPreviousPageID() const { if (PreviousIndex == -1) return G_EMPTY_STRING; else return PageIDs[PreviousIndex]; } int32 UGController::GetPageCount() const { return PageIDs.Num(); } bool UGController::HasPage(const FString& PageName) const { return PageNames.Find(PageName) != INDEX_NONE; } int32 UGController::GetPageIndexByID(const FString& PageID) const { return PageIDs.Find(PageID) != INDEX_NONE; } const FString& UGController::GetPageNameByID(const FString& PageID) const { int32 i = PageIDs.Find(PageID); if (i != INDEX_NONE) return PageNames[i]; else return G_EMPTY_STRING; } const FString& UGController::GetPageID(int32 Index) const { return PageIDs[Index]; } void UGController::SetOppositePageID(const FString& PageID) { int32 i = PageIDs.Find(PageID); if (i > 0) SetSelectedIndex(0); else if (PageIDs.Num() > 1) SetSelectedIndex(1); } void UGController::RunActions() { if (Actions.Num() == 0) return; for (auto& it : Actions) it.Run(this, GetPreviousPageID(), GetSelectedPageID()); } void UGController::Setup(FByteBuffer* Buffer) { int32 BeginPos = Buffer->GetPos(); Buffer->Seek(BeginPos, 0); Name = Buffer->ReadS(); bAutoRadioGroupDepth = Buffer->ReadBool(); Buffer->Seek(BeginPos, 1); int32 cnt = Buffer->ReadShort(); PageIDs.SetNum(cnt); PageNames.SetNum(cnt); for (int32 i = 0; i < cnt; i++) { PageIDs[i] = Buffer->ReadS(); PageNames[i] = Buffer->ReadS(); } int32 HomePageIndex = 0; if (Buffer->Version >= 2) { int32 HomePageType = Buffer->ReadByte(); switch (HomePageType) { case 1: HomePageIndex = Buffer->ReadShort(); break; case 2: HomePageIndex = PageNames.Find(UUIPackage::GetBranch()); if (HomePageIndex == INDEX_NONE) HomePageIndex = 0; break; case 3: HomePageIndex = PageNames.Find(UUIPackage::GetVar(Buffer->ReadS())); if (HomePageIndex == INDEX_NONE) HomePageIndex = 0; break; } } Buffer->Seek(BeginPos, 2); cnt = Buffer->ReadShort(); if (cnt > 0) { for (int32 i = 0; i < cnt; i++) { int32 nextPos = Buffer->ReadShort(); nextPos += Buffer->GetPos(); FControllerAction* Action = FControllerAction::CreateAction(Buffer->ReadByte()); Action->Setup(Buffer); Actions.Add(Action); Buffer->SetPos(nextPos); } } if (PageIDs.Num() > 0) SelectedIndex = HomePageIndex; else SelectedIndex = -1; } ================================================ FILE: Source/FairyGUI/Private/UI/GGraph.cpp ================================================ #include "UI/GGraph.h" #include "Utils/ByteBuffer.h" #include "Widgets/NTexture.h" #include "Widgets/SShape.h" #include "Widgets/Mesh/RectMesh.h" #include "Widgets/Mesh/RoundedRectMesh.h" #include "Widgets/Mesh/PolygonMesh.h" #include "Widgets/Mesh/RegularPolygonMesh.h" #include "Widgets/Mesh/EllipseMesh.h" UGGraph::UGGraph() { if (!HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject)) DisplayObject = Content = SNew(SShape).GObject(this); } UGGraph::~UGGraph() { } FColor UGGraph::GetColor() const { return Content->Graphics.GetColor(); } void UGGraph::SetColor(const FColor& InColor) { Content->Graphics.SetColor(InColor); } void UGGraph::DrawRect(float LineWidth, const FColor& LineColor, const FColor& FillColor) { FRectMesh& mesh = Content->Graphics.GetMeshFactory(); mesh.LineWidth = LineWidth; mesh.LineColor = LineColor; mesh.FillColor.Reset(); mesh.Colors.Reset(); Content->Graphics.SetColor(FillColor); Content->Graphics.SetMeshDirty(); } void UGGraph::DrawRoundRect(float LineWidth, const FColor& lineColor, const FColor& FillColor, float TopLeftRadius, float TopRightRadius, float BottomLeftRadius, float BottomRightRadius) { FRoundedRectMesh& mesh = Content->Graphics.GetMeshFactory(); mesh.LineWidth = LineWidth; mesh.LineColor = lineColor; mesh.FillColor.Reset(); mesh.TopLeftRadius = TopLeftRadius; mesh.TopRightRadius = TopRightRadius; mesh.BottomLeftRadius = BottomLeftRadius; mesh.BottomRightRadius = BottomRightRadius; Content->Graphics.SetColor(FillColor); Content->Graphics.SetMeshDirty(); } void UGGraph::DrawEllipse(float LineWidth, const FColor& LineColor, const FColor& FillColor, float StartDegree, float EndDegree) { FEllipseMesh& mesh = Content->Graphics.GetMeshFactory(); mesh.LineWidth = LineWidth; mesh.LineColor = LineColor; mesh.FillColor.Reset(); mesh.CenterColor.Reset(); mesh.StartDegree = StartDegree; mesh.EndDegreee = EndDegree; Content->Graphics.SetColor(FillColor); Content->Graphics.SetMeshDirty(); } void UGGraph::DrawPolygon(float LineWidth, const FColor& LineColor, const FColor& FillColor, const TArray& Points) { FPolygonMesh& mesh = Content->Graphics.GetMeshFactory(); mesh.LineWidth = LineWidth; mesh.LineColor = LineColor; mesh.Points.Reset(); mesh.Points.Append(Points); mesh.FillColor.Reset(); mesh.Colors.Reset(); Content->Graphics.SetColor(FillColor); Content->Graphics.SetMeshDirty(); } void UGGraph::DrawRegularPolygon(int32 Sides, float LineWidth, const FColor& LineColor, const FColor& FillColor, float ShapeRotation, const TArray& Distances) { FRegularPolygonMesh& mesh = Content->Graphics.GetMeshFactory(); mesh.Sides = Sides; mesh.LineWidth = LineWidth; mesh.CenterColor.Reset(); mesh.LineColor = LineColor; mesh.FillColor.Reset(); mesh.Rotation = ShapeRotation; mesh.Distances.Reset(); mesh.Distances.Append(Distances); Content->Graphics.SetColor(FillColor); Content->Graphics.SetMeshDirty(); } void UGGraph::Clear() { Content->Graphics.SetMeshFactory(nullptr); } bool UGGraph::IsEmpty() const { return !Content->Graphics.GetMeshFactory().IsValid(); } IHitTest* UGGraph::GetHitArea() const { const TSharedPtr& Factory = Content->Graphics.GetMeshFactory(); if (Factory.IsValid()) return Factory->GetMeshHitTest(); else return nullptr; } FNVariant UGGraph::GetProp(EObjectPropID PropID) const { switch (PropID) { case EObjectPropID::Color: return FNVariant(Content->Graphics.GetColor()); default: return UGObject::GetProp(PropID); } } void UGGraph::SetProp(EObjectPropID PropID, const FNVariant& InValue) { switch (PropID) { case EObjectPropID::Color: SetColor(InValue.AsColor()); break; default: UGObject::SetProp(PropID, InValue); break; } } void UGGraph::SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos) { UGObject::SetupBeforeAdd(Buffer, BeginPos); Buffer->Seek(BeginPos, 5); int32 type = Buffer->ReadByte(); if (type != 0) { int32 lineWidth = Buffer->ReadInt(); FColor lineColor = Buffer->ReadColor(); FColor fillColor = Buffer->ReadColor(); bool roundedRect = Buffer->ReadBool(); FVector4 cornerRadius; if (roundedRect) { for (int32 i = 0; i < 4; i++) cornerRadius[i] = Buffer->ReadFloat(); } if (type == 1) { if (roundedRect) DrawRoundRect(lineWidth, lineColor, fillColor, cornerRadius.X, cornerRadius.Y, cornerRadius.Z, cornerRadius.W); else DrawRect(lineWidth, lineColor, fillColor); } else if (type == 2) DrawEllipse(lineWidth, lineColor, fillColor); else if (type == 3) { int32 cnt = Buffer->ReadShort() / 2; TArray points; for (int32 i = 0; i < cnt; i++) { float f1 = Buffer->ReadFloat(); float f2 = Buffer->ReadFloat(); points.Add(FVector2D(f1, f2)); } DrawPolygon(lineWidth, lineColor, fillColor, points); } else if (type == 4) { int32 sides = Buffer->ReadShort(); float startAngle = Buffer->ReadFloat(); int32 cnt = Buffer->ReadShort(); TArray distances; if (cnt > 0) { for (int32 i = 0; i < cnt; i++) distances.Add(Buffer->ReadFloat()); } DrawRegularPolygon(sides, lineWidth, lineColor, fillColor, startAngle, distances); } } } ================================================ FILE: Source/FairyGUI/Private/UI/GGroup.cpp ================================================ #include "UI/GGroup.h" #include "UI/GComponent.h" #include "Utils/ByteBuffer.h" #include "Widgets/SDisplayObject.h" UGGroup::UGGroup() : MainGridIndex(-1), MainGridMinSize(10), MainChildIndex(-1) { DisplayObject = SNew(SDisplayObject).GObject(this);; DisplayObject->SetInteractable(false); } UGGroup::~UGGroup() { } void UGGroup::SetLayout(EGroupLayoutType InLayout) { if (Layout != InLayout) { Layout = InLayout; SetBoundsChangedFlag(true); } } void UGGroup::SetColumnGap(int32 InColumnGap) { if (ColumnGap != InColumnGap) { ColumnGap = InColumnGap; SetBoundsChangedFlag(); } } void UGGroup::SetLineGap(int32 InLineGap) { if (LineGap != InLineGap) { LineGap = InLineGap; SetBoundsChangedFlag(); } } void UGGroup::SetExcludeInvisibles(bool Flag) { if (bExcludeInvisibles != Flag) { bExcludeInvisibles = Flag; SetBoundsChangedFlag(); } } void UGGroup::SetAutoSizeDisabled(bool Flag) { if (bAutoSizeDisabled != Flag) { bAutoSizeDisabled = Flag; SetBoundsChangedFlag(); } } void UGGroup::SetMainGridIndex(int32 InIndex) { if (MainGridIndex != InIndex) { MainGridIndex = InIndex; SetBoundsChangedFlag(); } } void UGGroup::SetMainGridMinSize(int32 InSize) { if (MainGridMinSize != InSize) { MainGridMinSize = InSize; SetBoundsChangedFlag(); } } void UGGroup::SetBoundsChangedFlag(bool bPositionChangedOnly) { if (Updating == 0 && Parent.IsValid()) { if (!bPositionChangedOnly) bPercentReady = false; if (!bBoundsChanged) { bBoundsChanged = true; if (Layout != EGroupLayoutType::None) { GetApp()->DelayCall(UpdateBoundsTimerHandle, this, &UGGroup::EnsureBoundsCorrect); } } } } void UGGroup::EnsureBoundsCorrect() { if (!Parent.IsValid() || !bBoundsChanged) return; bBoundsChanged = false; if (bAutoSizeDisabled) ResizeChildren(FVector2D::ZeroVector); else { HandleLayout(); UpdateBounds(); } } void UGGroup::UpdateBounds() { int32 cnt = Parent->NumChildren(); int32 i; UGObject* child; float ax = FLT_MAX, ay = FLT_MAX; float ar = FLT_MIN, ab = FLT_MIN; float tmp; bool empty = true; for (i = 0; i < cnt; i++) { child = Parent->GetChildAt(i); if (child->GetGroup() != this || (bExcludeInvisibles && !child->InternalVisible3())) continue; tmp = child->GetX(); if (tmp < ax) ax = tmp; tmp = child->GetY(); if (tmp < ay) ay = tmp; tmp = child->GetX() + child->GetWidth(); if (tmp > ar) ar = tmp; tmp = child->GetY() + child->GetHeight(); if (tmp > ab) ab = tmp; empty = false; } float w; float h; if (!empty) { Updating |= 1; SetPosition(FVector2D(ax, ay)); Updating &= 2; w = ar - ax; h = ab - ay; } else w = h = 0; if ((Updating & 2) == 0) { Updating |= 2; SetSize(FVector2D(w, h)); Updating &= 1; } else { Updating &= 1; ResizeChildren(FVector2D(GetWidth() - w, GetHeight() - h)); } } void UGGroup::HandleLayout() { Updating |= 1; if (Layout == EGroupLayoutType::Horizontal) { float curX = GetX(); int32 cnt = Parent->NumChildren(); for (int32 i = 0; i < cnt; i++) { UGObject* child = Parent->GetChildAt(i); if (child->GetGroup() != this) continue; if (bExcludeInvisibles && !child->InternalVisible3()) continue; child->SetXMin(curX); if (child->GetWidth() != 0) curX += child->GetWidth() + ColumnGap; } } else if (Layout == EGroupLayoutType::Vertical) { float curY = GetY(); int32 cnt = Parent->NumChildren(); for (int32 i = 0; i < cnt; i++) { UGObject* child = Parent->GetChildAt(i); if (child->GetGroup() != this) continue; if (bExcludeInvisibles && !child->InternalVisible3()) continue; child->SetYMin(curY); if (child->GetHeight() != 0) curY += child->GetHeight() + LineGap; } } Updating &= 2; } void UGGroup::MoveChildren(const FVector2D& Delta) { if ((Updating & 1) != 0 || !Parent.IsValid()) return; Updating |= 1; int32 cnt = Parent->NumChildren(); for (int32 i = 0; i < cnt; i++) { UGObject* child = Parent->GetChildAt(i); if (child->GetGroup() == this) { child->SetPosition(child->GetPosition() + Delta); } } Updating &= 2; } void UGGroup::ResizeChildren(const FVector2D& Delta) { if (Layout == EGroupLayoutType::None || (Updating & 2) != 0 || !Parent.IsValid()) return; Updating |= 2; if (bBoundsChanged) { bBoundsChanged = false; if (!bAutoSizeDisabled) { UpdateBounds(); return; } } int32 cnt = Parent->NumChildren(); if (!bPercentReady) { bPercentReady = true; NumChildren = 0; TotalSize = 0; MainChildIndex = -1; int32 j = 0; for (int32 i = 0; i < cnt; i++) { UGObject* child = Parent->GetChildAt(i); if (child->GetGroup() != this) continue; if (!bExcludeInvisibles || child->InternalVisible3()) { if (j == MainGridIndex) MainChildIndex = i; NumChildren++; if (Layout == EGroupLayoutType::Horizontal) TotalSize += child->GetWidth(); else TotalSize += child->GetHeight(); } j++; } if (MainChildIndex != -1) { if (Layout == EGroupLayoutType::Horizontal) { UGObject* child = Parent->GetChildAt(MainChildIndex); TotalSize += MainGridMinSize - child->GetWidth(); child->SizePercentInGroup = MainGridMinSize / TotalSize; } else { UGObject* child = Parent->GetChildAt(MainChildIndex); TotalSize += MainGridMinSize - child->GetHeight(); child->SizePercentInGroup = MainGridMinSize / TotalSize; } } for (int32 i = 0; i < cnt; i++) { UGObject* child = Parent->GetChildAt(i); if (child->GetGroup() != this) continue; if (i == MainChildIndex) continue; if (TotalSize > 0) child->SizePercentInGroup = (Layout == EGroupLayoutType::Horizontal ? child->GetWidth() : child->GetHeight()) / TotalSize; else child->SizePercentInGroup = 0; } } float remainSize = 0; float remainPercent = 1; bool priorHandled = false; if (Layout == EGroupLayoutType::Horizontal) { remainSize = GetWidth() - (NumChildren - 1) * ColumnGap; if (MainChildIndex != -1 && remainSize >= TotalSize) { UGObject* child = Parent->GetChildAt(MainChildIndex); child->SetSize(FVector2D(remainSize - (TotalSize - MainGridMinSize), child->RawSize.Y + Delta.Y), true); remainSize -= child->GetWidth(); remainPercent -= child->SizePercentInGroup; priorHandled = true; } float curX = GetX(); for (int32 i = 0; i < cnt; i++) { UGObject* child = Parent->GetChildAt(i); if (child->GetGroup() != this) continue; if (bExcludeInvisibles && !child->InternalVisible3()) { child->SetSize(FVector2D(child->RawSize.X, child->RawSize.Y + Delta.Y), true); continue; } if (!priorHandled || i != MainChildIndex) { child->SetSize(FVector2D(FMath::RoundToInt(child->SizePercentInGroup / remainPercent * remainSize), child->RawSize.Y + Delta.Y), true); remainPercent -= child->SizePercentInGroup; remainSize -= child->GetWidth(); } child->SetXMin(curX); if (child->GetWidth() != 0) curX += child->GetWidth() + ColumnGap; } } else { remainSize = GetHeight() - (NumChildren - 1) * LineGap; if (MainChildIndex != -1 && remainSize >= TotalSize) { UGObject* child = Parent->GetChildAt(MainChildIndex); child->SetSize(FVector2D(child->RawSize.X + Delta.X, remainSize - (TotalSize - MainGridMinSize)), true); remainSize -= child->GetHeight(); remainPercent -= child->SizePercentInGroup; priorHandled = true; } float curY = GetY(); for (int32 i = 0; i < cnt; i++) { UGObject* child = Parent->GetChildAt(i); if (child->GetGroup() != this) continue; if (bExcludeInvisibles && !child->InternalVisible3()) { child->SetSize(FVector2D(child->RawSize.X + Delta.X, child->RawSize.Y), true); continue; } if (!priorHandled || i != MainChildIndex) { child->SetSize(FVector2D(child->RawSize.X + Delta.X, FMath::RoundToInt(child->SizePercentInGroup / remainPercent * remainSize)), true); remainPercent -= child->SizePercentInGroup; remainSize -= child->GetHeight(); } child->SetYMin(curY); if (child->GetHeight() != 0) curY += child->GetHeight() + LineGap; } } Updating &= 1; } void UGGroup::HandleAlphaChanged() { UGObject::HandleAlphaChanged(); if (bUnderConstruct) return; int32 cnt = Parent->NumChildren(); for (int32 i = 0; i < cnt; i++) { UGObject* child = Parent->GetChildAt(i); if (child->GetGroup() == this) child->SetAlpha(Alpha); } } void UGGroup::HandleVisibleChanged() { if (!Parent.IsValid()) return; int32 cnt = Parent->NumChildren(); for (int32 i = 0; i < cnt; i++) { UGObject* child = Parent->GetChildAt(i); if (child->GetGroup() == this) child->HandleVisibleChanged(); } } void UGGroup::SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos) { UGObject::SetupBeforeAdd(Buffer, BeginPos); Buffer->Seek(BeginPos, 5); Layout = (EGroupLayoutType)Buffer->ReadByte(); LineGap = Buffer->ReadInt(); ColumnGap = Buffer->ReadInt(); if (Buffer->Version >= 2) { bExcludeInvisibles = Buffer->ReadBool(); bAutoSizeDisabled = Buffer->ReadBool(); MainGridIndex = Buffer->ReadShort(); } } void UGGroup::SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos) { UGObject::SetupAfterAdd(Buffer, BeginPos); if (!bVisible) HandleVisibleChanged(); } ================================================ FILE: Source/FairyGUI/Private/UI/GImage.cpp ================================================ #include "UI/GImage.h" #include "Utils/ByteBuffer.h" #include "Widgets/NTexture.h" #include "Widgets/SFImage.h" UGImage::UGImage() { if (!HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject)) { DisplayObject = Content = SNew(SFImage).GObject(this); DisplayObject->SetInteractable(false); } } UGImage::~UGImage() { } EFlipType UGImage::GetFlip() const { return Content->Graphics.GetFlip(); } void UGImage::SetFlip(EFlipType InFlip) { Content->Graphics.SetFlip(InFlip); } FColor UGImage::GetColor() const { return Content->Graphics.GetColor(); } void UGImage::SetColor(const FColor& InColor) { Content->Graphics.SetColor(InColor); } EFillMethod UGImage::GetFillMethod() const { return Content->GetFillMethod(); } void UGImage::SetFillMethod(EFillMethod Method) { Content->SetFillMethod(Method); } int32 UGImage::GetFillOrigin() const { return Content->GetFillOrigin(); } void UGImage::SetFillOrigin(int32 Origin) { Content->SetFillOrigin(Origin); } bool UGImage::IsFillClockwise() const { return Content->IsFillClockwise(); } void UGImage::SetFillClockwise(bool bClockwise) { Content->SetFillClockwise(bClockwise); } float UGImage::GetFillAmount() const { return Content->GetFillAmount(); } void UGImage::SetFillAmount(float Amount) { Content->SetFillAmount(Amount); } FNVariant UGImage::GetProp(EObjectPropID PropID) const { switch (PropID) { case EObjectPropID::Color: return FNVariant(GetColor()); default: return UGObject::GetProp(PropID); } } void UGImage::SetProp(EObjectPropID PropID, const FNVariant& InValue) { switch (PropID) { case EObjectPropID::Color: SetColor(InValue.AsColor()); break; default: UGObject::SetProp(PropID, InValue); break; } } void UGImage::ConstructFromResource() { TSharedPtr ContentItem = PackageItem->GetBranch(); InitSize = SourceSize = ContentItem->Size; ContentItem = ContentItem->GetHighResolution(); ContentItem->Load(); Content->SetTexture(ContentItem->Texture); if (ContentItem->Scale9Grid.IsSet()) Content->SetScale9Grid(ContentItem->Scale9Grid); else if (ContentItem->bScaleByTile) Content->SetScaleByTile(true); SetSize(SourceSize); } void UGImage::SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos) { UGObject::SetupBeforeAdd(Buffer, BeginPos); Buffer->Seek(BeginPos, 5); if (Buffer->ReadBool()) SetColor(Buffer->ReadColor()); SetFlip((EFlipType)Buffer->ReadByte()); int32 method = Buffer->ReadByte(); if (method != 0) { Content->SetFillMethod((EFillMethod)method); Content->SetFillOrigin(Buffer->ReadByte()); Content->SetFillClockwise(Buffer->ReadBool()); Content->SetFillAmount(Buffer->ReadFloat()); } } ================================================ FILE: Source/FairyGUI/Private/UI/GLabel.cpp ================================================ #include "UI/GLabel.h" #include "UI/GTextInput.h" #include "UI/GButton.h" #include "UI/GTextField.h" #include "Utils/ByteBuffer.h" UGLabel::UGLabel() { } UGLabel::~UGLabel() { } const FString& UGLabel::GetText() const { if (TitleObject != nullptr) return TitleObject->GetText(); else return G_EMPTY_STRING; } void UGLabel::SetText(const FString& InText) { if (TitleObject != nullptr) TitleObject->SetText(InText); UpdateGear(6); } const FString& UGLabel::GetIcon() const { if (IconObject != nullptr) return IconObject->GetIcon(); else return G_EMPTY_STRING; } void UGLabel::SetIcon(const FString & InIcon) { if (IconObject != nullptr) IconObject->SetIcon(InIcon); UpdateGear(7); } FColor UGLabel::GetTitleColor() const { UGTextField* TextField = GetTextField(); if (TextField) return TextField->GetTextFormat().Color; else return FColor::Black; } void UGLabel::SetTitleColor(const FColor& InColor) { UGTextField* TextField = GetTextField(); if (TextField) { TextField->GetTextFormat().Color = InColor; TextField->ApplyFormat(); } } int32 UGLabel::GetTitleFontSize() const { UGTextField* TextField = GetTextField(); if (TextField) return TextField->GetTextFormat().Size; else return 0; } void UGLabel::SetTitleFontSize(int32 InFontSize) { UGTextField* TextField = GetTextField(); if (TextField) { TextField->GetTextFormat().Size = InFontSize; TextField->ApplyFormat(); } } UGTextField * UGLabel::GetTextField() const { if (TitleObject->IsA()) return Cast(TitleObject); else if (TitleObject->IsA()) return Cast(TitleObject)->GetTextField(); else if (TitleObject->IsA()) return Cast(TitleObject)->GetTextField(); else return nullptr; } FNVariant UGLabel::GetProp(EObjectPropID PropID) const { switch (PropID) { case EObjectPropID::Color: return FNVariant(GetTitleColor()); case EObjectPropID::OutlineColor: { UGTextField* TextField = GetTextField(); if (TextField != nullptr) return FNVariant(TextField->GetTextFormat().OutlineColor); else return FNVariant(FColor::Black); } case EObjectPropID::FontSize: return FNVariant(GetTitleFontSize()); default: return UGComponent::GetProp(PropID); } } void UGLabel::SetProp(EObjectPropID PropID, const FNVariant& InValue) { switch (PropID) { case EObjectPropID::Color: SetTitleColor(InValue.AsColor()); break; case EObjectPropID::OutlineColor: { UGTextField* TextField = GetTextField(); if (TextField != nullptr) { TextField->GetTextFormat().OutlineColor = InValue.AsColor(); TextField->ApplyFormat(); } break; } case EObjectPropID::FontSize: SetTitleFontSize(InValue.AsInt()); break; default: UGComponent::SetProp(PropID, InValue); break; } } void UGLabel::ConstructExtension(FByteBuffer* Buffer) { TitleObject = GetChild("title"); IconObject = GetChild("icon"); } void UGLabel::SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos) { UGComponent::SetupAfterAdd(Buffer, BeginPos); if (!Buffer->Seek(BeginPos, 6)) return; if ((EObjectType)Buffer->ReadByte() != PackageItem->ObjectType) return; const FString* str; if ((str = Buffer->ReadSP()) != nullptr) SetText(*str); if ((str = Buffer->ReadSP()) != nullptr) SetIcon(*str); if (Buffer->ReadBool()) SetTitleColor(Buffer->ReadColor()); int32 iv = Buffer->ReadInt(); if (iv != 0) SetTitleFontSize(iv); if (Buffer->ReadBool()) { UGTextInput* input = Cast(GetTextField()); if (input) { if ((str = Buffer->ReadSP()) != nullptr) input->SetPrompt(*str); if ((str = Buffer->ReadSP()) != nullptr) input->SetRestrict(*str); iv = Buffer->ReadInt(); if (iv != 0) input->SetMaxLength(iv); iv = Buffer->ReadInt(); if (iv != 0) input->SetKeyboardType(iv); if (Buffer->ReadBool()) input->SetPassword(true); } else Buffer->Skip(13); } } ================================================ FILE: Source/FairyGUI/Private/UI/GList.cpp ================================================ #include "UI/GList.h" #include "UI/GButton.h" #include "UI/GObjectPool.h" #include "UI/GController.h" #include "UI/GScrollBar.h" #include "UI/UIPackage.h" #include "Utils/ByteBuffer.h" #include "Widgets/SContainer.h" #include "FairyApplication.h" UGList::FItemInfo::FItemInfo() : Obj(nullptr), UpdateFlag(0), bSelected(false) { } UGList::UGList() : bScrollItemToViewOnClick(true), bAutoResizeItem(true), LastSelectedIndex(-1), FirstIndex(-1) { bTrackBounds = true; SetOpaque(true); Pool = new FGObjectPool(); } UGList::~UGList() { delete Pool; SelectionController = nullptr; bScrollItemToViewOnClick = false; } void UGList::SetDefaultItem(const FString& InDefaultItem) { DefaultItem = UUIPackage::NormalizeURL(InDefaultItem); } void UGList::SetLayout(EListLayoutType InLayout) { if (Layout != InLayout) { Layout = InLayout; SetBoundsChangedFlag(); if (bVirtual) SetVirtualListChangedFlag(true); } } void UGList::SetLineCount(int32 InLineCount) { if (LineCount != InLineCount) { LineCount = InLineCount; if (Layout == EListLayoutType::FlowVertical || Layout == EListLayoutType::Pagination) { SetBoundsChangedFlag(); if (bVirtual) SetVirtualListChangedFlag(true); } } } void UGList::SetColumnCount(int32 InColumnCount) { if (ColumnCount != InColumnCount) { ColumnCount = InColumnCount; if (Layout == EListLayoutType::FlowHorizontal || Layout == EListLayoutType::Pagination) { SetBoundsChangedFlag(); if (bVirtual) SetVirtualListChangedFlag(true); } } } void UGList::SetLineGap(int32 InLineGap) { if (LineGap != InLineGap) { LineGap = InLineGap; SetBoundsChangedFlag(); if (bVirtual) SetVirtualListChangedFlag(true); } } void UGList::SetColumnGap(int32 InColumnGap) { if (ColumnGap != InColumnGap) { ColumnGap = InColumnGap; SetBoundsChangedFlag(); if (bVirtual) SetVirtualListChangedFlag(true); } } void UGList::SetAlign(EAlignType InAlign) { if (Align != InAlign) { Align = InAlign; SetBoundsChangedFlag(); if (bVirtual) SetVirtualListChangedFlag(true); } } void UGList::SetVerticalAlign(EVerticalAlignType InVerticalAlign) { if (VerticalAlign != InVerticalAlign) { VerticalAlign = InVerticalAlign; SetBoundsChangedFlag(); if (bVirtual) SetVirtualListChangedFlag(true); } } void UGList::SetAutoResizeItem(bool bFlag) { if (bAutoResizeItem != bFlag) { bAutoResizeItem = bFlag; SetBoundsChangedFlag(); if (bVirtual) SetVirtualListChangedFlag(true); } } UGObject* UGList::GetFromPool() { return GetFromPool(G_EMPTY_STRING); } UGObject* UGList::GetFromPool(const FString& URL) { UGObject* ret; if (URL.Len() == 0) ret = Pool->GetObject(DefaultItem, this); else ret = Pool->GetObject(URL, this); if (ret != nullptr) ret->SetVisible(true); return ret; } void UGList::ReturnToPool(UGObject* Obj) { Pool->ReturnObject(Obj); } UGObject* UGList::AddItemFromPool(const FString& URL) { UGObject* Obj = GetFromPool(URL); return AddChild(Obj); } UGObject* UGList::AddChildAt(UGObject* Child, int32 Index) { UGComponent::AddChildAt(Child, Index); if (Child->IsA()) { UGButton* Button = (UGButton*)Child; Button->SetSelected(false); Button->bChangeStateOnClick = false; } Child->OnClick.AddUniqueDynamic(this, &UGList::OnClickItemHandler); return Child; } void UGList::RemoveChildAt(int32 Index) { UGObject* Child = Children[Index]; Child->OnClick.RemoveDynamic(this, &UGList::OnClickItemHandler); UGComponent::RemoveChildAt(Index); } void UGList::RemoveChildToPoolAt(int32 Index) { ReturnToPool(GetChildAt(Index)); RemoveChildAt(Index); } void UGList::RemoveChildToPool(UGObject* Child) { ReturnToPool(Child); RemoveChild(Child); } void UGList::RemoveChildrenToPool(int32 BeginIndex, int32 EndIndex) { if (EndIndex < 0 || EndIndex >= Children.Num()) EndIndex = Children.Num() - 1; for (int32 i = BeginIndex; i <= EndIndex; ++i) RemoveChildToPoolAt(BeginIndex); } int32 UGList::GetSelectedIndex() const { if (bVirtual) { int32 cnt = RealNumItems; for (int32 i = 0; i < cnt; i++) { const FItemInfo& ii = VirtualItems[i]; if ((Cast(ii.Obj) && ((UGButton*)ii.Obj)->IsSelected()) || (ii.Obj == nullptr && ii.bSelected)) { if (bLoop) return i % NumItems; else return i; } } } else { int32 cnt = Children.Num(); for (int32 i = 0; i < cnt; i++) { UGButton* Obj = Cast(Children[i]); if (Obj != nullptr && Obj->IsSelected()) return i; } } return -1; } void UGList::SetSelectedIndex(int32 Index) { if (Index >= 0 && Index < GetNumItems()) { if (SelectionMode != EListSelectionMode::Single) ClearSelection(); AddSelection(Index, false); } else ClearSelection(); } void UGList::SetSelectionController(UGController* InController) { SelectionController = InController; } void UGList::GetSelection(TArray& OutIndice) const { OutIndice.Reset(); if (bVirtual) { int32 cnt = RealNumItems; for (int32 i = 0; i < cnt; i++) { const FItemInfo& ii = VirtualItems[i]; if ((Cast(ii.Obj) && ((UGButton*)ii.Obj)->IsSelected()) || (ii.Obj == nullptr && ii.bSelected)) { int32 j = i; if (bLoop) { j = i % NumItems; if (OutIndice.Contains(j)) continue; } OutIndice.Add(j); } } } else { int32 cnt = Children.Num(); for (int32 i = 0; i < cnt; i++) { UGButton* Obj = Cast(Children[i]); if (Obj != nullptr && Obj->IsSelected()) OutIndice.Add(i); } } } void UGList::AddSelection(int32 Index, bool bScrollItToView) { if (SelectionMode == EListSelectionMode::None) return; CheckVirtualList(); if (SelectionMode == EListSelectionMode::Single) ClearSelection(); if (bScrollItToView) ScrollToView(Index); LastSelectedIndex = Index; UGButton* Obj = nullptr; if (bVirtual) { FItemInfo& ii = VirtualItems[Index]; if (ii.Obj != nullptr) Obj = ii.Obj->As(); ii.bSelected = true; } else Obj = GetChildAt(Index)->As(); if (Obj != nullptr && !Obj->IsSelected()) { Obj->SetSelected(true); UpdateSelectionController(Index); } } void UGList::RemoveSelection(int32 Index) { if (SelectionMode == EListSelectionMode::None) return; UGButton* Obj = nullptr; if (bVirtual) { FItemInfo& ii = VirtualItems[Index]; if (ii.Obj != nullptr) Obj = ii.Obj->As(); ii.bSelected = false; } else Obj = GetChildAt(Index)->As(); if (Obj != nullptr) Obj->SetSelected(false); } void UGList::ClearSelection() { if (bVirtual) { int32 cnt = RealNumItems; for (int32 i = 0; i < cnt; i++) { FItemInfo& ii = VirtualItems[i]; if (Cast(ii.Obj)) ((UGButton*)ii.Obj)->SetSelected(false); ii.bSelected = false; } } else { int32 cnt = Children.Num(); for (int32 i = 0; i < cnt; i++) { UGButton* Obj = Children[i]->As(); if (Obj != nullptr) Obj->SetSelected(false); } } } void UGList::ClearSelectionExcept(UGObject* Obj) { if (bVirtual) { int32 cnt = RealNumItems; for (int32 i = 0; i < cnt; i++) { FItemInfo& ii = VirtualItems[i]; if (ii.Obj != Obj) { if (Cast(ii.Obj)) ((UGButton*)ii.Obj)->SetSelected(false); ii.bSelected = false; } } } else { int32 cnt = Children.Num(); for (int32 i = 0; i < cnt; i++) { UGButton* Child = Children[i]->As(); if (Child != nullptr && Child != Obj) Child->SetSelected(false); } } } void UGList::SelectAll() { CheckVirtualList(); int32 last = -1; if (bVirtual) { int32 cnt = RealNumItems; for (int32 i = 0; i < cnt; i++) { FItemInfo& ii = VirtualItems[i]; if (Cast(ii.Obj) && !((UGButton*)ii.Obj)->IsSelected()) { ((UGButton*)ii.Obj)->SetSelected(true); last = i; } ii.bSelected = true; } } else { int32 cnt = Children.Num(); for (int32 i = 0; i < cnt; i++) { UGButton* Obj = Children[i]->As(); if (Obj != nullptr && !Obj->IsSelected()) { Obj->SetSelected(true); last = i; } } } if (last != -1) UpdateSelectionController(last); } void UGList::SelectReverse() { CheckVirtualList(); int32 last = -1; if (bVirtual) { int32 cnt = RealNumItems; for (int32 i = 0; i < cnt; i++) { FItemInfo& ii = VirtualItems[i]; if (Cast(ii.Obj)) { ((UGButton*)ii.Obj)->SetSelected(!((UGButton*)ii.Obj)->IsSelected()); if (((UGButton*)ii.Obj)->IsSelected()) last = i; } ii.bSelected = !ii.bSelected; } } else { int32 cnt = Children.Num(); for (int32 i = 0; i < cnt; i++) { UGButton* Obj = Children[i]->As(); if (Obj != nullptr) { Obj->SetSelected(!Obj->IsSelected()); if (Obj->IsSelected()) last = i; } } } if (last != -1) UpdateSelectionController(last); } void UGList::HandleArrowKey(int32 Direction) { int32 index = GetSelectedIndex(); if (index == -1) return; switch (Direction) { case 1: //up if (Layout == EListLayoutType::SingleColumn || Layout == EListLayoutType::FlowVertical) { index--; if (index >= 0) { ClearSelection(); AddSelection(index, true); } } else if (Layout == EListLayoutType::FlowHorizontal || Layout == EListLayoutType::Pagination) { UGObject* current = Children[index]; int32 k = 0; int32 i; for (i = index - 1; i >= 0; i--) { UGObject* obj = Children[i]; if (obj->GetY() != current->GetY()) { current = obj; break; } k++; } for (; i >= 0; i--) { UGObject* obj = Children[i]; if (obj->GetY() != current->GetY()) { ClearSelection(); AddSelection(i + k + 1, true); break; } } } break; case 3: //right if (Layout == EListLayoutType::SingleRow || Layout == EListLayoutType::FlowHorizontal || Layout == EListLayoutType::Pagination) { index++; if (index < Children.Num()) { ClearSelection(); AddSelection(index, true); } } else if (Layout == EListLayoutType::FlowVertical) { UGObject* current = Children[index]; int32 k = 0; int32 cnt = Children.Num(); int32 i; for (i = index + 1; i < cnt; i++) { UGObject* obj = Children[i]; if (obj->GetX() != current->GetX()) { current = obj; break; } k++; } for (; i < cnt; i++) { UGObject* obj = Children[i]; if (obj->GetX() != current->GetX()) { ClearSelection(); AddSelection(i - k - 1, true); break; } } } break; case 5: //down if (Layout == EListLayoutType::SingleColumn || Layout == EListLayoutType::FlowVertical) { index++; if (index < Children.Num()) { ClearSelection(); AddSelection(index, true); } } else if (Layout == EListLayoutType::FlowHorizontal || Layout == EListLayoutType::Pagination) { UGObject* current = Children[index]; int32 k = 0; int32 cnt = Children.Num(); int32 i; for (i = index + 1; i < cnt; i++) { UGObject* obj = Children[i]; if (obj->GetY() != current->GetY()) { current = obj; break; } k++; } for (; i < cnt; i++) { UGObject* obj = Children[i]; if (obj->GetY() != current->GetY()) { ClearSelection(); AddSelection(i - k - 1, true); break; } } } break; case 7: //left if (Layout == EListLayoutType::SingleRow || Layout == EListLayoutType::FlowHorizontal || Layout == EListLayoutType::Pagination) { index--; if (index >= 0) { ClearSelection(); AddSelection(index, true); } } else if (Layout == EListLayoutType::FlowVertical) { UGObject* current = Children[index]; int32 k = 0; int32 i; for (i = index - 1; i >= 0; i--) { UGObject* obj = Children[i]; if (obj->GetX() != current->GetX()) { current = obj; break; } k++; } for (; i >= 0; i--) { UGObject* obj = Children[i]; if (obj->GetX() != current->GetX()) { ClearSelection(); AddSelection(i + k + 1, true); break; } } } break; } } void UGList::OnClickItemHandler(UEventContext* Context) { UGObject* Obj = Context->GetSender(); if (Obj->IsA() && SelectionMode != EListSelectionMode::None) SetSelectionOnEvent(Obj, Context); if (ScrollPane != nullptr && bScrollItemToViewOnClick) ScrollPane->ScrollToView(Obj, true); DispatchItemEvent(Obj, Context); } void UGList::DispatchItemEvent(UGObject* Obj, UEventContext* Context) { DispatchEvent(FUIEvents::ClickItem, FNVariant(Obj)); } void UGList::SetSelectionOnEvent(UGObject* Obj, UEventContext* Context) { bool bDontChangeLastIndex = false; UGButton* Button = Cast(Obj); int32 Index = ChildIndexToItemIndex(GetChildIndex(Obj)); if (SelectionMode == EListSelectionMode::Single) { if (!Button->IsSelected()) { ClearSelectionExcept(Button); Button->SetSelected(true); } } else { if (Context->GetPointerEvent().IsShiftDown()) { if (!Button->IsSelected()) { if (LastSelectedIndex != -1) { int32 min = FMath::Min(LastSelectedIndex, Index); int32 max = FMath::Max(LastSelectedIndex, Index); max = FMath::Min(max, GetNumItems() - 1); if (bVirtual) { for (int32 i = min; i <= max; i++) { FItemInfo& ii = VirtualItems[i]; if (ii.Obj != nullptr && ii.Obj->IsA()) Cast(ii.Obj)->SetSelected(true); ii.bSelected = true; } } else { for (int32 i = min; i <= max; i++) { UGButton* Child = GetChildAt(i)->As(); if (Child != nullptr && !Child->IsSelected()) Child->SetSelected(true); } } bDontChangeLastIndex = true; } else { Button->SetSelected(true); } } } else if (Context->GetPointerEvent().IsControlDown() || SelectionMode == EListSelectionMode::MultipleSingleclick) { Button->SetSelected(!Button->IsSelected()); } else { if (!Button->IsSelected()) { ClearSelectionExcept(Button); Button->SetSelected(true); } else if (Context->GetMouseButton() == EKeys::LeftMouseButton) ClearSelectionExcept(Button); } } if (!bDontChangeLastIndex) LastSelectedIndex = Index; if (Button->IsSelected()) UpdateSelectionController(Index); } void UGList::ResizeToFit(int32 ItemCount, int32 InMinSize) { EnsureBoundsCorrect(); int32 curCount = GetNumItems(); if (ItemCount > curCount) ItemCount = curCount; if (bVirtual) { int32 lineCount = FMath::CeilToInt((float)ItemCount / CurLineItemCount); if (Layout == EListLayoutType::SingleColumn || Layout == EListLayoutType::FlowHorizontal) SetViewHeight(lineCount * ItemSize.Y + FMath::Max(0, lineCount - 1) * LineGap); else SetViewWidth(lineCount * ItemSize.X + FMath::Max(0, lineCount - 1) * ColumnGap); } else if (ItemCount == 0) { if (Layout == EListLayoutType::SingleColumn || Layout == EListLayoutType::FlowHorizontal) SetViewHeight(InMinSize); else SetViewWidth(InMinSize); } else { int32 i = ItemCount - 1; UGObject* obj = nullptr; while (i >= 0) { obj = GetChildAt(i); if (!bFoldInvisibleItems || obj->IsVisible()) break; i--; } if (i < 0) { if (Layout == EListLayoutType::SingleColumn || Layout == EListLayoutType::FlowHorizontal) SetViewHeight(InMinSize); else SetViewWidth(InMinSize); } else { float size; if (Layout == EListLayoutType::SingleColumn || Layout == EListLayoutType::FlowHorizontal) { size = obj->GetY() + obj->GetHeight(); if (size < InMinSize) size = InMinSize; SetViewHeight(size); } else { size = obj->GetX() + obj->GetWidth(); if (size < InMinSize) size = InMinSize; SetViewWidth(size); } } } } int32 UGList::GetFirstChildInView() const { return ChildIndexToItemIndex(UGComponent::GetFirstChildInView()); } void UGList::HandleSizeChanged() { UGComponent::HandleSizeChanged(); SetBoundsChangedFlag(); if (bVirtual) SetVirtualListChangedFlag(true); } void UGList::HandleControllerChanged(UGController* Controller) { UGComponent::HandleControllerChanged(Controller); if (SelectionController == Controller) SetSelectedIndex(Controller->GetSelectedIndex()); } void UGList::UpdateSelectionController(int32 Index) { if (SelectionController != nullptr && !SelectionController->bChanging && Index < SelectionController->GetPageCount()) { UGController* Controller = SelectionController; SelectionController = nullptr; Controller->SetSelectedIndex(Index); SelectionController = Controller; } } void UGList::ScrollToView(int32 Index, bool bAnimation, bool bSetFirst) { if (bVirtual) { if (NumItems == 0) return; CheckVirtualList(); verifyf(Index >= 0 && Index < VirtualItems.Num(), TEXT("Invalid child index")); if (bLoop) Index = FMath::FloorToFloat(FirstIndex / NumItems) * NumItems + Index; FBox2D rect; FItemInfo& ii = VirtualItems[Index]; if (Layout == EListLayoutType::SingleColumn || Layout == EListLayoutType::FlowHorizontal) { float pos = 0; for (int32 i = CurLineItemCount - 1; i < Index; i += CurLineItemCount) pos += VirtualItems[i].Size.Y + LineGap; rect.Min.Set(0, pos); rect.Max = rect.Min + FVector2D(ItemSize.X, ii.Size.Y); } else if (Layout == EListLayoutType::SingleRow || Layout == EListLayoutType::FlowVertical) { float pos = 0; for (int32 i = CurLineItemCount - 1; i < Index; i += CurLineItemCount) pos += VirtualItems[i].Size.X + ColumnGap; rect.Min.Set(pos, 0); rect.Max = rect.Min + FVector2D(ii.Size.X, ItemSize.Y); } else { int32 page = Index / (CurLineItemCount * CurLineItemCount2); rect.Min.Set(page * GetViewWidth() + (Index % CurLineItemCount) * (ii.Size.X + ColumnGap), (Index / CurLineItemCount) % CurLineItemCount2 * (ii.Size.Y + LineGap)); rect.Max = rect.Min + ii.Size; } if (ScrollPane != nullptr) ScrollPane->ScrollToView(rect, bAnimation, bSetFirst); else if (Parent.IsValid() && Parent->GetScrollPane() != nullptr) { FBox2D rect2 = LocalToGlobalRect(rect); rect2 = Parent->GlobalToLocalRect(rect2); Parent->GetScrollPane()->ScrollToView(rect2, bAnimation, bSetFirst); } } else { UGObject* obj = GetChildAt(Index); if (ScrollPane != nullptr) ScrollPane->ScrollToView(obj, bAnimation, bSetFirst); else if (Parent.IsValid() && Parent->GetScrollPane() != nullptr) Parent->GetScrollPane()->ScrollToView(obj, bAnimation, bSetFirst); } } int32 UGList::ChildIndexToItemIndex(int32 Index) const { if (!bVirtual) return Index; if (Layout == EListLayoutType::Pagination) { for (int32 i = FirstIndex; i < RealNumItems; i++) { if (VirtualItems[i].Obj != nullptr) { Index--; if (Index < 0) return i; } } return Index; } else { Index += FirstIndex; if (bLoop && NumItems > 0) Index = Index % NumItems; return Index; } } int32 UGList::ItemIndexToChildIndex(int32 Index) const { if (!bVirtual) return Index; if (Layout == EListLayoutType::Pagination) { return GetChildIndex(VirtualItems[Index].Obj); } else { if (bLoop && NumItems > 0) { int32 j = FirstIndex % NumItems; if (Index >= j) Index = Index - j; else Index = NumItems - j + Index; } else Index -= FirstIndex; return Index; } } void UGList::SetVirtual() { SetVirtual(false); } void UGList::SetVirtualAndLoop() { SetVirtual(true); } void UGList::SetVirtual(bool bInLoop) { if (!bVirtual) { verifyf(ScrollPane != nullptr, TEXT("FairyGUI: Virtual list must be scrollable!")); if (bInLoop) { verifyf(Layout != EListLayoutType::FlowHorizontal && Layout != EListLayoutType::FlowVertical, TEXT("Loop list is not supported for FlowHorizontal or FlowVertical layout!")); ScrollPane->bBouncebackEffect = false; } bVirtual = true; bLoop = bInLoop; RemoveChildrenToPool(); if (ItemSize.X == 0 || ItemSize.Y == 0) { UGObject* obj = GetFromPool(); verifyf(obj != nullptr, TEXT("Virtual List must have a default list item resource.")); ItemSize = obj->GetSize(); ItemSize.X = FMath::CeilToFloat(ItemSize.X); ItemSize.Y = FMath::CeilToFloat(ItemSize.Y); ReturnToPool(obj); } if (Layout == EListLayoutType::SingleColumn || Layout == EListLayoutType::FlowHorizontal) { ScrollPane->ScrollStep = ItemSize.Y; if (bLoop) ScrollPane->LoopMode = 2; } else { ScrollPane->ScrollStep = ItemSize.X; if (bLoop) ScrollPane->LoopMode = 1; } On(FUIEvents::Scroll).AddUObject(this, &UGList::OnScrollHandler); SetVirtualListChangedFlag(true); } } int32 UGList::GetNumItems() const { if (bVirtual) return NumItems; else return Children.Num(); } void UGList::SetNumItems(int32 InNumItems) { if (bVirtual) { verifyf(ItemRenderer.IsBound(), TEXT("Set itemRenderer first!")); NumItems = InNumItems; if (bLoop) RealNumItems = NumItems * 6; else RealNumItems = NumItems; int32 oldCount = VirtualItems.Num(); if (RealNumItems > oldCount) { for (int32 i = oldCount; i < RealNumItems; i++) { FItemInfo ii; ii.Size = ItemSize; VirtualItems.Add(MoveTemp(ii)); } } else { for (int32 i = RealNumItems; i < oldCount; i++) VirtualItems[i].bSelected = false; } if (VirtualListChanged != 0) GetApp()->CancelDelayCall(RefreshTimerHandle); DoRefreshVirtualList(); } else { int32 cnt = Children.Num(); if (InNumItems > cnt) { for (int32 i = cnt; i < InNumItems; i++) { if (!ItemProvider.IsBound()) AddItemFromPool(); else AddItemFromPool(ItemProvider.Execute(i)); } } else { RemoveChildrenToPool(InNumItems, cnt); } if (ItemRenderer.IsBound()) { for (int32 i = 0; i < InNumItems; i++) ItemRenderer.Execute(i, GetChildAt(i)); } } } void UGList::RefreshVirtualList() { verifyf(bVirtual, TEXT("not virtual list")); SetVirtualListChangedFlag(false); } FVector2D UGList::GetSnappingPosition(const FVector2D& InPoint) { if (bVirtual) { FVector2D ret = InPoint; if (Layout == EListLayoutType::SingleColumn || Layout == EListLayoutType::FlowHorizontal) { int32 index = GetIndexOnPos1(ret.Y, false); if (index < VirtualItems.Num() && InPoint.Y - ret.Y > VirtualItems[index].Size.Y / 2 && index < RealNumItems) ret.Y += VirtualItems[index].Size.Y + LineGap; } else if (Layout == EListLayoutType::SingleRow || Layout == EListLayoutType::FlowVertical) { int32 index = GetIndexOnPos2(ret.X, false); if (index < VirtualItems.Num() && InPoint.X - ret.X > VirtualItems[index].Size.X / 2 && index < RealNumItems) ret.X += VirtualItems[index].Size.X + ColumnGap; } else { int32 index = GetIndexOnPos3(ret.X, false); if (index < VirtualItems.Num() && InPoint.X - ret.X > VirtualItems[index].Size.X / 2 && index < RealNumItems) ret.X += VirtualItems[index].Size.X + ColumnGap; } return ret; } else return UGComponent::GetSnappingPosition(InPoint); } void UGList::CheckVirtualList() { if (VirtualListChanged != 0) { DoRefreshVirtualList(); GetApp()->CancelDelayCall(RefreshTimerHandle); } } void UGList::SetVirtualListChangedFlag(bool bLayoutChanged) { if (bLayoutChanged) VirtualListChanged = 2; else if (VirtualListChanged == 0) VirtualListChanged = 1; GetApp()->DelayCall(RefreshTimerHandle, this, &UGList::DoRefreshVirtualList); } void UGList::DoRefreshVirtualList() { bool bLayoutChanged = VirtualListChanged == 2; VirtualListChanged = 0; bEventLocked = true; if (bLayoutChanged) { if (Layout == EListLayoutType::SingleColumn || Layout == EListLayoutType::SingleRow) CurLineItemCount = 1; else if (Layout == EListLayoutType::FlowHorizontal) { if (ColumnCount > 0) CurLineItemCount = ColumnCount; else { CurLineItemCount = FMath::FloorToInt((ScrollPane->GetViewSize().X + ColumnGap) / (ItemSize.X + ColumnGap)); if (CurLineItemCount <= 0) CurLineItemCount = 1; } } else if (Layout == EListLayoutType::FlowVertical) { if (LineCount > 0) CurLineItemCount = LineCount; else { CurLineItemCount = FMath::FloorToInt((ScrollPane->GetViewSize().Y + LineGap) / (ItemSize.Y + LineGap)); if (CurLineItemCount <= 0) CurLineItemCount = 1; } } else //Pagination { if (ColumnCount > 0) CurLineItemCount = ColumnCount; else { CurLineItemCount = FMath::FloorToInt((ScrollPane->GetViewSize().X + ColumnGap) / (ItemSize.X + ColumnGap)); if (CurLineItemCount <= 0) CurLineItemCount = 1; } if (LineCount > 0) CurLineItemCount2 = LineCount; else { CurLineItemCount2 = FMath::FloorToInt((ScrollPane->GetViewSize().Y + LineGap) / (ItemSize.Y + LineGap)); if (CurLineItemCount2 <= 0) CurLineItemCount2 = 1; } } } float ch = 0, cw = 0; if (RealNumItems > 0) { int32 len = FMath::FloorToInt((float)RealNumItems / CurLineItemCount) * CurLineItemCount; int32 len2 = FMath::Min(CurLineItemCount, RealNumItems); if (Layout == EListLayoutType::SingleColumn || Layout == EListLayoutType::FlowHorizontal) { for (int32 i = 0; i < len; i += CurLineItemCount) ch += VirtualItems[i].Size.Y + LineGap; if (ch > 0) ch -= LineGap; if (bAutoResizeItem) cw = ScrollPane->GetViewSize().X; else { for (int32 i = 0; i < len2; i++) cw += VirtualItems[i].Size.X + ColumnGap; if (cw > 0) cw -= ColumnGap; } } else if (Layout == EListLayoutType::SingleRow || Layout == EListLayoutType::FlowVertical) { for (int32 i = 0; i < len; i += CurLineItemCount) cw += VirtualItems[i].Size.X + ColumnGap; if (cw > 0) cw -= ColumnGap; if (bAutoResizeItem) ch = ScrollPane->GetViewSize().Y; else { for (int32 i = 0; i < len2; i++) ch += VirtualItems[i].Size.Y + LineGap; if (ch > 0) ch -= LineGap; } } else { int32 pageCount = FMath::CeilToInt((float)len / (CurLineItemCount * CurLineItemCount2)); cw = pageCount * GetViewWidth(); ch = GetViewHeight(); } } HandleAlign(cw, ch); ScrollPane->SetContentSize(FVector2D(cw, ch)); bEventLocked = false; HandleScroll(true); } void UGList::OnScrollHandler(UEventContext* Context) { HandleScroll(false); } int32 UGList::GetIndexOnPos1(float& pos, bool forceUpdate) { if (RealNumItems < CurLineItemCount) { pos = 0; return 0; } if (NumChildren() > 0 && !forceUpdate) { float pos2 = GetChildAt(0)->GetY(); if (pos2 + (LineGap > 0 ? 0 : -LineGap) > pos) { for (int32 i = FirstIndex - CurLineItemCount; i >= 0; i -= CurLineItemCount) { pos2 -= (VirtualItems[i].Size.Y + LineGap); if (pos2 <= pos) { pos = pos2; return i; } } pos = 0; return 0; } else { float testGap = LineGap > 0 ? LineGap : 0; for (int32 i = FirstIndex; i < RealNumItems; i += CurLineItemCount) { float pos3 = pos2 + VirtualItems[i].Size.Y; if (pos3 + testGap > pos) { pos = pos2; return i; } pos2 = pos3 + LineGap; } pos = pos2; return RealNumItems - CurLineItemCount; } } else { float pos2 = 0; float testGap = LineGap > 0 ? LineGap : 0; for (int32 i = 0; i < RealNumItems; i += CurLineItemCount) { float pos3 = pos2 + VirtualItems[i].Size.Y; if (pos3 + testGap > pos) { pos = pos2; return i; } pos2 = pos3 + LineGap; } pos = pos2; return RealNumItems - CurLineItemCount; } } int32 UGList::GetIndexOnPos2(float& pos, bool forceUpdate) { if (RealNumItems < CurLineItemCount) { pos = 0; return 0; } if (NumChildren() > 0 && !forceUpdate) { float pos2 = GetChildAt(0)->GetX(); if (pos2 + (ColumnGap > 0 ? 0 : -ColumnGap) > pos) { for (int32 i = FirstIndex - CurLineItemCount; i >= 0; i -= CurLineItemCount) { pos2 -= (VirtualItems[i].Size.X + ColumnGap); if (pos2 <= pos) { pos = pos2; return i; } } pos = 0; return 0; } else { float testGap = ColumnGap > 0 ? ColumnGap : 0; for (int32 i = FirstIndex; i < RealNumItems; i += CurLineItemCount) { float pos3 = pos2 + VirtualItems[i].Size.X; if (pos3 + testGap > pos) { pos = pos2; return i; } pos2 = pos3 + ColumnGap; } pos = pos2; return RealNumItems - CurLineItemCount; } } else { float pos2 = 0; float testGap = ColumnGap > 0 ? ColumnGap : 0; for (int32 i = 0; i < RealNumItems; i += CurLineItemCount) { float pos3 = pos2 + VirtualItems[i].Size.X; if (pos3 + testGap > pos) { pos = pos2; return i; } pos2 = pos3 + ColumnGap; } pos = pos2; return RealNumItems - CurLineItemCount; } } int32 UGList::GetIndexOnPos3(float& pos, bool forceUpdate) { if (RealNumItems < CurLineItemCount) { pos = 0; return 0; } float viewWidth = GetViewWidth(); int32 page = FMath::FloorToInt(pos / viewWidth); int32 startIndex = page * (CurLineItemCount * CurLineItemCount2); float pos2 = page * viewWidth; float testGap = ColumnGap > 0 ? ColumnGap : 0; for (int32 i = 0; i < CurLineItemCount; i++) { float pos3 = pos2 + VirtualItems[startIndex + i].Size.X; if (pos3 + testGap > pos) { pos = pos2; return startIndex + i; } pos2 = pos3 + ColumnGap; } pos = pos2; return startIndex + CurLineItemCount - 1; } void UGList::HandleScroll(bool forceUpdate) { if (bEventLocked) return; if (Layout == EListLayoutType::SingleColumn || Layout == EListLayoutType::FlowHorizontal) { int32 enterCounter = 0; while (HandleScroll1(forceUpdate)) { enterCounter++; forceUpdate = false; if (enterCounter > 20) { UE_LOG(LogFairyGUI, Warning, TEXT("list will never be filled as the item renderer function always returns a different size.")); break; } } HandleArchOrder1(); } else if (Layout == EListLayoutType::SingleRow || Layout == EListLayoutType::FlowVertical) { int32 enterCounter = 0; while (HandleScroll2(forceUpdate)) { enterCounter++; forceUpdate = false; if (enterCounter > 20) { UE_LOG(LogFairyGUI, Warning, TEXT("list will never be filled as the item renderer function always returns a different size.")); break; } } HandleArchOrder2(); } else { HandleScroll3(forceUpdate); } bBoundsChanged = false; } bool UGList::HandleScroll1(bool forceUpdate) { float pos = ScrollPane->GetScrollingPosY(); float max = pos + ScrollPane->GetViewSize().Y; bool end = max == ScrollPane->GetContentSize().Y; int32 newFirstIndex = GetIndexOnPos1(pos, forceUpdate); if (newFirstIndex == FirstIndex && !forceUpdate) return false; int32 oldFirstIndex = FirstIndex; FirstIndex = newFirstIndex; int32 curIndex = newFirstIndex; bool forward = oldFirstIndex > newFirstIndex; int32 childCount = NumChildren(); int32 lastIndex = oldFirstIndex + childCount - 1; int32 reuseIndex = forward ? lastIndex : oldFirstIndex; float curX = 0, curY = pos; bool needRender; float deltaSize = 0; float firstItemDeltaSize = 0; FString url = DefaultItem; int32 partSize = (int32)((ScrollPane->GetViewSize().X - ColumnGap * (CurLineItemCount - 1)) / CurLineItemCount); ItemInfoVer++; while (curIndex < RealNumItems && (end || curY < max)) { FItemInfo& ii = VirtualItems[curIndex]; if (ii.Obj == nullptr || forceUpdate) { if (ItemProvider.IsBound()) { url = ItemProvider.Execute(curIndex % NumItems); if (url.Len() == 0) url = DefaultItem; url = UUIPackage::NormalizeURL(url); } if (ii.Obj != nullptr && ii.Obj->GetResourceURL().Compare(url) != 0) { if (Cast(ii.Obj)) ii.bSelected = ((UGButton*)ii.Obj)->IsSelected(); RemoveChildToPool(ii.Obj); ii.Obj = nullptr; } } if (ii.Obj == nullptr) { if (forward) { for (int32 j = reuseIndex; j >= oldFirstIndex; j--) { FItemInfo& ii2 = VirtualItems[j]; if (ii2.Obj != nullptr && ii2.UpdateFlag != ItemInfoVer && ii2.Obj->GetResourceURL().Compare(url) == 0) { if (Cast(ii2.Obj)) ii2.bSelected = ((UGButton*)ii2.Obj)->IsSelected(); ii.Obj = ii2.Obj; ii2.Obj = nullptr; if (j == reuseIndex) reuseIndex--; break; } } } else { for (int32 j = reuseIndex; j <= lastIndex; j++) { FItemInfo& ii2 = VirtualItems[j]; if (ii2.Obj != nullptr && ii2.UpdateFlag != ItemInfoVer && ii2.Obj->GetResourceURL().Compare(url) == 0) { if (Cast(ii2.Obj)) ii2.bSelected = ((UGButton*)ii2.Obj)->IsSelected(); ii.Obj = ii2.Obj; ii2.Obj = nullptr; if (j == reuseIndex) reuseIndex++; break; } } } if (ii.Obj != nullptr) { SetChildIndex(ii.Obj, forward ? curIndex - newFirstIndex : NumChildren()); } else { ii.Obj = Pool->GetObject(url, this); if (forward) AddChildAt(ii.Obj, curIndex - newFirstIndex); else AddChild(ii.Obj); } if (Cast(ii.Obj)) ((UGButton*)ii.Obj)->SetSelected(ii.bSelected); needRender = true; } else needRender = forceUpdate; if (needRender) { if (bAutoResizeItem && (Layout == EListLayoutType::SingleColumn || ColumnCount > 0)) ii.Obj->SetSize(FVector2D(partSize, ii.Obj->GetHeight()), true); ItemRenderer.ExecuteIfBound(curIndex % NumItems, ii.Obj); if (curIndex % CurLineItemCount == 0) { deltaSize += FMath::CeilToFloat(ii.Obj->GetHeight()) - ii.Size.Y; if (curIndex == newFirstIndex && oldFirstIndex > newFirstIndex) { firstItemDeltaSize = FMath::CeilToFloat(ii.Obj->GetHeight()) - ii.Size.Y; } } ii.Size.X = FMath::CeilToFloat(ii.Obj->GetWidth()); ii.Size.Y = FMath::CeilToFloat(ii.Obj->GetHeight()); } ii.UpdateFlag = ItemInfoVer; ii.Obj->SetPosition(FVector2D(curX, curY)); if (curIndex == newFirstIndex) max += ii.Size.Y; curX += ii.Size.X + ColumnGap; if (curIndex % CurLineItemCount == CurLineItemCount - 1) { curX = 0; curY += ii.Size.Y + LineGap; } curIndex++; } for (int32 i = 0; i < childCount; i++) { FItemInfo& ii = VirtualItems[oldFirstIndex + i]; if (ii.UpdateFlag != ItemInfoVer && ii.Obj != nullptr) { if (Cast(ii.Obj)) ii.bSelected = ((UGButton*)ii.Obj)->IsSelected(); RemoveChildToPool(ii.Obj); ii.Obj = nullptr; } } childCount = Children.Num(); for (int32 i = 0; i < childCount; i++) { UGObject* obj = VirtualItems[newFirstIndex + i].Obj; if (Children[i] != obj) SetChildIndex(obj, i); } if (deltaSize != 0 || firstItemDeltaSize != 0) ScrollPane->ChangeContentSizeOnScrolling(0, deltaSize, 0, firstItemDeltaSize); if (curIndex > 0 && NumChildren() > 0 && Container->GetPosition().Y <= 0 && GetChildAt(0)->GetY() > -Container->GetPosition().Y) return true; else return false; } bool UGList::HandleScroll2(bool forceUpdate) { float pos = ScrollPane->GetScrollingPosX(); float max = pos + ScrollPane->GetViewSize().X; bool end = pos == ScrollPane->GetContentSize().X; int32 newFirstIndex = GetIndexOnPos2(pos, forceUpdate); if (newFirstIndex == FirstIndex && !forceUpdate) return false; int32 oldFirstIndex = FirstIndex; FirstIndex = newFirstIndex; int32 curIndex = newFirstIndex; bool forward = oldFirstIndex > newFirstIndex; int32 childCount = NumChildren(); int32 lastIndex = oldFirstIndex + childCount - 1; int32 reuseIndex = forward ? lastIndex : oldFirstIndex; float curX = pos, curY = 0; bool needRender; float deltaSize = 0; float firstItemDeltaSize = 0; FString url = DefaultItem; int32 partSize = (int32)((ScrollPane->GetViewSize().Y - LineGap * (CurLineItemCount - 1)) / CurLineItemCount); ItemInfoVer++; while (curIndex < RealNumItems && (end || curX < max)) { FItemInfo& ii = VirtualItems[curIndex]; if (ii.Obj == nullptr || forceUpdate) { if (ItemProvider.IsBound()) { url = ItemProvider.Execute(curIndex % NumItems); if (url.Len() == 0) url = DefaultItem; url = UUIPackage::NormalizeURL(url); } if (ii.Obj != nullptr && ii.Obj->GetResourceURL().Compare(url) != 0) { if (Cast(ii.Obj)) ii.bSelected = ((UGButton*)ii.Obj)->IsSelected(); RemoveChildToPool(ii.Obj); ii.Obj = nullptr; } } if (ii.Obj == nullptr) { if (forward) { for (int32 j = reuseIndex; j >= oldFirstIndex; j--) { FItemInfo& ii2 = VirtualItems[j]; if (ii2.Obj != nullptr && ii2.UpdateFlag != ItemInfoVer && ii2.Obj->GetResourceURL().Compare(url) == 0) { if (Cast(ii2.Obj)) ii2.bSelected = ((UGButton*)ii2.Obj)->IsSelected(); ii.Obj = ii2.Obj; ii2.Obj = nullptr; if (j == reuseIndex) reuseIndex--; break; } } } else { for (int32 j = reuseIndex; j <= lastIndex; j++) { FItemInfo& ii2 = VirtualItems[j]; if (ii2.Obj != nullptr && ii2.UpdateFlag != ItemInfoVer && ii2.Obj->GetResourceURL().Compare(url) == 0) { if (Cast(ii2.Obj)) ii2.bSelected = ((UGButton*)ii2.Obj)->IsSelected(); ii.Obj = ii2.Obj; ii2.Obj = nullptr; if (j == reuseIndex) reuseIndex++; break; } } } if (ii.Obj != nullptr) { SetChildIndex(ii.Obj, forward ? curIndex - newFirstIndex : NumChildren()); } else { ii.Obj = Pool->GetObject(url, this); if (forward) AddChildAt(ii.Obj, curIndex - newFirstIndex); else AddChild(ii.Obj); } if (Cast(ii.Obj)) ((UGButton*)ii.Obj)->SetSelected(ii.bSelected); needRender = true; } else needRender = forceUpdate; if (needRender) { if (bAutoResizeItem && (Layout == EListLayoutType::SingleRow || LineCount > 0)) ii.Obj->SetSize(FVector2D(ii.Obj->GetWidth(), partSize), true); ItemRenderer.ExecuteIfBound(curIndex % NumItems, ii.Obj); if (curIndex % CurLineItemCount == 0) { deltaSize += FMath::CeilToFloat(ii.Obj->GetWidth()) - ii.Size.X; if (curIndex == newFirstIndex && oldFirstIndex > newFirstIndex) { firstItemDeltaSize = FMath::CeilToFloat(ii.Obj->GetWidth()) - ii.Size.X; } } ii.Size.X = FMath::CeilToFloat(ii.Obj->GetWidth()); ii.Size.Y = FMath::CeilToFloat(ii.Obj->GetHeight()); } ii.UpdateFlag = ItemInfoVer; ii.Obj->SetPosition(FVector2D(curX, curY)); if (curIndex == newFirstIndex) max += ii.Size.X; curY += ii.Size.Y + LineGap; if (curIndex % CurLineItemCount == CurLineItemCount - 1) { curY = 0; curX += ii.Size.X + ColumnGap; } curIndex++; } for (int32 i = 0; i < childCount; i++) { FItemInfo& ii = VirtualItems[oldFirstIndex + i]; if (ii.UpdateFlag != ItemInfoVer && ii.Obj != nullptr) { if (Cast(ii.Obj)) ii.bSelected = ((UGButton*)ii.Obj)->IsSelected(); RemoveChildToPool(ii.Obj); ii.Obj = nullptr; } } childCount = Children.Num(); for (int32 i = 0; i < childCount; i++) { UGObject* obj = VirtualItems[newFirstIndex + i].Obj; if (Children[i] != obj) SetChildIndex(obj, i); } if (deltaSize != 0 || firstItemDeltaSize != 0) ScrollPane->ChangeContentSizeOnScrolling(deltaSize, 0, firstItemDeltaSize, 0); if (curIndex > 0 && NumChildren() > 0 && Container->GetPosition().X <= 0 && GetChildAt(0)->GetX() > -Container->GetPosition().X) return true; else return false; } void UGList::HandleScroll3(bool forceUpdate) { float pos = ScrollPane->GetScrollingPosX(); int32 newFirstIndex = GetIndexOnPos3(pos, forceUpdate); if (newFirstIndex == FirstIndex && !forceUpdate) return; int32 oldFirstIndex = FirstIndex; FirstIndex = newFirstIndex; int32 reuseIndex = oldFirstIndex; int32 virtualItemCount = VirtualItems.Num(); int32 pageSize = CurLineItemCount * CurLineItemCount2; int32 startCol = newFirstIndex % CurLineItemCount; float viewWidth = GetViewWidth(); int32 page = (int32)(newFirstIndex / pageSize); int32 startIndex = page * pageSize; int32 lastIndex = startIndex + pageSize * 2; bool needRender; FString url = DefaultItem; int32 partWidth = (int32)((ScrollPane->GetViewSize().X - ColumnGap * (CurLineItemCount - 1)) / CurLineItemCount); int32 partHeight = (int32)((ScrollPane->GetViewSize().Y - LineGap * (CurLineItemCount2 - 1)) / CurLineItemCount2); ItemInfoVer++; for (int32 i = startIndex; i < lastIndex; i++) { if (i >= RealNumItems) continue; int32 col = i % CurLineItemCount; if (i - startIndex < pageSize) { if (col < startCol) continue; } else { if (col > startCol) continue; } FItemInfo& ii = VirtualItems[i]; ii.UpdateFlag = ItemInfoVer; } UGObject* lastObj = nullptr; int32 insertIndex = 0; for (int32 i = startIndex; i < lastIndex; i++) { if (i >= RealNumItems) continue; FItemInfo& ii = VirtualItems[i]; if (ii.UpdateFlag != ItemInfoVer) continue; if (ii.Obj == nullptr) { reuseIndex = reuseIndex < 0 ? 0 : reuseIndex; while (reuseIndex < virtualItemCount) { FItemInfo& ii2 = VirtualItems[reuseIndex]; if (ii2.Obj != nullptr && ii2.UpdateFlag != ItemInfoVer) { if (Cast(ii2.Obj)) ii2.bSelected = ((UGButton*)ii2.Obj)->IsSelected(); ii.Obj = ii2.Obj; ii2.Obj = nullptr; break; } reuseIndex++; } if (insertIndex == -1) insertIndex = GetChildIndex(lastObj) + 1; if (ii.Obj == nullptr) { if (ItemProvider.IsBound()) { url = ItemProvider.Execute(i % NumItems); if (url.Len() == 0) url = DefaultItem; url = UUIPackage::NormalizeURL(url); } ii.Obj = Pool->GetObject(url, this); AddChildAt(ii.Obj, insertIndex); } else { insertIndex = SetChildIndexBefore(ii.Obj, insertIndex); } insertIndex++; if (Cast(ii.Obj)) ((UGButton*)ii.Obj)->SetSelected(ii.bSelected); needRender = true; } else { needRender = forceUpdate; insertIndex = -1; lastObj = ii.Obj; } if (needRender) { if (bAutoResizeItem) { if (CurLineItemCount == ColumnCount && CurLineItemCount2 == LineCount) ii.Obj->SetSize(FVector2D(partWidth, partHeight), true); else if (CurLineItemCount == ColumnCount) ii.Obj->SetSize(FVector2D(partWidth, ii.Obj->GetHeight()), true); else if (CurLineItemCount2 == LineCount) ii.Obj->SetSize(FVector2D(ii.Obj->GetWidth(), partHeight), true); } ItemRenderer.ExecuteIfBound(i % NumItems, ii.Obj); ii.Size.X = FMath::CeilToFloat(ii.Obj->GetWidth()); ii.Size.Y = FMath::CeilToFloat(ii.Obj->GetHeight()); } } float borderX = (startIndex / pageSize) * viewWidth; float xx = borderX; float yy = 0; float lineHeight = 0; for (int32 i = startIndex; i < lastIndex; i++) { if (i >= RealNumItems) continue; FItemInfo& ii = VirtualItems[i]; if (ii.UpdateFlag == ItemInfoVer) ii.Obj->SetPosition(FVector2D(xx, yy)); if (ii.Size.Y > lineHeight) lineHeight = ii.Size.Y; if (i % CurLineItemCount == CurLineItemCount - 1) { xx = borderX; yy += lineHeight + LineGap; lineHeight = 0; if (i == startIndex + pageSize - 1) { borderX += viewWidth; xx = borderX; yy = 0; } } else xx += ii.Size.X + ColumnGap; } for (int32 i = reuseIndex; i < virtualItemCount; i++) { FItemInfo& ii = VirtualItems[i]; if (ii.UpdateFlag != ItemInfoVer && ii.Obj != nullptr) { if (Cast(ii.Obj)) ii.bSelected = ((UGButton*)ii.Obj)->IsSelected(); RemoveChildToPool(ii.Obj); ii.Obj = nullptr; } } } void UGList::HandleArchOrder1() { if (ChildrenRenderOrder == EChildrenRenderOrder::Arch) { float mid = ScrollPane->GetPosY() + GetViewHeight() / 2; float minDist = FLT_MAX, dist; int32 apexIndex = 0; int32 cnt = NumChildren(); for (int32 i = 0; i < cnt; i++) { UGObject* obj = GetChildAt(i); if (!bFoldInvisibleItems || obj->IsVisible()) { dist = FMath::Abs(mid - obj->GetY() - obj->GetHeight() / 2); if (dist < minDist) { minDist = dist; apexIndex = i; } } } SetApexIndex(apexIndex); } } void UGList::HandleArchOrder2() { if (ChildrenRenderOrder == EChildrenRenderOrder::Arch) { float mid = ScrollPane->GetPosX() + GetViewWidth() / 2; float minDist = FLT_MAX, dist; int32 apexIndex = 0; int32 cnt = NumChildren(); for (int32 i = 0; i < cnt; i++) { UGObject* obj = GetChildAt(i); if (!bFoldInvisibleItems || obj->IsVisible()) { dist = FMath::Abs(mid - obj->GetX() - obj->GetWidth() / 2); if (dist < minDist) { minDist = dist; apexIndex = i; } } } SetApexIndex(apexIndex); } } void UGList::HandleAlign(float contentWidth, float contentHeight) { FVector2D newOffset(0, 0); float viewHeight = GetViewHeight(); float viewWidth = GetViewWidth(); if (contentHeight < viewHeight) { if (VerticalAlign == EVerticalAlignType::Middle) newOffset.Y = (int32)((viewHeight - contentHeight) / 2); else if (VerticalAlign == EVerticalAlignType::Bottom) newOffset.Y = viewHeight - contentHeight; } if (contentWidth < viewWidth) { if (Align == EAlignType::Center) newOffset.X = (int32)((viewWidth - contentWidth) / 2); else if (Align == EAlignType::Right) newOffset.X = viewWidth - contentWidth; } if (newOffset != AlignOffset) { AlignOffset = newOffset; if (ScrollPane != nullptr) ScrollPane->AdjustMaskContainer(); else Container->SetPosition(FVector2D(Margin.Left + AlignOffset.X, Margin.Top + AlignOffset.Y)); } } void UGList::UpdateBounds() { if (bVirtual) return; int32 cnt = Children.Num(); int32 i; int32 j = 0; UGObject* child; float curX = 0; float curY = 0; float cw, ch; float maxWidth = 0; float maxHeight = 0; float viewWidth = GetViewWidth(); float viewHeight = GetViewHeight(); if (Layout == EListLayoutType::SingleColumn) { for (i = 0; i < cnt; i++) { child = GetChildAt(i); if (bFoldInvisibleItems && !child->IsVisible()) continue; if (curY != 0) curY += LineGap; child->SetY(curY); if (bAutoResizeItem) child->SetSize(FVector2D(viewWidth, child->GetHeight()), true); curY += FMath::CeilToFloat(child->GetHeight()); if (child->GetWidth() > maxWidth) maxWidth = child->GetWidth(); } ch = curY; if (ch <= viewHeight && bAutoResizeItem && ScrollPane != nullptr && ScrollPane->bDisplayInDemand && ScrollPane->VtScrollBar != nullptr) { viewWidth += ScrollPane->VtScrollBar->GetWidth(); for (i = 0; i < cnt; i++) { child = GetChildAt(i); if (bFoldInvisibleItems && !child->IsVisible()) continue; child->SetSize(FVector2D(viewWidth, child->GetHeight()), true); if (child->GetWidth() > maxWidth) maxWidth = child->GetWidth(); } } cw = FMath::CeilToFloat(maxWidth); } else if (Layout == EListLayoutType::SingleRow) { for (i = 0; i < cnt; i++) { child = GetChildAt(i); if (bFoldInvisibleItems && !child->IsVisible()) continue; if (curX != 0) curX += ColumnGap; child->SetX(curX); if (bAutoResizeItem) child->SetSize(FVector2D(child->GetWidth(), viewHeight), true); curX += FMath::CeilToFloat(child->GetWidth()); if (child->GetHeight() > maxHeight) maxHeight = child->GetHeight(); } cw = curX; if (cw <= viewWidth && bAutoResizeItem && ScrollPane != nullptr && ScrollPane->bDisplayInDemand && ScrollPane->HzScrollBar != nullptr) { viewHeight += ScrollPane->HzScrollBar->GetHeight(); for (i = 0; i < cnt; i++) { child = GetChildAt(i); if (bFoldInvisibleItems && !child->IsVisible()) continue; child->SetSize(FVector2D(child->GetWidth(), viewHeight), true); if (child->GetHeight() > maxHeight) maxHeight = child->GetHeight(); } } ch = FMath::CeilToFloat(maxHeight); } else if (Layout == EListLayoutType::FlowHorizontal) { if (bAutoResizeItem && ColumnCount > 0) { float lineSize = 0; int32 lineStart = 0; float ratio; for (i = 0; i < cnt; i++) { child = GetChildAt(i); if (bFoldInvisibleItems && !child->IsVisible()) continue; lineSize += child->SourceSize.X; j++; if (j == ColumnCount || i == cnt - 1) { ratio = (viewWidth - lineSize - (j - 1) * ColumnGap) / lineSize; curX = 0; for (j = lineStart; j <= i; j++) { child = GetChildAt(j); if (bFoldInvisibleItems && !child->IsVisible()) continue; child->SetPosition(FVector2D(curX, curY)); if (j < i) { child->SetSize(FVector2D(child->SourceSize.X + round(child->SourceSize.X * ratio), child->GetHeight()), true); curX += FMath::CeilToFloat(child->GetWidth()) + ColumnGap; } else { child->SetSize(FVector2D(viewWidth - curX, child->GetHeight()), true); } if (child->GetHeight() > maxHeight) maxHeight = child->GetHeight(); } curY += FMath::CeilToFloat(maxHeight) + LineGap; maxHeight = 0; j = 0; lineStart = i + 1; lineSize = 0; } } ch = curY + FMath::CeilToFloat(maxHeight); cw = viewWidth; } else { for (i = 0; i < cnt; i++) { child = GetChildAt(i); if (bFoldInvisibleItems && !child->IsVisible()) continue; if (curX != 0) curX += ColumnGap; if ((ColumnCount != 0 && j >= ColumnCount) || (ColumnCount == 0 && curX + child->GetWidth() > viewWidth && maxHeight != 0)) { curX = 0; curY += FMath::CeilToFloat(maxHeight) + LineGap; maxHeight = 0; j = 0; } child->SetPosition(FVector2D(curX, curY)); curX += FMath::CeilToFloat(child->GetWidth()); if (curX > maxWidth) maxWidth = curX; if (child->GetHeight() > maxHeight) maxHeight = child->GetHeight(); j++; } ch = curY + FMath::CeilToFloat(maxHeight); cw = FMath::CeilToFloat(maxWidth); } } else if (Layout == EListLayoutType::FlowVertical) { if (bAutoResizeItem && LineCount > 0) { float lineSize = 0; int32 lineStart = 0; float ratio; for (i = 0; i < cnt; i++) { child = GetChildAt(i); if (bFoldInvisibleItems && !child->IsVisible()) continue; lineSize += child->SourceSize.Y; j++; if (j == LineCount || i == cnt - 1) { ratio = (viewHeight - lineSize - (j - 1) * LineGap) / lineSize; curY = 0; for (j = lineStart; j <= i; j++) { child = GetChildAt(j); if (bFoldInvisibleItems && !child->IsVisible()) continue; child->SetPosition(FVector2D(curX, curY)); if (j < i) { child->SetSize(FVector2D(child->GetWidth(), child->SourceSize.Y + FMath::RoundToFloat(child->SourceSize.Y * ratio)), true); curY += FMath::CeilToFloat(child->GetHeight()) + LineGap; } else { child->SetSize(FVector2D(child->GetWidth(), viewHeight - curY), true); } if (child->GetWidth() > maxWidth) maxWidth = child->GetWidth(); } curX += FMath::CeilToFloat(maxWidth) + ColumnGap; maxWidth = 0; j = 0; lineStart = i + 1; lineSize = 0; } } cw = curX + FMath::CeilToFloat(maxWidth); ch = viewHeight; } else { for (i = 0; i < cnt; i++) { child = GetChildAt(i); if (bFoldInvisibleItems && !child->IsVisible()) continue; if (curY != 0) curY += LineGap; if ((LineCount != 0 && j >= LineCount) || (LineCount == 0 && curY + child->GetHeight() > viewHeight && maxWidth != 0)) { curY = 0; curX += FMath::CeilToFloat(maxWidth) + ColumnGap; maxWidth = 0; j = 0; } child->SetPosition(FVector2D(curX, curY)); curY += child->GetHeight(); if (curY > maxHeight) maxHeight = curY; if (child->GetWidth() > maxWidth) maxWidth = child->GetWidth(); j++; } cw = curX + FMath::CeilToFloat(maxWidth); ch = FMath::CeilToFloat(maxHeight); } } else //Pagination { int32 page = 0; int32 k = 0; float eachHeight = 0; if (bAutoResizeItem && LineCount > 0) eachHeight = FMath::FloorToFloat((viewHeight - (LineCount - 1) * LineGap) / LineCount); if (bAutoResizeItem && ColumnCount > 0) { float lineSize = 0; int32 lineStart = 0; float ratio; for (i = 0; i < cnt; i++) { child = GetChildAt(i); if (bFoldInvisibleItems && !child->IsVisible()) continue; if (j == 0 && ((LineCount != 0 && k >= LineCount) || (LineCount == 0 && curY + (LineCount > 0 ? eachHeight : child->GetHeight()) > viewHeight))) { page++; curY = 0; k = 0; } lineSize += child->SourceSize.X; j++; if (j == ColumnCount || i == cnt - 1) { ratio = (viewWidth - lineSize - (j - 1) * ColumnGap) / lineSize; curX = 0; for (j = lineStart; j <= i; j++) { child = GetChildAt(j); if (bFoldInvisibleItems && !child->IsVisible()) continue; child->SetPosition(FVector2D(page * viewWidth + curX, curY)); if (j < i) { child->SetSize(FVector2D(child->SourceSize.X + FMath::RoundToFloat(child->SourceSize.X * ratio), LineCount > 0 ? eachHeight : child->GetHeight()), true); curX += FMath::CeilToFloat(child->GetWidth()) + ColumnGap; } else { child->SetSize(FVector2D(viewWidth - curX, LineCount > 0 ? eachHeight : child->GetHeight()), true); } if (child->GetHeight() > maxHeight) maxHeight = child->GetHeight(); } curY += FMath::CeilToFloat(maxHeight) + LineGap; maxHeight = 0; j = 0; lineStart = i + 1; lineSize = 0; k++; } } } else { for (i = 0; i < cnt; i++) { child = GetChildAt(i); if (bFoldInvisibleItems && !child->IsVisible()) continue; if (curX != 0) curX += ColumnGap; if (bAutoResizeItem && LineCount > 0) child->SetSize(FVector2D(child->GetWidth(), eachHeight), true); if ((ColumnCount != 0 && j >= ColumnCount) || (ColumnCount == 0 && curX + child->GetWidth() > viewWidth && maxHeight != 0)) { curX = 0; curY += maxHeight + LineGap; maxHeight = 0; j = 0; k++; if ((LineCount != 0 && k >= LineCount) || (LineCount == 0 && curY + child->GetHeight() > viewHeight && maxWidth != 0)) //new page { page++; curY = 0; k = 0; } } child->SetPosition(FVector2D(page * viewWidth + curX, curY)); curX += FMath::CeilToFloat(child->GetWidth()); if (curX > maxWidth) maxWidth = curX; if (child->GetHeight() > maxHeight) maxHeight = child->GetHeight(); j++; } } ch = page > 0 ? viewHeight : (curY + FMath::CeilToFloat(maxHeight)); cw = (page + 1) * viewWidth; } HandleAlign(cw, ch); SetBounds(0, 0, cw, ch); } void UGList::SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos) { UGComponent::SetupBeforeAdd(Buffer, BeginPos); Buffer->Seek(BeginPos, 5); Layout = (EListLayoutType)Buffer->ReadByte(); SelectionMode = (EListSelectionMode)Buffer->ReadByte(); Align = (EAlignType)Buffer->ReadByte(); VerticalAlign = (EVerticalAlignType)Buffer->ReadByte(); LineGap = Buffer->ReadShort(); ColumnGap = Buffer->ReadShort(); LineCount = Buffer->ReadShort(); ColumnCount = Buffer->ReadShort(); bAutoResizeItem = Buffer->ReadBool(); ChildrenRenderOrder = (EChildrenRenderOrder)Buffer->ReadByte(); ApexIndex = Buffer->ReadShort(); if (Buffer->ReadBool()) { Margin.Top = Buffer->ReadInt(); Margin.Bottom = Buffer->ReadInt(); Margin.Left = Buffer->ReadInt(); Margin.Right = Buffer->ReadInt(); } EOverflowType overflow = (EOverflowType)Buffer->ReadByte(); if (overflow == EOverflowType::Scroll) { int32 savedPos = Buffer->GetPos(); Buffer->Seek(BeginPos, 7); SetupScroll(Buffer); Buffer->SetPos(savedPos); } else SetupOverflow(overflow); if (Buffer->ReadBool()) //clipSoftness Buffer->Skip(8); if (Buffer->Version >= 2) { bScrollItemToViewOnClick = Buffer->ReadBool(); bFoldInvisibleItems = Buffer->ReadBool(); } Buffer->Seek(BeginPos, 8); DefaultItem = Buffer->ReadS(); ReadItems(Buffer); } void UGList::ReadItems(FByteBuffer* Buffer) { const FString* str; int32 itemCount = Buffer->ReadShort(); for (int32 i = 0; i < itemCount; i++) { int32 nextPos = Buffer->ReadShort(); nextPos += Buffer->GetPos(); str = Buffer->ReadSP(); if (!str || (*str).IsEmpty()) { str = &DefaultItem; if ((*str).IsEmpty()) { Buffer->SetPos(nextPos); continue; } } UGObject* obj = GetFromPool(*str); if (obj != nullptr) { AddChild(obj); SetupItem(Buffer, obj); } Buffer->SetPos(nextPos); } } void UGList::SetupItem(FByteBuffer* Buffer, UGObject* Obj) { const FString* str; UGButton* btn = Cast(Obj); if ((str = Buffer->ReadSP()) != nullptr) Obj->SetText(*str); if ((str = Buffer->ReadSP()) != nullptr && btn) btn->SetSelectedTitle(*str); if ((str = Buffer->ReadSP()) != nullptr) Obj->SetIcon(*str); if ((str = Buffer->ReadSP()) != nullptr && btn) btn->SetSelectedIcon(*str); if ((str = Buffer->ReadSP()) != nullptr) Obj->Name = *str; UGComponent* gcom = Cast(Obj); if (gcom != nullptr) { int32 cnt = Buffer->ReadShort(); for (int32 i = 0; i < cnt; i++) { UGController* cc = gcom->GetController(Buffer->ReadS()); const FString& PageID = Buffer->ReadS(); cc->SetSelectedPageID(PageID); } if (Buffer->Version >= 2) { cnt = Buffer->ReadShort(); for (int32 i = 0; i < cnt; i++) { const FString& target = Buffer->ReadS(); EObjectPropID PropID = (EObjectPropID)Buffer->ReadShort(); FString value = Buffer->ReadS(); UGObject* obj2 = gcom->GetChildByPath(target); if (obj2 != nullptr) obj2->SetProp(PropID, FNVariant(value)); } } } } void UGList::SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos) { UGComponent::SetupAfterAdd(Buffer, BeginPos); Buffer->Seek(BeginPos, 6); int32 i = Buffer->ReadShort(); if (i != -1) SelectionController = Parent->GetControllerAt(i); } ================================================ FILE: Source/FairyGUI/Private/UI/GLoader.cpp ================================================ #include "UI/GLoader.h" #include "UI/UIPackage.h" #include "UI/GComponent.h" #include "Widgets/NTexture.h" #include "Widgets/SMovieClip.h" #include "Widgets/SContainer.h" #include "Utils/ByteBuffer.h" #include "Engine/AssetManager.h" UGLoader::UGLoader() { if (!HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject)) { DisplayObject = Container = SNew(SContainer).GObject(this); Content = SNew(SMovieClip); Content->SetInteractable(false); Container->AddChild(Content.ToSharedRef()); } } UGLoader::~UGLoader() { } void UGLoader::SetURL(const FString& InURL) { if (URL.Compare(InURL, ESearchCase::CaseSensitive) == 0) return; ClearContent(); URL = InURL; LoadContent(); UpdateGear(7); } void UGLoader::SetAlign(EAlignType InAlign) { if (Align != InAlign) { Align = InAlign; UpdateLayout(); } } void UGLoader::SetVerticalAlign(EVerticalAlignType InVerticalAlign) { if (VerticalAlign != InVerticalAlign) { VerticalAlign = InVerticalAlign; UpdateLayout(); } } void UGLoader::SetAutoSize(bool bInAutoSize) { if (bAutoSize != bInAutoSize) { bAutoSize = bInAutoSize; UpdateLayout(); } } void UGLoader::SetFill(ELoaderFillType InFillType) { if (Fill != InFillType) { Fill = InFillType; UpdateLayout(); } } void UGLoader::SetShrinkOnly(bool bInShrinkOnly) { if (bShrinkOnly != bInShrinkOnly) { bShrinkOnly = bInShrinkOnly; UpdateLayout(); } } EFlipType UGLoader::GetFlip() const { return Content->Graphics.GetFlip(); } void UGLoader::SetFlip(EFlipType InFlip) { Content->Graphics.SetFlip(InFlip); } FColor UGLoader::GetColor() const { return Content->Graphics.GetColor(); } void UGLoader::SetColor(const FColor& InColor) { Content->Graphics.SetColor(InColor); } EFillMethod UGLoader::GetFillMethod() const { return Content->GetFillMethod(); } void UGLoader::SetFillMethod(EFillMethod Method) { Content->SetFillMethod(Method); } int32 UGLoader::GetFillOrigin() const { return Content->GetFillOrigin(); } void UGLoader::SetFillOrigin(int32 Origin) { Content->SetFillOrigin(Origin); } bool UGLoader::IsFillClockwise() const { return Content->IsFillClockwise(); } void UGLoader::SetFillClockwise(bool bClockwise) { Content->SetFillClockwise(bClockwise); } float UGLoader::GetFillAmount() const { return Content->GetFillAmount(); } void UGLoader::SetFillAmount(float Amount) { Content->SetFillAmount(Amount); } bool UGLoader::IsPlaying() const { return Content->IsPlaying(); } void UGLoader::SetPlaying(bool bInPlaying) { if (Content->IsPlaying() != bInPlaying) { Content->SetPlaying(bInPlaying); UpdateGear(5); } } int UGLoader::GetFrame() const { return Content->GetFrame(); } void UGLoader::SetFrame(int32 InFrame) { if (Content->GetFrame() != InFrame) { Content->SetFrame(InFrame); UpdateGear(5); } } void UGLoader::LoadContent() { ClearContent(); if (URL.IsEmpty()) return; if (URL.StartsWith("ui://")) LoadFromPackage(URL); else LoadExternal(); } void UGLoader::ClearContent() { ContentItem.Reset(); Content->SetTexture(nullptr); Content->SetClipData(nullptr); if (Content2 != nullptr) { Container->RemoveChild(Content2->GetDisplayObject()); Content2 = nullptr; } } void UGLoader::LoadFromPackage(const FString& ItemURL) { ContentItem = UUIPackage::GetItemByURL(ItemURL); if (ContentItem.IsValid()) { ContentItem = ContentItem->GetBranch(); SourceSize = ContentItem->Size; ContentItem = ContentItem->GetHighResolution(); ContentItem->Load(); if (ContentItem->Type == EPackageItemType::Image) { Content->SetTexture(ContentItem->Texture); if (ContentItem->Scale9Grid.IsSet()) Content->SetScale9Grid(ContentItem->Scale9Grid); else if (ContentItem->bScaleByTile) Content->SetScaleByTile(true); UpdateLayout(); } else if (ContentItem->Type == EPackageItemType::MovieClip) { Content->SetClipData(ContentItem->MovieClipData); UpdateLayout(); } else if (ContentItem->Type == EPackageItemType::Component) { UGObject* obj = UUIPackage::CreateObjectFromURL(ItemURL, this); if (obj == nullptr || !obj->IsA()) SetErrorState(); else { Content2 = Cast(obj); Container->AddChild(Content2->GetDisplayObject()); UpdateLayout(); } } else { if (bAutoSize) SetSize(ContentItem->Size); SetErrorState(); UE_LOG(LogFairyGUI, Warning, TEXT("Unsupported type of GLoader: %d"), ContentItem->Type); } } else SetErrorState(); } void UGLoader::LoadExternal() { SoftObjectPath = MakeShareable(new FSoftObjectPath(URL)); UAssetManager::GetStreamableManager().RequestAsyncLoad(*SoftObjectPath, FStreamableDelegate::CreateUObject(this, &UGLoader::OnExternalLoaded, URL)); } void UGLoader::OnExternalLoaded(FString LoadingURL) { if (!SoftObjectPath.IsValid() || LoadingURL != URL) return; TSoftObjectPtr NativeTexture(*SoftObjectPath); UNTexture* NTexture = NewObject(this); NTexture->Init(NativeTexture.Get()); Content->SetTexture(NTexture); Content->SetNativeSize(); SourceSize = NTexture->GetSize(); UpdateLayout(); SoftObjectPath.Reset(); } void UGLoader::UpdateLayout() { if (Content2 == nullptr && Content->GetTexture() == nullptr && !Content->GetClipData().IsValid()) { if (bAutoSize) { bUpdatingLayout = true; SetSize(FVector2D(50, 30)); bUpdatingLayout = false; } return; } FVector2D contentSize = SourceSize; if (bAutoSize) { bUpdatingLayout = true; if (contentSize.X == 0) contentSize.X = 50; if (contentSize.Y == 0) contentSize.Y = 30; SetSize(contentSize); bUpdatingLayout = false; if (Size == contentSize) { if (Content2 != nullptr) { Content2->SetPosition(FVector2D(0, 0)); Content2->SetScale(FVector2D(1, 1)); } else { Content->SetPosition(FVector2D(0, 0)); Content->SetSize(contentSize); } return; } } FVector2D ContentScale(1, 1); if (Fill != ELoaderFillType::None) { ContentScale = Size / SourceSize; if (ContentScale != FVector2D(1, 1)) { if (Fill == ELoaderFillType::ScaleMatchHeight) ContentScale.X = ContentScale.Y; else if (Fill == ELoaderFillType::ScaleMatchWidth) ContentScale.Y = ContentScale.X; else if (Fill == ELoaderFillType::Scale) { if (ContentScale.X > ContentScale.Y) ContentScale.X = ContentScale.Y; else ContentScale.Y = ContentScale.X; } else if (Fill == ELoaderFillType::ScaleNoBorder) { if (ContentScale.X > ContentScale.Y) ContentScale.Y = ContentScale.X; else ContentScale.X = ContentScale.Y; } if (bShrinkOnly) { if (ContentScale.X > 1) ContentScale.X = 1; if (ContentScale.Y > 1) ContentScale.Y = 1; } contentSize = SourceSize * ContentScale; } } if (Content2 != nullptr) Content2->SetScale(ContentScale); else Content->SetSize(contentSize); FVector2D ContentPosition; if (Align == EAlignType::Center) ContentPosition.X = (Size.X - contentSize.X) / 2; else if (Align == EAlignType::Right) ContentPosition.X = Size.X - contentSize.X; else ContentPosition.X = 0; if (VerticalAlign == EVerticalAlignType::Middle) ContentPosition.Y = (Size.Y - contentSize.Y) / 2; else if (VerticalAlign == EVerticalAlignType::Bottom) ContentPosition.Y = Size.Y - contentSize.Y; else ContentPosition.Y = 0; if (Content2 != nullptr) Content2->SetPosition(ContentPosition); else Content->SetPosition(ContentPosition); } void UGLoader::SetErrorState() { } FNVariant UGLoader::GetProp(EObjectPropID PropID) const { switch (PropID) { case EObjectPropID::Color: return FNVariant(GetColor()); case EObjectPropID::Playing: return FNVariant(Content->IsPlaying()); case EObjectPropID::Frame: return FNVariant(Content->GetFrame()); case EObjectPropID::TimeScale: return FNVariant(Content->GetTimeScale()); default: return UGObject::GetProp(PropID); } } void UGLoader::SetProp(EObjectPropID PropID, const FNVariant& InValue) { switch (PropID) { case EObjectPropID::Color: SetColor(InValue.AsColor()); break; case EObjectPropID::Playing: Content->SetPlaying(InValue.AsBool()); break; case EObjectPropID::Frame: Content->SetFrame(InValue.AsInt()); break; case EObjectPropID::TimeScale: Content->SetTimeScale(InValue.AsFloat()); break; case EObjectPropID::DeltaTime: Content->Advance(InValue.AsFloat()); break; default: UGObject::SetProp(PropID, InValue); break; } } void UGLoader::HandleSizeChanged() { UGObject::HandleSizeChanged(); if (!bUpdatingLayout) UpdateLayout(); } void UGLoader::SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos) { UGObject::SetupBeforeAdd(Buffer, BeginPos); Buffer->Seek(BeginPos, 5); URL = Buffer->ReadS(); Align = (EAlignType)Buffer->ReadByte(); VerticalAlign = (EVerticalAlignType)Buffer->ReadByte(); Fill = (ELoaderFillType)Buffer->ReadByte(); bShrinkOnly = Buffer->ReadBool(); bAutoSize = Buffer->ReadBool(); bShowErrorSign = Buffer->ReadBool(); Content->SetPlaying(Buffer->ReadBool()); Content->SetFrame(Buffer->ReadInt()); if (Buffer->ReadBool()) SetColor(Buffer->ReadColor()); int32 method = Buffer->ReadByte(); if (method != 0) { Content->SetFillMethod((EFillMethod)method); Content->SetFillOrigin(Buffer->ReadByte()); Content->SetFillClockwise(Buffer->ReadBool()); Content->SetFillAmount(Buffer->ReadFloat()); } if (!URL.IsEmpty()) LoadContent(); } ================================================ FILE: Source/FairyGUI/Private/UI/GLoader3D.cpp ================================================ #include "UI/GLoader3D.h" #include "UI/UIPackage.h" #include "UI/GComponent.h" #include "Widgets/NTexture.h" #include "Widgets/SMovieClip.h" #include "Widgets/SContainer.h" #include "Utils/ByteBuffer.h" UGLoader3D::UGLoader3D() { if (!HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject)) { DisplayObject = Content = SNew(SFImage).GObject(this); } } UGLoader3D::~UGLoader3D() { } void UGLoader3D::SetURL(const FString& InURL) { if (URL.Compare(InURL, ESearchCase::CaseSensitive) == 0) return; ClearContent(); URL = InURL; LoadContent(); UpdateGear(7); } FColor UGLoader3D::GetColor() const { return FColor();// Content->getColor(); } void UGLoader3D::SetColor(const FColor& InColor) { //Content->setColor(value); } void UGLoader3D::LoadContent() { ClearContent(); if (URL.IsEmpty()) return; if (URL.StartsWith("ui://")) LoadFromPackage(URL); else LoadExternal(); } void UGLoader3D::ClearContent() { } void UGLoader3D::LoadFromPackage(const FString& ItemURL) { ContentItem = UUIPackage::GetItemByURL(ItemURL); if (ContentItem.IsValid()) { ContentItem = ContentItem->GetBranch(); SourceSize = ContentItem->Size; ContentItem = ContentItem->GetHighResolution(); ContentItem->Load(); if (ContentItem->Type == EPackageItemType::Spine) { UpdateLayout(); } else if (ContentItem->Type == EPackageItemType::DragonBones) { UpdateLayout(); } else { if (bAutoSize) SetSize(ContentItem->Size); SetErrorState(); UE_LOG(LogFairyGUI, Warning, TEXT("Unsupported type of GLoader: %d"), ContentItem->Type); } } else SetErrorState(); } void UGLoader3D::LoadExternal() { } void UGLoader3D::UpdateLayout() { FVector2D contentSize = SourceSize; if (bAutoSize) { bUpdatingLayout = true; if (contentSize.X == 0) contentSize.X = 50; if (contentSize.Y == 0) contentSize.Y = 30; SetSize(contentSize); bUpdatingLayout = false; if (Size == contentSize) { Content->SetPosition(FVector2D(0, 0)); Content->SetSize(contentSize); return; } } FVector2D ContentScale(1, 1); if (Fill != ELoaderFillType::None) { ContentScale = Size / SourceSize; if (ContentScale != FVector2D(1, 1)) { if (Fill == ELoaderFillType::ScaleMatchHeight) ContentScale.X = ContentScale.Y; else if (Fill == ELoaderFillType::ScaleMatchWidth) ContentScale.Y = ContentScale.X; else if (Fill == ELoaderFillType::Scale) { if (ContentScale.X > ContentScale.Y) ContentScale.X = ContentScale.Y; else ContentScale.Y = ContentScale.X; } else if (Fill == ELoaderFillType::ScaleNoBorder) { if (ContentScale.X > ContentScale.Y) ContentScale.Y = ContentScale.X; else ContentScale.X = ContentScale.Y; } if (bShrinkOnly) { if (ContentScale.X > 1) ContentScale.X = 1; if (ContentScale.Y > 1) ContentScale.Y = 1; } contentSize = SourceSize * ContentScale; } } Content->SetSize(contentSize); FVector2D ContentPosition; if (Align == EAlignType::Center) ContentPosition.X = (Size.X - contentSize.X) / 2; else if (Align == EAlignType::Right) ContentPosition.X = Size.X - contentSize.X; else ContentPosition.X = 0; if (VerticalAlign == EVerticalAlignType::Middle) ContentPosition.Y = (Size.Y - contentSize.Y) / 2; else if (VerticalAlign == EVerticalAlignType::Bottom) ContentPosition.Y = Size.Y - contentSize.Y; else ContentPosition.Y = 0; Content->SetPosition(ContentPosition); } void UGLoader3D::SetErrorState() { } FNVariant UGLoader3D::GetProp(EObjectPropID PropID) const { switch (PropID) { case EObjectPropID::Color: return FNVariant(GetColor()); break; default: return UGObject::GetProp(PropID); } } void UGLoader3D::SetProp(EObjectPropID PropID, const FNVariant& InValue) { switch (PropID) { case EObjectPropID::Color: SetColor(InValue.AsColor()); break; default: UGObject::SetProp(PropID, InValue); break; } } void UGLoader3D::HandleSizeChanged() { UGObject::HandleSizeChanged(); if (!bUpdatingLayout) UpdateLayout(); } void UGLoader3D::SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos) { UGObject::SetupBeforeAdd(Buffer, BeginPos); Buffer->Seek(BeginPos, 5); } ================================================ FILE: Source/FairyGUI/Private/UI/GMovieClip.cpp ================================================ #include "UI/GMovieClip.h" #include "Widgets/NTexture.h" #include "Widgets/SMovieClip.h" #include "Utils/ByteBuffer.h" UGMovieClip::UGMovieClip() { if (!HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject)) { DisplayObject = Content = SNew(SMovieClip).GObject(this); DisplayObject->SetInteractable(false); } } UGMovieClip::~UGMovieClip() { } void UGMovieClip::SetPlaySettings(int32 InStart, int32 InEnd, int32 InTimes, int32 InEndAt, const FSimpleDelegate& InCompleteCallback) { Content->SetPlaySettings(InStart, InEnd, InTimes, InEndAt, InCompleteCallback); } bool UGMovieClip::IsPlaying() const { return Content->IsPlaying(); } void UGMovieClip::SetPlaying(bool bInPlaying) { Content->SetPlaying(bInPlaying); } int32 UGMovieClip::GetFrame() const { return Content->GetFrame(); } void UGMovieClip::SetFrame(int32 InFrame) { Content->SetFrame(InFrame); } float UGMovieClip::GetTimeScale() const { return Content->GetTimeScale(); } void UGMovieClip::SetTimeScale(float InTimeScale) { Content->SetTimeScale(InTimeScale); } void UGMovieClip::Advance(float Time) { Content->Advance(Time); } EFlipType UGMovieClip::GetFlip() const { return Content->Graphics.GetFlip(); } void UGMovieClip::SetFlip(EFlipType InFlip) { Content->Graphics.SetFlip(InFlip); } FColor UGMovieClip::GetColor() const { return Content->Graphics.GetColor(); } void UGMovieClip::SetColor(const FColor& InColor) { Content->Graphics.SetColor(InColor); } FNVariant UGMovieClip::GetProp(EObjectPropID PropID) const { switch (PropID) { case EObjectPropID::Color: return FNVariant(GetColor()); case EObjectPropID::Playing: return FNVariant(Content->IsPlaying()); case EObjectPropID::Frame: return FNVariant(Content->GetFrame()); case EObjectPropID::TimeScale: return FNVariant(Content->GetTimeScale()); default: return UGObject::GetProp(PropID); } } void UGMovieClip::SetProp(EObjectPropID PropID, const FNVariant& InValue) { switch (PropID) { case EObjectPropID::Color: SetColor(InValue.AsColor()); break; case EObjectPropID::Playing: Content->SetPlaying(InValue.AsBool()); break; case EObjectPropID::Frame: Content->SetFrame(InValue.AsInt()); break; case EObjectPropID::TimeScale: Content->SetTimeScale(InValue.AsFloat()); break; case EObjectPropID::DeltaTime: Content->Advance(InValue.AsFloat()); break; default: UGObject::SetProp(PropID, InValue); break; } } void UGMovieClip::ConstructFromResource() { TSharedPtr contentItem = PackageItem->GetBranch(); SourceSize = contentItem->Size; InitSize = SourceSize; contentItem = contentItem->GetHighResolution(); contentItem->Load(); Content->SetClipData(contentItem->MovieClipData); SetSize(SourceSize); } void UGMovieClip::SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos) { UGObject::SetupBeforeAdd(Buffer, BeginPos); Buffer->Seek(BeginPos, 5); if (Buffer->ReadBool()) SetColor(Buffer->ReadColor()); SetFlip((EFlipType)Buffer->ReadByte()); SetFrame(Buffer->ReadInt()); SetPlaying(Buffer->ReadBool()); } ================================================ FILE: Source/FairyGUI/Private/UI/GObject.cpp ================================================ #include "UI/GObject.h" #include "UI/GList.h" #include "UI/GGroup.h" #include "UI/GController.h" #include "UI/UIPackage.h" #include "UI/GRoot.h" #include "UI/Gears/GearBase.h" #include "UI/Gears/GearDisplay.h" #include "UI/Gears/GearDisplay2.h" #include "Widgets/SDisplayObject.h" #include "Utils/ByteBuffer.h" #include "FairyApplication.h" TWeakObjectPtr UGObject::DraggingObject; FVector2D UGObject::GlobalDragStart; FBox2D UGObject::GlobalRect; bool UGObject::bUpdateInDragging = false; UGObject::UGObject() : SourceSize(ForceInit), InitSize(ForceInit), MinSize(ForceInit), MaxSize(ForceInit), Position(ForceInit), Size(ForceInit), RawSize(ForceInit), Pivot(ForceInit), Scale{ 1, 1 }, Skew(ForceInit), Alpha(1.0f), bVisible(true), bInternalVisible(true) { static int32 _gInstanceCounter = 1; ID.AppendInt(_gInstanceCounter); Relations = MakeShareable(new FRelations(this)); } UGObject::~UGObject() { } void UGObject::SetX(float InX) { SetPosition(FVector2D(InX, Position.Y)); } void UGObject::SetY(float InY) { SetPosition(FVector2D(Position.X, InY)); } void UGObject::SetPosition(const FVector2D& InPosition) { if (Position != InPosition) { FVector2D delta = InPosition - Position; Position = InPosition; HandlePositionChanged(); UGGroup* g = Cast(this); if (g != nullptr) g->MoveChildren(delta); UpdateGear(1); if (Parent.IsValid() && !Parent->IsA()) { Parent->SetBoundsChangedFlag(); if (Group.IsValid()) Group->SetBoundsChangedFlag(true); OnPositionChangedEvent.Broadcast(); } if (DraggingObject.Get() == this && !bUpdateInDragging) GlobalRect = LocalToGlobalRect(FBox2D(FVector2D(), Size)); } } float UGObject::GetXMin() const { return bPivotAsAnchor ? (Position.X - Size.X * Pivot.X) : Position.X; } void UGObject::SetXMin(float InXMin) { if (bPivotAsAnchor) SetPosition(FVector2D(InXMin + Size.X * Pivot.X, Position.Y)); else SetPosition(FVector2D(InXMin, Position.Y)); } float UGObject::GetYMin() const { return bPivotAsAnchor ? (Position.Y - Size.Y * Pivot.Y) : Position.Y; } void UGObject::SetYMin(float InYMin) { if (bPivotAsAnchor) SetPosition(FVector2D(Position.X, InYMin + Size.Y * Pivot.Y)); else SetPosition(FVector2D(Position.X, InYMin)); } void UGObject::SetSize(const FVector2D& InSize, bool bIgnorePivot) { if (RawSize != InSize) { RawSize = InSize; FVector2D ClampSize = InSize; if (ClampSize.X < MinSize.X) ClampSize.X = MinSize.X; else if (MaxSize.X > 0 && ClampSize.X > MaxSize.X) ClampSize.X = MaxSize.X; if (ClampSize.Y < MinSize.Y) ClampSize.Y = MinSize.Y; else if (MaxSize.Y > 0 && ClampSize.Y > MaxSize.Y) ClampSize.Y = MaxSize.Y; FVector2D Delta = ClampSize - Size; Size = ClampSize; HandleSizeChanged(); if (Pivot.X != 0 || Pivot.Y != 0) { if (!bPivotAsAnchor) { if (!bIgnorePivot) SetPosition(Position - Pivot * Delta); else HandlePositionChanged(); } else HandlePositionChanged(); } UGGroup* g = Cast(this); if (g != nullptr) g->ResizeChildren(Delta); UpdateGear(2); if (Parent.IsValid()) { Relations->OnOwnerSizeChanged(Delta, bPivotAsAnchor || !bIgnorePivot); Parent->SetBoundsChangedFlag(); if (Group.IsValid()) Group->SetBoundsChangedFlag(); } OnSizeChangedEvent.Broadcast(); } } void UGObject::SetSizeDirectly(const FVector2D& InSize) { RawSize = InSize; Size = InSize; if (Size.X < 0) Size.X = 0; if (Size.Y < 0) Size.Y = 0; } void UGObject::Center(bool bRestraint) { UGComponent* r = nullptr; if (Parent.IsValid()) r = Parent.Get(); else r = GetUIRoot(); SetPosition(((r->Size - Size) / 2).RoundToVector()); if (bRestraint) { AddRelation(r, ERelationType::Center_Center); AddRelation(r, ERelationType::Middle_Middle); } } void UGObject::MakeFullScreen(bool bRestraint) { SetSize(GetUIRoot()->GetSize()); if (bRestraint) AddRelation(GetUIRoot(), ERelationType::Size); } void UGObject::SetPivot(const FVector2D& InPivot, bool bAsAnchor) { if (Pivot != InPivot || bPivotAsAnchor != bAsAnchor) { Pivot = InPivot; bPivotAsAnchor = bAsAnchor; DisplayObject->SetRenderTransformPivot(FVector2D(Pivot.X, Pivot.Y)); HandlePositionChanged(); } } void UGObject::SetScale(const FVector2D& InScale) { if (Scale != InScale) { Scale = InScale; UpdateTransform(); UpdateGear(2); } } void UGObject::SetSkew(const FVector2D& InSkew) { Skew = InSkew; } void UGObject::SetRotation(float InRotation) { if (Rotation != InRotation) { Rotation = InRotation; UpdateTransform(); UpdateGear(3); } } void UGObject::UpdateTransform() { FScale2D Scale2D = FScale2D(Scale); FQuat2D Quat2D = FQuat2D(FMath::DegreesToRadians(Rotation)); FMatrix2x2 Matrix = Concatenate(Quat2D, Scale2D); DisplayObject->SetRenderTransform(FSlateRenderTransform(Matrix, Position)); } void UGObject::SetAlpha(float InAlpha) { if (Alpha != InAlpha) { Alpha = InAlpha; HandleAlphaChanged(); UpdateGear(3); } } void UGObject::SetGrayed(bool InBGrayed) { if (bGrayed != InBGrayed) { bGrayed = InBGrayed; HandleGrayedChanged(); UpdateGear(3); } } void UGObject::SetVisible(bool bInVisible) { if (bVisible != bInVisible) { bVisible = bInVisible; HandleVisibleChanged(); if (Parent.IsValid()) Parent->SetBoundsChangedFlag(); if (Group.IsValid() && Group->IsExcludeInvisibles()) Group->SetBoundsChangedFlag(); } } bool UGObject::InternalVisible() const { return bInternalVisible && (!Group.IsValid() || Group->InternalVisible()); } bool UGObject::InternalVisible2() const { return bVisible && (!Group.IsValid() || Group->InternalVisible2()); } bool UGObject::InternalVisible3() const { return bVisible && bInternalVisible; } bool UGObject::IsTouchable() const { return DisplayObject->IsTouchable(); } void UGObject::SetTouchable(bool bInTouchable) { DisplayObject->SetTouchable(bInTouchable); } void UGObject::SetSortingOrder(int32 InSortingOrder) { if (InSortingOrder < 0) InSortingOrder = 0; if (SortingOrder != InSortingOrder) { int32 old = SortingOrder; SortingOrder = InSortingOrder; if (Parent.IsValid()) Parent->ChildSortingOrderChanged(this, old, SortingOrder); } } void UGObject::SetGroup(UGGroup* InGroup) { if (Group.Get() != InGroup) { if (Group.IsValid()) Group->SetBoundsChangedFlag(); Group = InGroup; if (Group.IsValid()) Group->SetBoundsChangedFlag(); HandleVisibleChanged(); if (Parent.IsValid()) Parent->ChildStateChanged(this); } } const FString& UGObject::GetText() const { return G_EMPTY_STRING; } void UGObject::SetText(const FString& InText) { } const FString& UGObject::GetIcon() const { return G_EMPTY_STRING; } void UGObject::SetIcon(const FString& InIcon) { } void UGObject::SetTooltips(const FString& InTooltips) { Tooltips = InTooltips; if (!Tooltips.IsEmpty()) { On(FUIEvents::RollOver).AddUObject(this, &UGObject::OnRollOverHandler); On(FUIEvents::RollOut).AddUObject(this, &UGObject::OnRollOutHandler); } } void UGObject::OnRollOverHandler(UEventContext* Context) { GetUIRoot()->ShowTooltips(Tooltips); } void UGObject::OnRollOutHandler(UEventContext* Context) { GetUIRoot()->HideTooltips(); } void UGObject::SetDraggable(bool bInDraggable) { if (bDraggable != bInDraggable) { bDraggable = bInDraggable; InitDrag(); } } FBox2D UGObject::GetDragBounds() const { if (DragBounds.IsSet()) return DragBounds.GetValue(); else return FBox2D(FVector2D::ZeroVector, FVector2D::ZeroVector); } void UGObject::SetDragBounds(const FBox2D& InBounds) { if (InBounds.Min == InBounds.Max && InBounds.Min == FVector2D::ZeroVector) DragBounds.Reset(); else DragBounds = InBounds; } void UGObject::StartDrag(int32 UserIndex, int32 PointerIndex) { DragBegin(UserIndex, PointerIndex); } void UGObject::StopDrag() { DragEnd(); } FString UGObject::GetResourceURL() const { if (PackageItem.IsValid()) return "ui://" + PackageItem->Owner->GetID() + PackageItem->ID; else return G_EMPTY_STRING; } FString UGObject::GetResourceName() const { if (PackageItem.IsValid()) return PackageItem->Name; else return G_EMPTY_STRING; } FString UGObject::GetPackageName() const { if (PackageItem.IsValid()) return PackageItem->Owner->GetName(); else return G_EMPTY_STRING; } FVector2D UGObject::LocalToGlobal(const FVector2D& InPoint) { FVector2D Point = InPoint; if (bPivotAsAnchor) Point += Size * Pivot; return DisplayObject->GetCachedGeometry().LocalToAbsolute(Point); } FBox2D UGObject::LocalToGlobalRect(const FBox2D& InRect) { FVector2D v0 = LocalToGlobal(InRect.Min); FVector2D v1 = LocalToGlobal(InRect.Max); return FBox2D(v0, v1); } FVector2D UGObject::LocalToRoot(const FVector2D& InPoint) { return GetUIRoot()->GlobalToLocal(LocalToGlobal(InPoint)); } FBox2D UGObject::LocalToRootRect(const FBox2D& InRect) { return GetUIRoot()->GlobalToLocalRect(LocalToGlobalRect(InRect)); } FVector2D UGObject::GlobalToLocal(const FVector2D& InPoint) { FVector2D Point = DisplayObject->GetCachedGeometry().AbsoluteToLocal(InPoint); if (bPivotAsAnchor) Point -= Size * Pivot; return Point; } FBox2D UGObject::GlobalToLocalRect(const FBox2D& InRect) { FVector2D v0 = GlobalToLocal(InRect.Min); FVector2D v1 = GlobalToLocal(InRect.Max); return FBox2D(v0, v1); } FVector2D UGObject::RootToLocal(const FVector2D& InPoint) { return GlobalToLocal(GetUIRoot()->LocalToGlobal(InPoint)); } FBox2D UGObject::RootToLocalRect(const FBox2D& InRect) { return GlobalToLocalRect(GetUIRoot()->LocalToGlobalRect(InRect)); } void UGObject::AddRelation(UGObject* Obj, ERelationType RelationType, bool bUsePercent) { verifyf(Obj != this, TEXT("Cannot add relation to self")); Relations->Add(Obj, RelationType, bUsePercent); } void UGObject::RemoveRelation(UGObject* Obj, ERelationType RelationType) { Relations->Remove(Obj, RelationType); } const TSharedPtr& UGObject::GetGear(int32 Index) { TSharedPtr& Gear = Gears[Index]; if (!Gear.IsValid()) Gear = FGearBase::Create(this, static_cast(Index)); return Gear; } void UGObject::UpdateGear(int32 Index) { if (bUnderConstruct || bGearLocked) return; const TSharedPtr& Gear = Gears[Index]; if (Gear.IsValid() && Gear->GetController() != nullptr) Gear->UpdateState(); } bool UGObject::CheckGearController(int32 Index, UGController* Controller) { return Gears[Index].IsValid() && Gears[Index]->GetController() == Controller; } void UGObject::UpdateGearFromRelations(int32 Index, const FVector2D& Delta) { if (Gears[Index].IsValid()) Gears[Index]->UpdateFromRelations(Delta); } uint32 UGObject::AddDisplayLock() { const TSharedPtr& GearDisplay = StaticCastSharedPtr(Gears[0]); if (GearDisplay.IsValid() && GearDisplay->GetController() != nullptr) { uint32 ret = GearDisplay->AddLock(); CheckGearDisplay(); return ret; } else return 0; } void UGObject::ReleaseDisplayLock(uint32 Token) { const TSharedPtr& GearDisplay = StaticCastSharedPtr(Gears[0]); if (GearDisplay.IsValid() && GearDisplay->GetController() != nullptr) { GearDisplay->ReleaseLock(Token); CheckGearDisplay(); } } void UGObject::CheckGearDisplay() { if (bHandlingController) return; bool bConnected = !Gears[0].IsValid() || StaticCastSharedPtr(Gears[0])->IsConnected(); if (Gears[8].IsValid() && Gears[8]->GetType() == FGearBase::EType::Display2) bConnected = StaticCastSharedPtr(Gears[8])->Evaluate(bConnected); if (bConnected != bInternalVisible) { bInternalVisible = bConnected; if (Parent.IsValid()) Parent->ChildStateChanged(this); if (Group.IsValid() && Group->IsExcludeInvisibles()) Group->SetBoundsChangedFlag(); } } void UGObject::SetParent(UGObject* InParent) { verifyf(InParent == nullptr || InParent->IsA(), TEXT("Parent must be GComponent")); verifyf(InParent != this, TEXT("Parent must not be self")); if (InParent != nullptr) Cast(InParent)->AddChild(this); else if (Parent.IsValid()) Parent->RemoveChild(this); } void UGObject::SetParentToRoot() { SetParent(GetUIRoot()); } void UGObject::RemoveFromParent() { if (Parent.IsValid()) Parent->RemoveChild(this); } bool UGObject::OnStage() const { return SDisplayObject::IsWidgetOnStage(DisplayObject); } UGRoot* UGObject::GetUIRoot() const { return GetApp()->GetUIRoot(); } UFairyApplication* UGObject::GetApp() const { if (CachedApp == nullptr) const_cast(this)->CachedApp = UFairyApplication::Get(const_cast(this)); return CachedApp; } UWorld* UGObject::GetWorld() const { if (!HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject)) return GetOuter()->GetWorld(); else return nullptr; } UGObject* UGObject::CastTo(TSubclassOf ClassType) const { return const_cast(this); } FNVariant UGObject::GetProp(EObjectPropID PropID) const { switch (PropID) { case EObjectPropID::Text: return FNVariant(GetText()); case EObjectPropID::Icon: return FNVariant(GetIcon()); default: return FNVariant(0); } } void UGObject::SetProp(EObjectPropID PropID, const FNVariant& InValue) { switch (PropID) { case EObjectPropID::Text: return SetText(InValue.AsString()); case EObjectPropID::Icon: return SetIcon(InValue.AsString()); default: break; } } bool UGObject::DispatchEvent(const FName& EventType, const FNVariant& Data) { return GetApp()->DispatchEvent(EventType, DisplayObject.ToSharedRef(), Data); } bool UGObject::HasEventListener(const FName& EventType) const { const FUnifiedEventDelegate& Delegate = const_cast(this)->GetEventDelegate(EventType); return Delegate.Func.IsBound() || (Delegate.DynFunc != nullptr && Delegate.DynFunc->IsBound()); } void UGObject::InvokeEventDelegate(UEventContext* Context) { FUnifiedEventDelegate& Delegate = GetEventDelegate(Context->GetType()); Delegate.Func.Broadcast(Context); if (Delegate.DynFunc != nullptr) Delegate.DynFunc->Broadcast(Context); } UGObject::FUnifiedEventDelegate& UGObject::GetEventDelegate(const FName& EventType) { FUnifiedEventDelegate* Delegate = EventDelegates.Find(EventType); if (Delegate == nullptr) { Delegate = &EventDelegates.Add(EventType); #if (ENGINE_MAJOR_VERSION <= 4) && (ENGINE_MINOR_VERSION < 25) UProperty #else FProperty #endif * Property = GetClass()->FindPropertyByName(FName(*FString("On").Append(EventType.ToString()))); if (Property != nullptr) Delegate->DynFunc = Property->ContainerPtrToValuePtr(this); else Delegate->DynFunc = nullptr; } return *Delegate; } FGUIEventMDelegate& UGObject::On(const FName& EventType) { return GetEventDelegate(EventType).Func; } void UGObject::ConstructFromResource() { } void UGObject::HandlePositionChanged() { DisplayObject->SetPosition(bPivotAsAnchor ? (Position - Size * Pivot) : Position); } void UGObject::HandleSizeChanged() { DisplayObject->SetSize(Size); } void UGObject::HandleAlphaChanged() { DisplayObject->SetRenderOpacity(Alpha); } void UGObject::HandleGrayedChanged() { DisplayObject->SetEnabled(!bGrayed); } void UGObject::HandleVisibleChanged() { DisplayObject->SetVisible(InternalVisible2()); } void UGObject::HandleControllerChanged(UGController* Controller) { bHandlingController = true; for (int32 i = 0; i < 10; i++) { const TSharedPtr& Gear = Gears[i]; if (Gear.IsValid() && Gear->GetController() == Controller) Gear->Apply(); } bHandlingController = false; CheckGearDisplay(); } void UGObject::SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos) { Buffer->Seek(BeginPos, 0); Buffer->Skip(5); ID = Buffer->ReadS(); Name = Buffer->ReadS(); float f1 = Buffer->ReadInt(); float f2 = Buffer->ReadInt(); SetPosition(FVector2D(f1, f2)); if (Buffer->ReadBool()) { InitSize.X = Buffer->ReadInt(); InitSize.Y = Buffer->ReadInt(); SetSize(InitSize, true); } if (Buffer->ReadBool()) { MinSize.X = Buffer->ReadInt(); MaxSize.X = Buffer->ReadInt(); MinSize.Y = Buffer->ReadInt(); MaxSize.Y = Buffer->ReadInt(); } if (Buffer->ReadBool()) { f1 = Buffer->ReadFloat(); f2 = Buffer->ReadFloat(); SetScale(FVector2D(f1, f2)); } if (Buffer->ReadBool()) { f1 = Buffer->ReadFloat(); f2 = Buffer->ReadFloat(); SetSkew(FVector2D(f1, f2)); } if (Buffer->ReadBool()) { f1 = Buffer->ReadFloat(); f2 = Buffer->ReadFloat(); SetPivot(FVector2D(f1, f2), Buffer->ReadBool()); } f1 = Buffer->ReadFloat(); if (f1 != 1) SetAlpha(f1); f1 = Buffer->ReadFloat(); if (f1 != 0) SetRotation(f1); if (!Buffer->ReadBool()) SetVisible(false); if (!Buffer->ReadBool()) SetTouchable(false); if (Buffer->ReadBool()) SetGrayed(true); Buffer->ReadByte(); //blendMode Buffer->ReadByte(); //filter const FString& str = Buffer->ReadS(); if (!str.IsEmpty()) UserData = str; } void UGObject::SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos) { Buffer->Seek(BeginPos, 1); const FString& str = Buffer->ReadS(); if (!str.IsEmpty()) SetTooltips(str); int16 groupId = Buffer->ReadShort(); if (groupId >= 0) Group = Cast(Parent->GetChildAt(groupId)); Buffer->Seek(BeginPos, 2); int16 cnt = Buffer->ReadShort(); for (int32 i = 0; i < cnt; i++) { int16 nextPos = Buffer->ReadShort(); nextPos += Buffer->GetPos(); GetGear(Buffer->ReadByte())->Setup(Buffer); Buffer->SetPos(nextPos); } } void UGObject::InitDrag() { if (bDraggable) { OnTouchBegin.AddUniqueDynamic(this, &UGObject::OnTouchBeginHandler); OnTouchMove.AddUniqueDynamic(this, &UGObject::OnTouchMoveHandler); OnTouchEnd.AddUniqueDynamic(this, &UGObject::OnTouchEndHandler); } else { OnTouchBegin.RemoveDynamic(this, &UGObject::OnTouchBeginHandler); OnTouchMove.RemoveDynamic(this, &UGObject::OnTouchMoveHandler); OnTouchEnd.RemoveDynamic(this, &UGObject::OnTouchEndHandler); } } void UGObject::DragBegin(int32 UserIndex, int32 PointerIndex) { if (DispatchEvent(FUIEvents::DragStart)) return; if (DraggingObject.IsValid()) { UGObject* tmp = DraggingObject.Get(); DraggingObject->StopDrag(); DraggingObject.Reset(); tmp->DispatchEvent(FUIEvents::DragEnd); } GlobalDragStart = GetApp()->GetTouchPosition(UserIndex, PointerIndex); GlobalRect = LocalToGlobalRect(FBox2D(FVector2D::ZeroVector, Size)); DraggingObject = this; bDragTesting = false; GetApp()->AddMouseCaptor(UserIndex, PointerIndex, this); OnTouchMove.AddUniqueDynamic(this, &UGObject::OnTouchMoveHandler); OnTouchEnd.AddUniqueDynamic(this, &UGObject::OnTouchEndHandler); } void UGObject::DragEnd() { if (DraggingObject.Get() == this) { bDragTesting = false; DraggingObject.Reset(); } } void UGObject::OnTouchBeginHandler(UEventContext* Context) { DragTouchStartPos = Context->GetPointerPosition(); bDragTesting = true; Context->CaptureTouch(); } void UGObject::OnTouchMoveHandler(UEventContext* Context) { if (DraggingObject.Get() != this && bDragTesting) { int32 sensitivity; if (FPlatformMisc::DesktopTouchScreen()) sensitivity = FUIConfig::Config.ClickDragSensitivity; else sensitivity = FUIConfig::Config.TouchDragSensitivity; if (FMath::Abs(DragTouchStartPos.X - Context->GetPointerPosition().X) < sensitivity && FMath::Abs(DragTouchStartPos.Y - Context->GetPointerPosition().Y) < sensitivity) return; bDragTesting = false; DragBegin(Context->GetUserIndex(), Context->GetPointerIndex()); } if (DraggingObject.Get() == this) { FVector2D Pos = Context->GetPointerPosition() - GlobalDragStart + GlobalRect.Min; if (DragBounds.IsSet()) { FBox2D rect = GetUIRoot()->LocalToGlobalRect(DragBounds.GetValue()); if (Pos.X < rect.Min.X) Pos.X = rect.Min.X; else if (Pos.X + GlobalRect.GetSize().X > rect.Max.X) { Pos.X = rect.Max.X - GlobalRect.GetSize().X; if (Pos.X < rect.Min.X) Pos.X = rect.Min.X; } if (Pos.Y < rect.Min.Y) Pos.Y = rect.Min.Y; else if (Pos.Y + GlobalRect.GetSize().Y > rect.Max.Y) { Pos.Y = rect.Max.Y - GlobalRect.GetSize().Y; if (Pos.Y < rect.Min.Y) Pos.Y = rect.Min.Y; } } Pos = Parent->GlobalToLocal(Pos); bUpdateInDragging = true; SetPosition(Pos.RoundToVector()); bUpdateInDragging = false; DispatchEvent(FUIEvents::DragMove); } } void UGObject::OnTouchEndHandler(UEventContext* Context) { if (DraggingObject.Get() == this) { DraggingObject.Reset(); DispatchEvent(FUIEvents::DragEnd); } } ================================================ FILE: Source/FairyGUI/Private/UI/GObjectPool.cpp ================================================ #include "UI/GObjectPool.h" #include "UI/GObject.h" #include "UI/UIPackage.h" UGObject* FGObjectPool::GetObject(const FString & URL, UObject* WorldContextObject) { FString URL2 = UUIPackage::NormalizeURL(URL); if (URL2.Len() == 0) return nullptr; UGObject* ret; TArray& arr = Pool.FindOrAdd(URL2); if (arr.Num() > 0) ret = arr.Pop(); else ret = UUIPackage::CreateObjectFromURL(URL2, WorldContextObject); return ret; } void FGObjectPool::ReturnObject(UGObject* Obj) { TArray& arr = Pool.FindOrAdd(Obj->GetResourceURL()); arr.Add(Obj); } void FGObjectPool::AddReferencedObjects(FReferenceCollector& Collector) { for (auto& Elem : Pool) { Collector.AddReferencedObjects(Elem.Value); } } ================================================ FILE: Source/FairyGUI/Private/UI/GProgressBar.cpp ================================================ #include "UI/GProgressBar.h" #include "UI/GImage.h" #include "UI/GLoader.h" #include "Tween/GTween.h" #include "Utils/ByteBuffer.h" UGProgressBar::UGProgressBar() : Max(100) { } UGProgressBar::~UGProgressBar() { } void UGProgressBar::SetTitleType(EProgressTitleType InTitleType) { if (TitleType != InTitleType) { TitleType = InTitleType; Update(Value); } } void UGProgressBar::SetMin(float InMin) { if (Min != InMin) { Min = InMin; Update(Value); } } void UGProgressBar::SetMax(float InMax) { if (Max != InMax) { Max = InMax; Update(Value); } } void UGProgressBar::SetValue(float InValue) { if (Value != InValue) { FGTween::Kill(TweenHandle, false); Value = InValue; Update(Value); } } void UGProgressBar::TweenValue(float InValue, float Duration) { float oldValule; FGTweener* tweener = FGTween::GetTween(TweenHandle); if (tweener != nullptr) { oldValule = tweener->Value.X; tweener->Kill(false); } else oldValule = Value; Value = InValue; TweenHandle = FGTween::To(oldValule, Value, Duration) ->SetEase(EEaseType::Linear) ->OnUpdate(FTweenDelegate::CreateStatic(&FGTweenAction::SetProgress)) ->SetTarget(this) ->GetHandle(); } void UGProgressBar::Update(float InValue) { float percent; if (Max == Min) percent = 0; else percent = FMath::Clamp((InValue - Min) / (Max - Min), 0, 1); if (TitleObject != nullptr) { FString NewTitle; switch (TitleType) { case EProgressTitleType::Percent: NewTitle.AppendInt(FMath::FloorToInt(percent * 100)); NewTitle.AppendChar('%'); break; case EProgressTitleType::ValueMax: NewTitle.AppendInt(FMath::FloorToInt(InValue)); NewTitle.AppendChar('/'); NewTitle.AppendInt(FMath::FloorToInt(Max)); break; case EProgressTitleType::Value: NewTitle.AppendInt(FMath::FloorToInt(InValue)); break; case EProgressTitleType::Max: NewTitle.AppendInt(FMath::FloorToInt(Max)); break; default: break; } TitleObject->SetText(NewTitle); } FVector2D FullSize = GetSize() - BarMaxSizeDelta;; if (!bReverse) { if (BarObjectH != nullptr) { if (!SetFillAmount(BarObjectH, percent)) BarObjectH->SetWidth(FMath::RoundToFloat(FullSize.X * percent)); } if (BarObjectV != nullptr) { if (!SetFillAmount(BarObjectV, percent)) BarObjectV->SetHeight(FMath::RoundToFloat(FullSize.Y * percent)); } } else { if (BarObjectH != nullptr) { if (!SetFillAmount(BarObjectH, 1 - percent)) { BarObjectH->SetWidth(FMath::RoundToFloat(FullSize.X * percent)); BarObjectH->SetX(BarStartPosition.X + (FullSize.X - BarObjectH->GetWidth())); } } if (BarObjectV != nullptr) { if (!SetFillAmount(BarObjectV, 1 - percent)) { BarObjectV->SetHeight(round(FullSize.Y * percent)); BarObjectV->SetY(BarStartPosition.Y + (FullSize.Y - BarObjectV->GetHeight())); } } } } bool UGProgressBar::SetFillAmount(UGObject* Bar, float Amount) { UGImage* image = nullptr; UGLoader* loader = nullptr; if ((image = Cast(Bar)) != nullptr && image->GetFillMethod() != EFillMethod::None) image->SetFillAmount(Amount); else if ((loader = Cast(Bar)) != nullptr && loader->GetFillMethod() != EFillMethod::None) loader->SetFillAmount(Amount); else return false; return true; } void UGProgressBar::HandleSizeChanged() { UGComponent::HandleSizeChanged(); BarMaxSize = GetSize() - BarMaxSizeDelta; if (!bUnderConstruct) Update(Value); } void UGProgressBar::ConstructExtension(FByteBuffer* Buffer) { Buffer->Seek(0, 6); TitleType = (EProgressTitleType)Buffer->ReadByte(); bReverse = Buffer->ReadBool(); TitleObject = GetChild("title"); BarObjectH = GetChild("bar"); BarObjectV = GetChild("bar_v"); if (BarObjectH != nullptr) { BarMaxSize.X = BarObjectH->GetWidth(); BarMaxSizeDelta.X = GetWidth() - BarMaxSize.X; BarStartPosition.X = BarObjectH->GetX(); } if (BarObjectV != nullptr) { BarMaxSize.Y = BarObjectV->GetHeight(); BarMaxSizeDelta.Y = GetHeight() - BarMaxSize.Y; BarStartPosition.Y = BarObjectV->GetY(); } } void UGProgressBar::SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos) { UGComponent::SetupAfterAdd(Buffer, BeginPos); if (!Buffer->Seek(BeginPos, 6)) { Update(Value); return; } if ((EObjectType)Buffer->ReadByte() != PackageItem->ObjectType) { Update(Value); return; } Value = Buffer->ReadInt(); Max = Buffer->ReadInt(); if (Buffer->Version >= 2) Min = Buffer->ReadInt(); Update(Value); } ================================================ FILE: Source/FairyGUI/Private/UI/GRichTextField.cpp ================================================ #include "UI/GRichTextField.h" UGRichTextField::UGRichTextField() { } UGRichTextField::~UGRichTextField() { } ================================================ FILE: Source/FairyGUI/Private/UI/GRoot.cpp ================================================ #include "UI/GRoot.h" #include "Engine/World.h" #include "Engine/GameViewportClient.h" #include "Slate.h" #include "FairyApplication.h" #include "UI/GWindow.h" #include "UI/GGraph.h" #include "UI/UIPackage.h" #include "Widgets/SContainer.h" int32 UGRoot::ContentScaleLevel = 0; class SRootContainer : public SContainer { public: virtual void OnArrangeChildren(const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const override; }; UGRoot* UGRoot::Get(UObject* WorldContextObject) { return UFairyApplication::Get(WorldContextObject)->GetUIRoot(); } UGRoot::UGRoot() { } UGRoot::~UGRoot() { } void UGRoot::AddToViewport() { UGameViewportClient* ViewportClient = GetApp()->GetViewportClient(); verifyf(ViewportClient != nullptr, TEXT("Null Viewport?")); TSharedRef FullScreenCanvas = SNew(SRootContainer).GObject(this); FullScreenCanvas->SetOpaque(false); FullScreenCanvas->AddChild(GetDisplayObject()); ViewportClient->AddViewportWidgetContent(FullScreenCanvas, 100); SetSize(FullScreenCanvas->GetParentWidget()->GetPaintSpaceGeometry().GetLocalSize().RoundToVector()); } void UGRoot::ShowWindow(UGWindow* Window) { AddChild(Window); AdjustModalLayer(); } void UGRoot::HideWindow(UGWindow* Window) { Window->Hide(); } void UGRoot::HideWindowImmediately(UGWindow* Window) { if (Window->GetParent() == this) RemoveChild(Window); AdjustModalLayer(); } void UGRoot::BringToFront(UGWindow* Window) { int32 cnt = NumChildren(); int32 i; if (ModalLayer->GetParent() != nullptr && !Window->IsModal()) i = GetChildIndex(ModalLayer) - 1; else i = cnt - 1; for (; i >= 0; i--) { UGObject* g = GetChildAt(i); if (g == Window) return; if (g->IsA()) break; } if (i >= 0) SetChildIndex(Window, i); } void UGRoot::CloseAllExceptModals() { TArray map; map.Append(Children); for (const auto& child : map) { if (child->IsA() && !((UGWindow*)child)->IsModal()) HideWindowImmediately((UGWindow*)child); } } void UGRoot::CloseAllWindows() { TArray map; map.Append(Children); for (const auto& child : map) { if (child->IsA()) HideWindowImmediately((UGWindow*)child); } } UGWindow* UGRoot::GetTopWindow() const { int32 cnt = NumChildren(); for (int32 i = cnt - 1; i >= 0; i--) { UGObject* child = GetChildAt(i); if (child->IsA()) { return (UGWindow*)child; } } return nullptr; } UGGraph* UGRoot::GetModalLayer() { if (ModalLayer == nullptr) CreateModalLayer(); return ModalLayer; } void UGRoot::CreateModalLayer() { ModalLayer = NewObject(this); ModalLayer->SetSize(Size); ModalLayer->DrawRect(0, FColor::White, FUIConfig::Config.ModalLayerColor); ModalLayer->AddRelation(this, ERelationType::Size); } void UGRoot::AdjustModalLayer() { if (ModalLayer == nullptr) CreateModalLayer(); int32 cnt = NumChildren(); if (ModalWaitPane != nullptr && ModalWaitPane->GetParent() != nullptr) SetChildIndex(ModalWaitPane, cnt - 1); for (int32 i = cnt - 1; i >= 0; i--) { UGObject* child = GetChildAt(i); if (child->IsA() && ((UGWindow*)child)->IsModal()) { if (ModalLayer->GetParent() == nullptr) AddChildAt(ModalLayer, i); else SetChildIndexBefore(ModalLayer, i); return; } } if (ModalLayer->GetParent() != nullptr) RemoveChild(ModalLayer); } bool UGRoot::HasModalWindow() const { return ModalLayer != nullptr && ModalLayer->GetParent() != nullptr; } void UGRoot::ShowModalWait() { GetModalWaitingPane(); if (ModalWaitPane) AddChild(ModalWaitPane); } void UGRoot::CloseModalWait() { if (ModalWaitPane != nullptr && ModalWaitPane->GetParent() != nullptr) RemoveChild(ModalWaitPane); } UGObject* UGRoot::GetModalWaitingPane() { if (!FUIConfig::Config.GlobalModalWaiting.IsEmpty()) { if (ModalWaitPane == nullptr) { ModalWaitPane = UUIPackage::CreateObjectFromURL(FUIConfig::Config.GlobalModalWaiting, this); ModalWaitPane->SetSortingOrder(INT_MAX); } ModalWaitPane->SetSize(GetSize()); ModalWaitPane->AddRelation(this, ERelationType::Size); return ModalWaitPane; } else return nullptr; } bool UGRoot::IsModalWaiting() const { return (ModalWaitPane != nullptr) && ModalWaitPane->OnStage(); } void UGRoot::ShowPopup(UGObject* Popup, UGObject* AtObject, EPopupDirection Direction) { if (PopupStack.Num() > 0) HidePopup(Popup); PopupStack.Add(Popup); if (AtObject != nullptr) { UGObject* p = AtObject; while (p != nullptr) { if (p->GetParent() == this) { if (Popup->GetSortingOrder() < p->GetSortingOrder()) { Popup->SetSortingOrder(p->GetSortingOrder()); } break; } p = p->GetParent(); } } AddChild(Popup); AdjustModalLayer(); if (Popup->IsA() && AtObject == nullptr && Direction == EPopupDirection::Auto) return; FVector2D pos = GetPoupPosition(Popup, AtObject, Direction); Popup->SetPosition(pos); } void UGRoot::TogglePopup(UGObject* Popup, UGObject* AtObject, EPopupDirection Direction) { int32 Index; if (JustClosedPopups.Find(Popup, Index)) return; ShowPopup(Popup, AtObject, Direction); } void UGRoot::HidePopup(UGObject* Popup) { if (Popup != nullptr) { int32 k; if (PopupStack.Find(Popup, k)) { for (int32 i = PopupStack.Num() - 1; i >= k; i--) { ClosePopup(PopupStack.Last().Get()); PopupStack.Pop(); } } } else { for (const auto& it : PopupStack) ClosePopup(it.Get()); PopupStack.Reset(); } } void UGRoot::ClosePopup(UGObject* Popup) { if (Popup != nullptr && Popup->GetParent() != nullptr) { if (Popup->IsA()) ((UGWindow*)Popup)->Hide(); else RemoveChild(Popup); } } void UGRoot::CheckPopups(SWidget* ClickTarget) { JustClosedPopups.Reset(); if (PopupStack.Num() > 0) { bool handled = false; SWidget* Ptr = ClickTarget; SWidget* Top = DisplayObject.Get(); while (Ptr != Top && Ptr != nullptr) { if (Ptr->GetTag() == SDisplayObject::SDisplayObjectTag) { UGObject* Obj = static_cast(Ptr)->GObject.Get(); int32 k; if (PopupStack.Find(Obj, k)) { for (int32 i = PopupStack.Num() - 1; i > k; i--) { ClosePopup(PopupStack.Pop().Get()); } handled = true; break; } } Ptr = Ptr->GetParentWidget().Get(); } if (!handled) { for (int32 i = PopupStack.Num() - 1; i >= 0; i--) { UGObject* popup = PopupStack[i].Get(); if (popup != nullptr) { JustClosedPopups.Add(popup); ClosePopup(popup); } } PopupStack.Reset(); } } } bool UGRoot::HasAnyPopup() const { return PopupStack.Num() > 0; } FVector2D UGRoot::GetPoupPosition(UGObject* Popup, UGObject* AtObject, EPopupDirection Direction) { FVector2D pos; FVector2D size; if (AtObject != nullptr) { pos = AtObject->LocalToGlobal(FVector2D::ZeroVector); pos = this->GlobalToLocal(pos); size = AtObject->LocalToGlobal(AtObject->GetSize()); size = this->GlobalToLocal(size); size -= pos; } else { pos = GlobalToLocal(GetApp()->GetTouchPosition()); } FVector2D RetPosition; RetPosition.X = pos.X; if (RetPosition.X + Popup->GetWidth() > GetWidth()) RetPosition.X += size.X - Popup->GetWidth(); RetPosition.Y = pos.Y + size.Y; if ((Direction == EPopupDirection::Auto && RetPosition.Y + Popup->GetHeight() > GetHeight()) || Direction == EPopupDirection::Up) { RetPosition.Y = pos.Y - Popup->GetHeight() - 1; if (RetPosition.Y < 0) { RetPosition.Y = 0; RetPosition.X += size.X / 2; } } return RetPosition.RoundToVector(); } void UGRoot::ShowTooltips(const FString& Text) { if (DefaultTooltipWin == nullptr) { const FString& resourceURL = FUIConfig::Config.TooltipsWin; if (resourceURL.IsEmpty()) { UE_LOG(LogFairyGUI, Warning, TEXT("UIConfig.tooltipsWin not defined")); return; } DefaultTooltipWin = UUIPackage::CreateObjectFromURL(resourceURL, this); DefaultTooltipWin->SetTouchable(false); } DefaultTooltipWin->SetText(Text); ShowTooltipsWin(DefaultTooltipWin); } void UGRoot::ShowTooltipsWin(UGObject* InTooltipWin) { HideTooltips(); TooltipWin = InTooltipWin; GWorld->GetTimerManager().SetTimer( ShowTooltipsTimerHandle, FTimerDelegate::CreateUObject(this, &UGRoot::DoShowTooltipsWin), 0.1f, false); } void UGRoot::DoShowTooltipsWin() { if (TooltipWin == nullptr) return; FVector2D pt = GetApp()->GetTouchPosition(); FVector2D Pos = pt + FVector2D(10, 20); Pos = GlobalToLocal(Pos); if (Pos.X + TooltipWin->GetWidth() > GetWidth()) Pos.X -= TooltipWin->GetWidth(); if (Pos.Y + TooltipWin->GetHeight() > GetHeight()) { Pos.Y -= TooltipWin->GetHeight() - 1; if (Pos.Y < 0) Pos.Y = 0; } TooltipWin->SetPosition(Pos.RoundToVector()); AddChild(TooltipWin); } void UGRoot::HideTooltips() { if (TooltipWin != nullptr) { if (TooltipWin->GetParent() != nullptr) RemoveChild(TooltipWin); TooltipWin = nullptr; } } void SRootContainer::OnArrangeChildren(const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const { FVector2D LocalSize = AllottedGeometry.GetLocalSize().RoundToVector(); if (LocalSize != GObject->GetSize()) { GObject->SetSize(LocalSize); UE_LOG(LogFairyGUI, Log, TEXT("UIRoot resize to %f,%f"), LocalSize.X, LocalSize.Y); } SContainer::OnArrangeChildren(AllottedGeometry, ArrangedChildren); } ================================================ FILE: Source/FairyGUI/Private/UI/GScrollBar.cpp ================================================ #include "UI/GScrollBar.h" #include "Utils/ByteBuffer.h" UGScrollBar::UGScrollBar() { } UGScrollBar::~UGScrollBar() { } void UGScrollBar::SetScrollPane(UScrollPane* InTarget, bool bInVertical) { Target = InTarget; bVertical = bInVertical; } void UGScrollBar::SetDisplayPerc(float Value) { if (bVertical) { if (!bFixedGripSize) GripObject->SetHeight(FMath::FloorToFloat(Value * BarObject->GetHeight())); GripObject->SetY(round(BarObject->GetY() + (BarObject->GetHeight() - GripObject->GetHeight()) * ScrollPerc)); } else { if (!bFixedGripSize) GripObject->SetWidth(FMath::FloorToFloat(Value * BarObject->GetWidth())); GripObject->SetX(round(BarObject->GetX() + (BarObject->GetWidth() - GripObject->GetWidth()) * ScrollPerc)); } GripObject->SetVisible(Value != 0 && Value != 1); } void UGScrollBar::SetScrollPerc(float Value) { ScrollPerc = Value; if (bVertical) GripObject->SetY(round(BarObject->GetY() + (BarObject->GetHeight() - GripObject->GetHeight()) * ScrollPerc)); else GripObject->SetX(round(BarObject->GetX() + (BarObject->GetWidth() - GripObject->GetWidth()) * ScrollPerc)); } float UGScrollBar::GetMinSize() { if (bVertical) return (ArrowButton1 != nullptr ? ArrowButton1->GetHeight() : 0) + (ArrowButton2 != nullptr ? ArrowButton2->GetHeight() : 0); else return (ArrowButton1 != nullptr ? ArrowButton1->GetWidth() : 0) + (ArrowButton2 != nullptr ? ArrowButton2->GetWidth() : 0); } void UGScrollBar::ConstructExtension(FByteBuffer* buffer) { buffer->Seek(0, 6); bFixedGripSize = buffer->ReadBool(); GripObject = GetChild("grip"); verifyf(GripObject != nullptr, TEXT("FairyGUI: should define grip")); BarObject = GetChild("bar"); verifyf(BarObject != nullptr, TEXT("FairyGUI: should define bar")); ArrowButton1 = GetChild("arrow1"); ArrowButton2 = GetChild("arrow2"); GripObject->On(FUIEvents::TouchBegin).AddUObject(this, &UGScrollBar::OnGripTouchBegin); GripObject->On(FUIEvents::TouchMove).AddUObject(this, &UGScrollBar::OnGripTouchMove); GripObject->On(FUIEvents::TouchEnd).AddUObject(this, &UGScrollBar::OnGripTouchEnd); On(FUIEvents::TouchBegin).AddUObject(this, &UGScrollBar::OnTouchBeginHandler); if (ArrowButton1 != nullptr) ArrowButton1->On(FUIEvents::TouchBegin).AddUObject(this, &UGScrollBar::OnArrowButton1Click); if (ArrowButton2 != nullptr) ArrowButton2->On(FUIEvents::TouchBegin).AddUObject(this, &UGScrollBar::OnArrowButton2Click); } void UGScrollBar::OnTouchBeginHandler(UEventContext* Context) { Context->StopPropagation(); FVector2D pt = GripObject->GlobalToLocal(Context->GetPointerPosition()); if (bVertical) { if (pt.Y < 0) Target->ScrollUp(4, false); else Target->ScrollDown(4, false); } else { if (pt.X < 0) Target->ScrollLeft(4, false); else Target->ScrollRight(4, false); } } void UGScrollBar::OnGripTouchBegin(UEventContext* Context) { if (BarObject == nullptr) return; Context->StopPropagation(); Context->CaptureTouch(); bGripDragging = true; Target->UpdateScrollBarVisible(); FVector2D pt = GlobalToLocal(Context->GetPointerPosition()); DragOffset = pt - GripObject->GetPosition(); } void UGScrollBar::OnGripTouchMove(UEventContext* Context) { FVector2D pt = GlobalToLocal(Context->GetPointerPosition()); if (bVertical) { float curY = pt.Y - DragOffset.Y; float diff = BarObject->GetHeight() - GripObject->GetHeight(); if (diff == 0) Target->SetPercY(0); else Target->SetPercY((curY - BarObject->GetY()) / diff); } else { float curX = pt.X - DragOffset.X; float diff = BarObject->GetWidth() - GripObject->GetWidth(); if (diff == 0) Target->SetPercX(0); else Target->SetPercX((curX - BarObject->GetX()) / diff); } } void UGScrollBar::OnGripTouchEnd(UEventContext* Context) { bGripDragging = false; Target->UpdateScrollBarVisible(); } void UGScrollBar::OnArrowButton1Click(UEventContext* Context) { Context->StopPropagation(); if (bVertical) Target->ScrollUp(); else Target->ScrollLeft(); } void UGScrollBar::OnArrowButton2Click(UEventContext* Context) { Context->StopPropagation(); if (bVertical) Target->ScrollDown(); else Target->ScrollRight(); } ================================================ FILE: Source/FairyGUI/Private/UI/GSlider.cpp ================================================ #include "UI/GSlider.h" #include "Utils/ByteBuffer.h" UGSlider::UGSlider() { } UGSlider::~UGSlider() { } void UGSlider::SetTitleType(EProgressTitleType InTitleType) { if (TitleType != InTitleType) { TitleType = InTitleType; Update(); } } void UGSlider::SetMin(float InMin) { if (Min != InMin) { Min = InMin; Update(); } } void UGSlider::SetMax(float InMax) { if (Max != InMax) { Max = InMax; Update(); } } void UGSlider::SetValue(float InValue) { if (Value != InValue) { Value = InValue; Update(); } } void UGSlider::SetWholeNumbers(bool InFlag) { if (bWholeNumbers != InFlag) { bWholeNumbers = InFlag; Update(); } } void UGSlider::Update() { float Percent = FMath::Min((float)(Value / Max), 1.f); UpdateWithPercent(Percent, false); } void UGSlider::UpdateWithPercent(float Percent, bool bManual) { Percent = FMath::Clamp(Percent, 0.f, 1.f); if (bManual) { float newValue = Min + (Max - Min) * Percent; if (newValue < Min) newValue = Min; if (newValue > Max) newValue = Max; if (bWholeNumbers) { newValue = round(newValue); Percent = FMath::Clamp((float)((newValue - Min) / (Max - Min)), 0.f, 1.f); } if (newValue != Value) { Value = newValue; if (DispatchEvent(FUIEvents::Changed)) return; } } if (TitleObject != nullptr) { FString NewTitle; switch (TitleType) { case EProgressTitleType::Percent: NewTitle.AppendInt(FMath::FloorToInt(Percent * 100)); NewTitle.AppendChar('%'); break; case EProgressTitleType::ValueMax: NewTitle.AppendInt(FMath::FloorToInt(Value)); NewTitle.AppendChar('/'); NewTitle.AppendInt(FMath::FloorToInt(Max)); break; case EProgressTitleType::Value: NewTitle.AppendInt(FMath::FloorToInt(Value)); break; case EProgressTitleType::Max: NewTitle.AppendInt(FMath::FloorToInt(Max)); break; default: break; } TitleObject->SetText(NewTitle); } FVector2D FullSize = GetSize() - BarMaxSizeDelta;; if (!bReverse) { if (BarObjectH != nullptr) BarObjectH->SetWidth(FMath::RoundToFloat(FullSize.X * Percent)); if (BarObjectV != nullptr) BarObjectV->SetHeight(FMath::RoundToFloat(FullSize.Y * Percent)); } else { if (BarObjectH != nullptr) { BarObjectH->SetWidth(FMath::RoundToFloat(FullSize.X * Percent)); BarObjectH->SetX(BarStartPosition.X + (FullSize.X - BarObjectH->GetWidth())); } if (BarObjectV != nullptr) { BarObjectV->SetHeight(round(FullSize.Y * Percent)); BarObjectV->SetY(BarStartPosition.Y + (FullSize.Y - BarObjectV->GetHeight())); } } } void UGSlider::HandleSizeChanged() { UGComponent::HandleSizeChanged(); BarMaxSize = GetSize() - BarMaxSizeDelta; if (!bUnderConstruct) Update(); } void UGSlider::ConstructExtension(FByteBuffer* Buffer) { TitleType = (EProgressTitleType)Buffer->ReadByte(); bReverse = Buffer->ReadBool(); if (Buffer->Version >= 2) { bWholeNumbers = Buffer->ReadBool(); bChangeOnClick = Buffer->ReadBool(); } TitleObject = GetChild("title"); BarObjectH = GetChild("bar"); BarObjectV = GetChild("bar_v"); GripObject = GetChild("grip"); if (BarObjectH != nullptr) { BarMaxSize.X = BarObjectH->GetWidth(); BarMaxSizeDelta.X = GetWidth() - BarMaxSize.X; BarStartPosition.X = BarObjectH->GetX(); } if (BarObjectV != nullptr) { BarMaxSize.Y = BarObjectV->GetHeight(); BarMaxSizeDelta.Y = GetHeight() - BarMaxSize.Y; BarStartPosition.Y = BarObjectV->GetY(); } if (GripObject != nullptr) { GripObject->On(FUIEvents::TouchBegin).AddUObject(this, &UGSlider::OnGripTouchBegin); GripObject->On(FUIEvents::TouchMove).AddUObject(this, &UGSlider::OnGripTouchMove); } On(FUIEvents::TouchBegin).AddUObject(this, &UGSlider::OnTouchBeginHandler); } void UGSlider::SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos) { UGComponent::SetupAfterAdd(Buffer, BeginPos); if (!Buffer->Seek(BeginPos, 6)) { Update(); return; } if ((EObjectType)Buffer->ReadByte() != PackageItem->ObjectType) { Update(); return; } Value = Buffer->ReadInt(); Max = Buffer->ReadInt(); if (Buffer->Version >= 2) Min = Buffer->ReadInt(); Update(); } void UGSlider::OnTouchBeginHandler(UEventContext* Context) { if (!bChangeOnClick) return; if (Context->GetMouseButton() != EKeys::LeftMouseButton) return; FVector2D pt = GripObject->GlobalToLocal(Context->GetPointerPosition()); float percent = FMath::Clamp((float)((Value - Min) / (Max - Min)), 0.f, 1.f); float delta = 0; if (BarObjectH != nullptr) delta = pt.X / BarMaxSize.X; if (BarObjectV != nullptr) delta = pt.Y / BarMaxSize.Y; if (bReverse) percent -= delta; else percent += delta; UpdateWithPercent(percent, true); } void UGSlider::OnGripTouchBegin(UEventContext* Context) { if (Context->GetMouseButton() != EKeys::LeftMouseButton) return; bCanDrag = true; Context->StopPropagation(); Context->CaptureTouch(); ClickPos = GlobalToLocal(Context->GetPointerPosition()); ClickPercent = FMath::Clamp((float)((Value - Min) / (Max - Min)), 0.f, 1.f); } void UGSlider::OnGripTouchMove(UEventContext* Context) { if (!bCanDrag) return; FVector2D pt = GlobalToLocal(Context->GetPointerPosition()); FVector2D delta = pt - ClickPos; if (bReverse) { delta.X = -delta.X; delta.Y = -delta.Y; } float percent; if (BarObjectH != nullptr) percent = ClickPercent + delta.X / BarMaxSize.X; else percent = ClickPercent + delta.Y / BarMaxSize.Y; UpdateWithPercent(percent, true); } ================================================ FILE: Source/FairyGUI/Private/UI/GTextField.cpp ================================================ #include "UI/GTextField.h" #include "UI/GRichTextField.h" #include "Utils/ByteBuffer.h" #include "Utils/UBBParser.h" #include "Widgets/STextField.h" UGTextField::UGTextField() { if (!HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject)) { DisplayObject = Content = SNew(STextField).GObject(this); bSupportHTML = IsA(); DisplayObject->SetInteractable(bSupportHTML); } } UGTextField::~UGTextField() { } void UGTextField::SetText(const FString& InText) { if (!bFormatApplied) ApplyFormat(); Text = InText; if (bUBBEnabled) { FString parsedText = FUBBParser::DefaultParser.Parse(Text); if (TemplateVars.IsSet()) parsedText = ParseTemplate(parsedText); Content->SetText(parsedText, true); } else { if (TemplateVars.IsSet()) Content->SetText(ParseTemplate(Text), bSupportHTML); else Content->SetText(Text, bSupportHTML); } Content->SetMaxWidth(MaxSize.X); UpdateSize(); UpdateGear(6); } void UGTextField::SetUBBEnabled(bool bFlag) { if (bUBBEnabled != bFlag) { bUBBEnabled = bFlag; SetText(Text); } } EAutoSizeType UGTextField::GetAutoSize() const { return Content->GetAutoSize(); } void UGTextField::SetAutoSize(EAutoSizeType InAutoSize) { Content->SetAutoSize(InAutoSize); } bool UGTextField::IsSingleLine() const { return Content->IsSingleLine(); } void UGTextField::SetSingleLine(bool bFlag) { Content->SetSingleLine(bFlag); } FNTextFormat& UGTextField::GetTextFormat() { return Content->GetTextFormat(); } void UGTextField::SetTextFormat(const FNTextFormat& InTextFormat) { Content->SetTextFormat(InTextFormat); bFormatApplied = true; UpdateGear(4); } void UGTextField::ApplyFormat() { SetTextFormat(Content->GetTextFormat()); } FVector2D UGTextField::GetTextSize() { return Content->GetTextSize(); } void UGTextField::UpdateSize() { if (Content->GetAutoSize() == EAutoSizeType::Both || Content->GetAutoSize() == EAutoSizeType::Height) Content->GetTextSize(); //force text layout update } UGTextField* UGTextField::SetVar(const FString& VarKey, const FString& VarValue) { if (!TemplateVars.IsSet()) TemplateVars.Emplace(); TemplateVars.GetValue().Add(VarKey, VarValue); return this; } void UGTextField::FlushVars() { SetText(Text); } FString UGTextField::ParseTemplate(const FString& Template) { int32 pos1 = 0, pos2 = 0; int32 pos3; FString tag; FString value; FString buffer; TMap& Vars = TemplateVars.GetValue(); while ((pos2 = Template.Find("{", ESearchCase::CaseSensitive, ESearchDir::FromStart, pos1)) != -1) { if (pos2 > 0 && Template[pos2 - 1] == '\\') { buffer.Append(*Template + pos1, pos2 - pos1 - 1); buffer.AppendChar('{'); pos1 = pos2 + 1; continue; } buffer.Append(*Template + pos1, pos2 - pos1); pos1 = pos2; pos2 = Template.Find("}", ESearchCase::CaseSensitive, ESearchDir::FromStart, pos1); if (pos2 == -1) break; if (pos2 == pos1 + 1) { buffer.Append(*Template + pos1, 2); pos1 = pos2 + 1; continue; } tag = Template.Mid(pos1 + 1, pos2 - pos1 - 1); if (tag.FindChar('=', pos3)) { FString* ptr = Vars.Find(tag.Mid(0, pos3)); if (ptr != nullptr) buffer.Append(*ptr); else buffer.Append(tag.Mid(pos3 + 1)); } else { FString* ptr = Vars.Find(tag); if (ptr != nullptr) buffer.Append(*ptr); } pos1 = pos2 + 1; } if (pos1 < Template.Len()) buffer.Append(Template.Mid(pos1, Template.Len() - pos1)); return buffer; } FNVariant UGTextField::GetProp(EObjectPropID PropID) const { switch (PropID) { case EObjectPropID::Color: return FNVariant(Content->GetTextFormat().Color); case EObjectPropID::OutlineColor: return FNVariant(Content->GetTextFormat().OutlineColor); case EObjectPropID::FontSize: return FNVariant(Content->GetTextFormat().Size); default: return UGObject::GetProp(PropID); } } void UGTextField::SetProp(EObjectPropID PropID, const FNVariant& InValue) { switch (PropID) { case EObjectPropID::Color: Content->GetTextFormat().Color = InValue.AsColor(); ApplyFormat(); break; case EObjectPropID::OutlineColor: Content->GetTextFormat().OutlineColor = InValue.AsColor(); ApplyFormat(); break; case EObjectPropID::FontSize: Content->GetTextFormat().Size = InValue.AsInt(); ApplyFormat(); break; default: UGObject::SetProp(PropID, InValue); break; } } void UGTextField::SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos) { UGObject::SetupBeforeAdd(Buffer, BeginPos); Buffer->Seek(BeginPos, 5); FNTextFormat& TextFormat = Content->GetTextFormat(); TextFormat.Face = Buffer->ReadS(); TextFormat.Size = Buffer->ReadShort(); TextFormat.Color = Buffer->ReadColor(); TextFormat.Align = (EAlignType)Buffer->ReadByte(); TextFormat.VerticalAlign = (EVerticalAlignType)Buffer->ReadByte(); TextFormat.LineSpacing = Buffer->ReadShort(); TextFormat.LetterSpacing = Buffer->ReadShort(); bUBBEnabled = Buffer->ReadBool(); SetAutoSize((EAutoSizeType)Buffer->ReadByte()); TextFormat.bUnderline = Buffer->ReadBool(); TextFormat.bItalic = Buffer->ReadBool(); TextFormat.bBold = Buffer->ReadBool(); if (Buffer->ReadBool()) SetSingleLine(true); if (Buffer->ReadBool()) { TextFormat.OutlineColor = Buffer->ReadColor(); TextFormat.OutlineSize = Buffer->ReadFloat(); } if (Buffer->ReadBool()) { TextFormat.ShadowColor = Buffer->ReadColor(); float f1 = Buffer->ReadFloat(); float f2 = Buffer->ReadFloat(); TextFormat.ShadowOffset = FVector2D(f1, f2); } if (Buffer->ReadBool()) TemplateVars.Emplace(); } void UGTextField::SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos) { UGObject::SetupAfterAdd(Buffer, BeginPos); ApplyFormat(); Buffer->Seek(BeginPos, 6); const FString& str = Buffer->ReadS(); if (!str.IsEmpty()) SetText(str); } ================================================ FILE: Source/FairyGUI/Private/UI/GTextInput.cpp ================================================ #include "UI/GTextInput.h" #include "Utils/ByteBuffer.h" #include "Utils/UBBParser.h" #include "Widgets/STextInput.h" UGTextInput::UGTextInput() { if (!HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject)) { DisplayObject = Content = SNew(STextInput).GObject(this); Content->SetOnTextChanged(FOnTextChanged::CreateLambda([this](const FText& InText) { Text = InText.ToString(); })); Content->SetOnTextCommitted(FOnTextCommitted::CreateLambda([this](const FText& InText, ETextCommit::Type InType) { if (InType == ETextCommit::OnEnter) DispatchEvent(FUIEvents::Submit); })); } } UGTextInput::~UGTextInput() { } TSharedRef UGTextInput::GetInputWidget() const { return StaticCastSharedRef(Content->Widget); } void UGTextInput::SetText(const FString& InText) { Content->Widget->SetText(FText::FromString(InText)); } bool UGTextInput::IsSingleLine() const { return false; } void UGTextInput::SetSingleLine(bool bFlag) { Content->SetSingleLine(bFlag); } void UGTextInput::SetTextFormat(const FNTextFormat& InTextFormat) { Content->SetTextFormat(InTextFormat); } void UGTextInput::ApplyFormat() { Content->SetTextFormat(TextFormat); } void UGTextInput::SetPrompt(const FString& InPrompt) { Content->Widget->SetHintText(FText::FromString(FUBBParser::DefaultParser.Parse(InPrompt, true))); } void UGTextInput::SetPassword(bool bInPassword) { Content->SetPassword(bInPassword); } void UGTextInput::SetKeyboardType(int32 InKeyboardType) { } void UGTextInput::SetMaxLength(int32 InMaxLength) { } void UGTextInput::SetRestrict(const FString& InRestrict) { } void UGTextInput::NotifyTextChanged(const FText& InText) { Text = InText.ToString(); } FNVariant UGTextInput::GetProp(EObjectPropID PropID) const { switch (PropID) { case EObjectPropID::Color: return FNVariant(TextFormat.Color); case EObjectPropID::OutlineColor: return FNVariant(TextFormat.OutlineColor); case EObjectPropID::FontSize: return FNVariant(TextFormat.Size); default: return UGObject::GetProp(PropID); } } void UGTextInput::SetProp(EObjectPropID PropID, const FNVariant& InValue) { switch (PropID) { case EObjectPropID::Color: TextFormat.Color = InValue.AsColor(); ApplyFormat(); break; case EObjectPropID::OutlineColor: TextFormat.OutlineColor = InValue.AsColor(); ApplyFormat(); break; case EObjectPropID::FontSize: TextFormat.Size = InValue.AsInt(); ApplyFormat(); break; default: UGObject::SetProp(PropID, InValue); break; } } void UGTextInput::SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos) { UGObject::SetupBeforeAdd(Buffer, BeginPos); Buffer->Seek(BeginPos, 5); TextFormat.Face = Buffer->ReadS(); TextFormat.Size = Buffer->ReadShort(); TextFormat.Color = Buffer->ReadColor(); TextFormat.Align = (EAlignType)Buffer->ReadByte(); TextFormat.VerticalAlign = (EVerticalAlignType)Buffer->ReadByte(); TextFormat.LineSpacing = Buffer->ReadShort(); TextFormat.LetterSpacing = Buffer->ReadShort(); Buffer->ReadBool(); //bUBBEnabled Buffer->ReadByte(); //AutoSize TextFormat.bUnderline = Buffer->ReadBool(); TextFormat.bItalic = Buffer->ReadBool(); TextFormat.bBold = Buffer->ReadBool(); if (Buffer->ReadBool()) SetSingleLine(true); if (Buffer->ReadBool()) { TextFormat.OutlineColor = Buffer->ReadColor(); TextFormat.OutlineSize = Buffer->ReadFloat(); } if (Buffer->ReadBool()) { TextFormat.ShadowColor = Buffer->ReadColor(); float f1 = Buffer->ReadFloat(); float f2 = Buffer->ReadFloat(); TextFormat.ShadowOffset = FVector2D(f1, -f2); } Buffer->ReadBool(); //TemplateVars; Buffer->Seek(BeginPos, 4); const FString* str; if ((str = Buffer->ReadSP()) != nullptr) SetPrompt(*str); if ((str = Buffer->ReadSP()) != nullptr) SetRestrict(*str); int32 iv = Buffer->ReadInt(); if (iv != 0) SetMaxLength(iv); iv = Buffer->ReadInt(); if (iv != 0) SetKeyboardType(iv); if (Buffer->ReadBool()) SetPassword(true); } void UGTextInput::SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos) { UGObject::SetupAfterAdd(Buffer, BeginPos); ApplyFormat(); Buffer->Seek(BeginPos, 6); const FString& str = Buffer->ReadS(); SetText(str); } ================================================ FILE: Source/FairyGUI/Private/UI/GTree.cpp ================================================ #include "UI/GTree.h" #include "Utils/ByteBuffer.h" #include "UI/GController.h" #include "UI/GObjectPool.h" UGTree::UGTree() : Indent(30) { if (!HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject)) { RootNode = UGTreeNode::CreateNode(true); RootNode->SetTree(this); RootNode->SetExpaned(true); } } UGTree::~UGTree() { } UGTreeNode* UGTree::GetSelectedNode() const { int32 i = GetSelectedIndex(); if (i != -1) return GetChildAt(i)->TreeNode; else return nullptr; } void UGTree::GetSelectedNodes(TArray& Result) const { TArray ids; GetSelection(ids); for (auto& it : ids) { UGTreeNode* Node = GetChildAt(it)->TreeNode; Result.Add(Node); } } void UGTree::SelectNode(UGTreeNode* Node, bool bScrollItToView) { UGTreeNode* ParentNode = Node->Parent.Get(); while (ParentNode != nullptr && ParentNode != RootNode) { ParentNode->SetExpaned(true); ParentNode = ParentNode->GetParent(); } if (Node->Cell != nullptr) AddSelection(GetChildIndex(Node->Cell), bScrollItToView); } void UGTree::UnselectNode(UGTreeNode* Node) { if (Node->Cell != nullptr) RemoveSelection(GetChildIndex(Node->Cell)); } void UGTree::ExpandAll(UGTreeNode* FolderNode) { FolderNode->SetExpaned(true); for (auto& it : FolderNode->Children) { if (it->IsFolder()) ExpandAll(it); } } void UGTree::CollapseAll(UGTreeNode* FolderNode) { if (FolderNode != RootNode) FolderNode->SetExpaned(false); for (auto& it : FolderNode->Children) { if (it->IsFolder()) CollapseAll(it); } } void UGTree::CreateCell(UGTreeNode* Node) { const FString& url = Node->ResourceURL.IsEmpty() ? GetDefaultItem() : Node->ResourceURL; UGComponent* Child = GetItemPool()->GetObject(url, this)->As(); verifyf(Child != nullptr, TEXT("Unable to create tree cell")); Child->TreeNode = Node; Node->Cell = Child; UGObject* IndentObj = Node->Cell->GetChild("indent"); if (IndentObj != nullptr) IndentObj->SetWidth((Node->Level - 1) * Indent); UGController* cc; cc = Child->GetController("expanded"); if (cc != nullptr) { cc->OnChanged().AddUObject(this, &UGTree::OnExpandedStateChanged); cc->SetSelectedIndex(Node->IsExpanded() ? 1 : 0); } cc = Child->GetController("leaf"); if (cc != nullptr) cc->SetSelectedIndex(Node->IsFolder() ? 0 : 1); if (Node->IsFolder()) Child->OnTouchBegin.AddUniqueDynamic(this, &UGTree::OnCellTouchBegin); TreeNodeRenderer.ExecuteIfBound(Node, Child); } void UGTree::AfterInserted(UGTreeNode* Node) { if (Node->Cell == nullptr) CreateCell(Node); int32 Index = GetInsertIndexForNode(Node); AddChildAt(Node->Cell, Index); TreeNodeRenderer.ExecuteIfBound(Node, Node->Cell); if (Node->IsFolder() && Node->IsExpanded()) CheckChildren(Node, Index); } int32 UGTree::GetInsertIndexForNode(UGTreeNode* Node) { UGTreeNode* PrevNode = Node->GetPrevSibling(); if (PrevNode == nullptr) PrevNode = Node->GetParent(); int32 InsertIndex; if (PrevNode->Cell != nullptr) InsertIndex = GetChildIndex(PrevNode->Cell) + 1; else InsertIndex = 0; int32 myLevel = Node->Level; int32 cnt = NumChildren(); for (int32 i = InsertIndex; i < cnt; i++) { UGTreeNode* TestNode = GetChildAt(i)->TreeNode; if (TestNode->Level <= myLevel) break; InsertIndex++; } return InsertIndex; } void UGTree::AfterRemoved(UGTreeNode* Node) { RemoveNode(Node); } void UGTree::AfterExpanded(UGTreeNode* Node) { if (Node == RootNode) { CheckChildren(RootNode, 0); return; } OnTreeNodeWillExpand.ExecuteIfBound(Node, true); if (Node->Cell == nullptr) return; TreeNodeRenderer.ExecuteIfBound(Node, Node->Cell); UGController* cc = Node->Cell->GetController("expanded"); if (cc != nullptr) cc->SetSelectedIndex(1); if (Node->Cell->GetParent() != nullptr) CheckChildren(Node, GetChildIndex(Node->Cell)); } void UGTree::AfterCollapsed(UGTreeNode* Node) { if (Node == RootNode) { CheckChildren(RootNode, 0); return; } OnTreeNodeWillExpand.ExecuteIfBound(Node, false); if (Node->Cell == nullptr) return; TreeNodeRenderer.ExecuteIfBound(Node, Node->Cell); UGController* cc = Node->Cell->GetController("expanded"); if (cc != nullptr) cc->SetSelectedIndex(0); if (Node->Cell->GetParent() != nullptr) HideFolderNode(Node); } void UGTree::AfterMoved(UGTreeNode* Node) { int32 startIndex = GetChildIndex(Node->Cell); int32 endIndex; if (Node->IsFolder()) endIndex = GetFolderEndIndex(startIndex, Node->Level); else endIndex = startIndex + 1; int32 insertIndex = GetInsertIndexForNode(Node); int32 cnt = endIndex - startIndex; if (insertIndex < startIndex) { for (int32 i = 0; i < cnt; i++) { UGObject* obj = GetChildAt(startIndex + i); SetChildIndex(obj, insertIndex + i); } } else { for (int32 i = 0; i < cnt; i++) { UGObject* obj = GetChildAt(startIndex); SetChildIndex(obj, insertIndex); } } } int32 UGTree::GetFolderEndIndex(int32 StartIndex, int32 Level) { int32 cnt = NumChildren(); for (int32 i = StartIndex + 1; i < cnt; i++) { UGTreeNode* Node = GetChildAt(i)->TreeNode; if (Node->Level <= Level) return i; } return cnt; } int32 UGTree::CheckChildren(UGTreeNode* FolderNode, int32 Index) { int32 cnt = FolderNode->NumChildren(); for (int32 i = 0; i < cnt; i++) { Index++; UGTreeNode* Node = FolderNode->GetChildAt(i); if (Node->Cell == nullptr) CreateCell(Node); if (Node->Cell->GetParent() == nullptr) AddChildAt(Node->Cell, Index); if (Node->IsFolder() && Node->IsExpanded()) Index = CheckChildren(Node, Index); } return Index; } void UGTree::HideFolderNode(UGTreeNode* FolderNode) { int32 cnt = FolderNode->NumChildren(); for (int32 i = 0; i < cnt; i++) { UGTreeNode* Node = FolderNode->GetChildAt(i); if (Node->Cell != nullptr && Node->Cell->GetParent() != nullptr) RemoveChild(Node->Cell); if (Node->IsFolder() && Node->IsExpanded()) HideFolderNode(Node); } } void UGTree::RemoveNode(UGTreeNode* Node) { if (Node->Cell != nullptr) { if (Node->Cell->GetParent() != nullptr) RemoveChild(Node->Cell); GetItemPool()->ReturnObject(Node->Cell); Node->Cell->TreeNode = nullptr; Node->Cell = nullptr; } if (Node->IsFolder()) { int32 cnt = Node->NumChildren(); for (int32 i = 0; i < cnt; i++) { UGTreeNode* Node2 = Node->GetChildAt(i); RemoveNode(Node2); } } } void UGTree::OnCellTouchBegin(UEventContext* Context) { UGTreeNode* Node = Context->GetSender()->TreeNode; bExpandedStatusInEvt = Node->IsExpanded(); } void UGTree::OnExpandedStateChanged(UGController* Controller) { UGTreeNode* Node = Cast(Controller->GetOuter())->TreeNode; Node->SetExpaned(Controller->GetSelectedIndex() == 1); } void UGTree::DispatchItemEvent(UGObject* Obj, UEventContext* Context) { if (ClickToExpand != 0) { UGTreeNode* Node = Obj->TreeNode; if (Node != nullptr && bExpandedStatusInEvt == Node->IsExpanded()) { if (ClickToExpand == 2) { if (Context->IsDoubleClick()) Node->SetExpaned(!Node->IsExpanded()); } else Node->SetExpaned(!Node->IsExpanded()); } } Super::DispatchItemEvent(Obj, Context); } void UGTree::SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos) { Super::SetupBeforeAdd(Buffer, BeginPos); Buffer->Seek(BeginPos, 9); Indent = Buffer->ReadInt(); ClickToExpand = Buffer->ReadByte(); } void UGTree::ReadItems(FByteBuffer* Buffer) { int32 nextPos; FString str; bool bIsFolder; UGTreeNode* lastNode = nullptr; int32 level; int32 prevLevel = 0; int32 cnt = Buffer->ReadShort(); for (int32 i = 0; i < cnt; i++) { nextPos = Buffer->ReadShort(); nextPos += Buffer->GetPos(); str = Buffer->ReadS(); if (!str.IsEmpty()) { str = GetDefaultItem(); if (str.IsEmpty()) { Buffer->SetPos(nextPos); continue; } } bIsFolder = Buffer->ReadBool(); level = Buffer->ReadByte(); UGTreeNode* node = UGTreeNode::CreateNode(bIsFolder, str); node->SetExpaned(true); if (i == 0) RootNode->AddChild(node); else { if (level > prevLevel) lastNode->AddChild(node); else if (level < prevLevel) { for (int32 j = level; j <= prevLevel; j++) lastNode = lastNode->GetParent(); lastNode->AddChild(node); } else lastNode->GetParent()->AddChild(node); } lastNode = node; prevLevel = level; SetupItem(Buffer, node->Cell); Buffer->SetPos(nextPos); } } ================================================ FILE: Source/FairyGUI/Private/UI/GTreeNode.cpp ================================================ #include "UI/GTreeNode.h" #include "UI/GComponent.h" #include "UI/GTree.h" UGTreeNode* UGTreeNode::CreateNode(bool bIsFolder, const FString& ResourceURL) { UGTreeNode* Node = NewObject(); Node->bIsFolder = bIsFolder; Node->ResourceURL = ResourceURL; return Node; } UGTreeNode::UGTreeNode() { } UGTreeNode::~UGTreeNode() { } void UGTreeNode::SetParent(UGTreeNode* InParent) { verifyf(InParent == nullptr || InParent->IsFolder(), TEXT("Parent must be a folder node")); verifyf(InParent != this, TEXT("Parent must not be self")); if (InParent != nullptr) InParent->AddChild(this); else if (Parent.IsValid()) Parent->RemoveChild(this); } void UGTreeNode::SetExpaned(bool bInExpanded) { if (!bIsFolder) return; if (bExpanded != bInExpanded) { bExpanded = bInExpanded; if (Tree.IsValid()) { if (bExpanded) Tree->AfterExpanded(this); else Tree->AfterCollapsed(this); } } } const FString& UGTreeNode::GetText() const { if (Cell != nullptr) return Cell->GetText(); else return G_EMPTY_STRING; } void UGTreeNode::SetText(const FString& InText) { if (Cell != nullptr) return Cell->SetText(InText); } const FString& UGTreeNode::GetIcon() const { if (Cell != nullptr) return Cell->GetIcon(); else return G_EMPTY_STRING; } void UGTreeNode::SetIcon(const FString& InIcon) { if (Cell != nullptr) return Cell->SetIcon(InIcon); } UGTreeNode* UGTreeNode::AddChild(UGTreeNode* Child) { AddChildAt(Child, Children.Num()); return Child; } UGTreeNode* UGTreeNode::AddChildAt(UGTreeNode* Child, int32 Index) { verifyf(Child != nullptr, TEXT("Argument must be non-nil")); if (Child->Parent == this) { SetChildIndex(Child, Index); } else { if (Child->Parent.IsValid()) Child->Parent->RemoveChild(Child); Child->Parent = this; int32 cnt = Children.Num(); if (Index == cnt) Children.Add(Child); else Children.Insert(Child, Index); Child->Level = Level + 1; Child->SetTree(Tree.Get()); if ((Tree.IsValid() && this == Tree->GetRootNode()) || (Cell != nullptr && Cell->GetParent() != nullptr && bExpanded)) Tree->AfterInserted(Child); } return Child; } void UGTreeNode::RemoveChild(UGTreeNode* Child) { verifyf(Child != nullptr, TEXT("Argument must be non-nil")); int32 ChildIndex = Children.Find(Child); if (ChildIndex != INDEX_NONE) RemoveChildAt(ChildIndex); } void UGTreeNode::RemoveChildAt(int32 Index) { verifyf(Index >= 0 && Index < Children.Num(), TEXT("Invalid child index")); UGTreeNode* Child = Children[Index]; Child->Parent = nullptr; if (Tree.IsValid()) { Child->SetTree(nullptr); Tree->AfterRemoved(Child); } Children.RemoveAt(Index); } void UGTreeNode::RemoveChildren(int32 BeginIndex, int32 EndIndex) { if (EndIndex < 0 || EndIndex >= Children.Num()) EndIndex = Children.Num() - 1; for (int32 i = BeginIndex; i <= EndIndex; ++i) RemoveChildAt(BeginIndex); } UGTreeNode* UGTreeNode::GetChildAt(int32 Index) const { verifyf(Index >= 0 && Index < Children.Num(), TEXT("Invalid child index")); return Children[Index]; } UGTreeNode* UGTreeNode::GetPrevSibling() const { if (!Parent.IsValid()) return nullptr; int32 i = Parent->Children.IndexOfByKey(this); if (i <= 0) return nullptr; return Parent->Children[i - 1]; } UGTreeNode* UGTreeNode::GetNextSibling() const { if (!Parent.IsValid()) return nullptr; int32 i = Parent->Children.IndexOfByKey(this); if (i < 0 || i >= Parent->Children.Num() - 1) return nullptr; return Parent->Children[i + 1]; } int32 UGTreeNode::GetChildIndex(const UGTreeNode* Child) const { verifyf(Child != nullptr, TEXT("Argument must be non-nil")); return Children.IndexOfByKey(Child); } void UGTreeNode::SetChildIndex(UGTreeNode* Child, int32 Index) { verifyf(Child != nullptr, TEXT("Argument must be non-nil")); int32 OldIndex = Children.Find(Child); verifyf(OldIndex != -1, TEXT("Not a child of this container")); int32 cnt = Children.Num(); if (Index < 0) Index = 0; else if (Index > cnt) Index = cnt; if (OldIndex == Index) return; Children.RemoveAt(OldIndex); Children.Insert(Child, Index); if ((Tree.IsValid() && this == Tree->RootNode) || (Cell != nullptr && Cell->GetParent() != nullptr && bExpanded)) Tree->AfterMoved(Child); } void UGTreeNode::SwapChildren(UGTreeNode* Child1, UGTreeNode* Child2) { int32 Index1 = Children.Find(Child1); int32 Index2 = Children.Find(Child2); verifyf(Index1 != -1, TEXT("Not a child of this container")); verifyf(Index2 != -1, TEXT("Not a child of this container")); SwapChildrenAt(Index1, Index2); } void UGTreeNode::SwapChildrenAt(int32 Index1, int32 Index2) { UGTreeNode* Child1 = Children[Index1]; UGTreeNode* Child2 = Children[Index2]; SetChildIndex(Child1, Index2); SetChildIndex(Child2, Index1); } int32 UGTreeNode::NumChildren() const { return Children.Num(); } void UGTreeNode::SetTree(UGTree* InTree) { Tree = InTree; if (Tree.IsValid() && Tree->OnTreeNodeWillExpand.IsBound() && bExpanded) Tree->OnTreeNodeWillExpand.Execute(this, true); if (bIsFolder) { for (auto& Child : Children) { Child->Level = Level + 1; Child->SetTree(InTree); } } } ================================================ FILE: Source/FairyGUI/Private/UI/GWindow.cpp ================================================ #include "UI/GWindow.h" #include "UI/GGraph.h" #include "UI/GRoot.h" #include "UI/UIPackage.h" UGWindow* UGWindow::CreateWindow(const FString& PackageName, const FString& ResourceName, UObject* WorldContextObject) { UGObject* ContentPane = UUIPackage::CreateObject(PackageName, ResourceName, WorldContextObject); verifyf(ContentPane->IsA(), TEXT("Window content should be a component")); UGWindow* Window = NewObject(WorldContextObject); Window->SetContentPane(Cast(ContentPane)); return Window; } UGWindow::UGWindow() { bBringToFontOnClick = FUIConfig::Config.BringWindowToFrontOnClick; On(FUIEvents::AddedToStage).AddUObject(this, &UGWindow::OnAddedToStageHandler); On(FUIEvents::RemovedFromStage).AddUObject(this, &UGWindow::OnRemovedFromStageHandler); On(FUIEvents::TouchBegin).AddUObject(this, &UGWindow::OnTouchBeginHandler); } UGWindow::~UGWindow() { } void UGWindow::SetContentPane(UGComponent* Obj) { if (ContentPane != Obj) { if (ContentPane != nullptr) { RemoveChild(ContentPane); FrameObject = nullptr; } ContentPane = Obj; if (ContentPane != nullptr) { AddChild(ContentPane); SetSize(ContentPane->GetSize()); ContentPane->AddRelation(this, ERelationType::Size); FrameObject = Cast(ContentPane->GetChild("frame")); if (FrameObject != nullptr) { SetCloseButton(FrameObject->GetChild("closeButton")); SetDragArea(FrameObject->GetChild("dragArea")); SetContentArea(FrameObject->GetChild("contentArea")); } } else FrameObject = nullptr; } } void UGWindow::SetCloseButton(UGObject * Obj) { if (CloseButton != Obj) { if (CloseButton != nullptr) CloseButton->OnClick.RemoveDynamic(this, &UGWindow::CloseEventHandler); CloseButton = Obj; if (CloseButton != nullptr) CloseButton->OnClick.AddUniqueDynamic(this, &UGWindow::CloseEventHandler); } } void UGWindow::SetDragArea(UGObject * Obj) { if (DragArea != Obj) { if (DragArea != nullptr) { DragArea->SetDraggable(false); DragArea->OnDragStart.RemoveDynamic(this, &UGWindow::OnDragStartHandler); } DragArea = Obj; if (DragArea != nullptr) { UGGraph* DragGraph; if ((DragGraph = Cast(DragArea)) != nullptr && DragGraph->IsEmpty()) DragGraph->DrawRect(0, FColor::Transparent, FColor::Transparent); DragArea->SetDraggable(true); DragArea->OnDragStart.AddUniqueDynamic(this, &UGWindow::OnDragStartHandler); } } } void UGWindow::Show() { GetUIRoot()->ShowWindow(this); } void UGWindow::Hide() { if (IsShowing()) DoHideAnimation(); } void UGWindow::HideImmediately() { GetUIRoot()->HideWindowImmediately(this); } void UGWindow::ToggleStatus() { if (IsTop()) Hide(); else Show(); } void UGWindow::BringToFront() { GetUIRoot()->BringToFront(this); } bool UGWindow::IsTop() const { return Parent.IsValid() && Parent->GetChildIndex(this) == Parent->NumChildren() - 1; } void UGWindow::ShowModalWait(int32 InRequestingCmd) { if (InRequestingCmd != 0) RequestingCmd = InRequestingCmd; if (!FUIConfig::Config.WindowModalWaiting.IsEmpty()) { if (ModalWaitPane == nullptr) ModalWaitPane = UUIPackage::CreateObjectFromURL(FUIConfig::Config.WindowModalWaiting, this); LayoutModalWaitPane(); AddChild(ModalWaitPane); } } void UGWindow::LayoutModalWaitPane() { if (ContentArea != nullptr) { FVector2D pt = FrameObject->LocalToGlobal(FVector2D::ZeroVector); pt = GlobalToLocal(pt); ModalWaitPane->SetPosition(pt + ContentArea->GetPosition()); ModalWaitPane->SetSize(ContentArea->GetSize()); } else ModalWaitPane->SetSize(Size); } bool UGWindow::CloseModalWait(int32 InRequestingCmd) { if (InRequestingCmd != 0) { if (RequestingCmd != InRequestingCmd) return false; } RequestingCmd = 0; if (ModalWaitPane != nullptr && ModalWaitPane->GetParent() != nullptr) RemoveChild(ModalWaitPane); return true; } void UGWindow::Init() { if (bInited || bLoading) return; if (UISources.Num() > 0) { bLoading = false; int32 cnt = UISources.Num(); for (int32 i = 0; i < cnt; i++) { const TSharedPtr& lib = UISources[i]; if (!lib->IsLoaded()) { lib->Load(FSimpleDelegate::CreateUObject(this, &UGWindow::OnUILoadComplete)); bLoading = true; } } if (!bLoading) InternalInit(); } else InternalInit(); } void UGWindow::InternalInit() { bInited = true; OnInit(); if (IsShowing()) DoShowAnimation(); } void UGWindow::AddUISource(TSharedPtr UISource) { UISources.Add(UISource); } void UGWindow::OnInit() { InitCallback.ExecuteIfBound(this); } void UGWindow::OnShown() { ShownCallback.ExecuteIfBound(this); } void UGWindow::OnHide() { HideCallback.ExecuteIfBound(this); } void UGWindow::DoShowAnimation() { if (ShowingCallback.IsBound()) ShowingCallback.Execute(this); else OnShown(); } void UGWindow::DoHideAnimation() { if (HidingCallback.IsBound()) HidingCallback.Execute(this); else HideImmediately(); } void UGWindow::CloseEventHandler(UEventContext * Context) { Hide(); } void UGWindow::OnUILoadComplete() { int32 cnt = UISources.Num(); for (int32 i = 0; i < cnt; i++) { const TSharedPtr& lib = UISources[i]; if (!lib->IsLoaded()) return; } bLoading = false; InternalInit(); } void UGWindow::OnAddedToStageHandler(UEventContext * Context) { if (!bInited) Init(); else DoShowAnimation(); } void UGWindow::OnRemovedFromStageHandler(UEventContext * Context) { CloseModalWait(); OnHide(); } void UGWindow::OnTouchBeginHandler(UEventContext * Context) { if (IsShowing() && bBringToFontOnClick) { BringToFront(); } } void UGWindow::OnDragStartHandler(UEventContext * Context) { Context->PreventDefault(); StartDrag(Context->GetUserIndex(), Context->GetPointerIndex()); } ================================================ FILE: Source/FairyGUI/Private/UI/Gears/GearAnimation.cpp ================================================ #include "UI/Gears/GearAnimation.h" #include "UI/GObject.h" #include "UI/GController.h" #include "Utils/ByteBuffer.h" FGearAnimation::FValue::FValue() : bPlaying(false), Frame(0) { } FGearAnimation::FGearAnimation(UGObject* InOwner) : FGearBase(InOwner) { Type = EType::Animation; } FGearAnimation::~FGearAnimation() { } void FGearAnimation::Init() { Default.bPlaying = Owner->GetProp(EObjectPropID::Playing); Default.Frame = Owner->GetProp(EObjectPropID::Frame); Storage.Reset(); } void FGearAnimation::AddStatus(const FString& PageID, FByteBuffer* Buffer) { FValue Value; Value.bPlaying = Buffer->ReadBool(); Value.Frame = Buffer->ReadInt(); if (PageID.IsEmpty()) Default = Value; else Storage.Add(PageID, MoveTemp(Value)); } void FGearAnimation::Apply() { Owner->bGearLocked = true; FValue* Value = Storage.Find(Controller->GetSelectedPageID()); if (Value == nullptr) Value = &Default; Owner->SetProp(EObjectPropID::Playing, FNVariant(Value->bPlaying)); Owner->SetProp(EObjectPropID::Frame, FNVariant(Value->Frame)); Owner->bGearLocked = false; } void FGearAnimation::UpdateState() { FValue Value; Value.bPlaying = Owner->GetProp(EObjectPropID::Playing); Value.Frame = Owner->GetProp(EObjectPropID::Frame); Storage.Add(Controller->GetSelectedPageID(), MoveTemp(Value)); } ================================================ FILE: Source/FairyGUI/Private/UI/Gears/GearBase.cpp ================================================ #include "UI/Gears/GearBase.h" #include "UI/Gears/GearDisplay.h" #include "UI/Gears/GearAnimation.h" #include "UI/Gears/GearColor.h" #include "UI/Gears/GearDisplay2.h" #include "UI/Gears/GearFontSize.h" #include "UI/Gears/GearIcon.h" #include "UI/Gears/GearLook.h" #include "UI/Gears/GearSize.h" #include "UI/Gears/GearText.h" #include "UI/Gears/GearXY.h" #include "UI/GComponent.h" #include "Utils/ByteBuffer.h" bool FGearBase::bDisableAllTweenEffect = false; TSharedPtr FGearBase::Create(UGObject* InOwner, EType InType) { FGearBase* Gear = nullptr; switch (InType) { case EType::Display: Gear = new FGearDisplay(InOwner); break; case EType::XY: Gear = new FGearXY(InOwner); break; case EType::Size: Gear = new FGearSize(InOwner); break; case EType::Look: Gear = new FGearLook(InOwner); break; case EType::Color: Gear = new FGearColor(InOwner); break; case EType::Animation: Gear = new FGearAnimation(InOwner); break; case EType::Text: Gear = new FGearText(InOwner); break; case EType::Icon: Gear = new FGearIcon(InOwner); break; case EType::Display2: Gear = new FGearDisplay2(InOwner); break; case EType::FontSize: Gear = new FGearFontSize(InOwner); break; } return MakeShareable(Gear); } FGearTweenConfig::FGearTweenConfig(): bTween(true), EaseType(EEaseType::QuadOut), Duration(0.3f), Delay(0), DisplayLockToken(0) { } FGearBase::FGearBase(UGObject* InOwner) : Owner(InOwner) { } FGearBase::~FGearBase() { } void FGearBase::SetController(UGController* InController) { if (Controller != InController) { Controller = InController; if (Controller != nullptr) Init(); } } FGearTweenConfig& FGearBase::GetTweenConfig() { if (!TweenConfig.IsSet()) TweenConfig.Emplace(); return TweenConfig.GetValue(); } void FGearBase::Init() { } void FGearBase::AddStatus(const FString& PageID, FByteBuffer* Buffer) { } void FGearBase::Apply() { } void FGearBase::UpdateState() { } void FGearBase::UpdateFromRelations(const FVector2D& Delta) { } void FGearBase::Setup(FByteBuffer* Buffer) { Controller = Owner->GetParent()->GetControllerAt(Buffer->ReadShort()); Init(); int32 Count = Buffer->ReadShort(); FGearDisplay* g0 = Type == EType::Display ? static_cast(this) : nullptr; FGearDisplay2* g1 = Type == EType::Display2 ? static_cast(this) : nullptr; FGearXY* g2 = nullptr; if (g0) Buffer->ReadSArray(g0->Pages, Count); else if (g1) Buffer->ReadSArray(g1->Pages, Count); else { for (int32 i = 0; i < Count; i++) { const FString& page = Buffer->ReadS(); if (page.IsEmpty()) continue; AddStatus(page, Buffer); } if (Buffer->ReadBool()) AddStatus(G_EMPTY_STRING, Buffer); } if (Buffer->ReadBool()) { TweenConfig.Emplace(); TweenConfig->bTween = true; TweenConfig->EaseType = (EEaseType)Buffer->ReadByte(); TweenConfig->Duration = Buffer->ReadFloat(); TweenConfig->Delay = Buffer->ReadFloat(); } if (Buffer->Version >= 2) { g2 = Type == EType::XY ? static_cast(this) : nullptr; if (g2) { if (Buffer->ReadBool()) { if (g2) { g2->bPositionsInPercent = true; for (int32 i = 0; i < Count; i++) { const FString& page = Buffer->ReadS(); if (page.IsEmpty()) continue; g2->AddExtStatus(page, Buffer); } if (Buffer->ReadBool()) g2->AddExtStatus(G_EMPTY_STRING, Buffer); } } } else if (g1 != nullptr) g1->Condition = Buffer->ReadByte(); } } ================================================ FILE: Source/FairyGUI/Private/UI/Gears/GearColor.cpp ================================================ #include "UI/Gears/GearColor.h" #include "UI/GObject.h" #include "UI/UIPackage.h" #include "UI/GController.h" #include "Tween/GTween.h" #include "Utils/ByteBuffer.h" FGearColor::FValue::FValue() { } FGearColor::FGearColor(UGObject* InOwner) : FGearBase(InOwner) { Type = EType::Color; } FGearColor::~FGearColor() { } void FGearColor::Init() { Default.Color = Owner->GetProp(EObjectPropID::Color); Default.OutlineColor = Owner->GetProp(EObjectPropID::OutlineColor); Storage.Reset(); } void FGearColor::AddStatus(const FString& PageID, FByteBuffer* Buffer) { FValue Value; Value.Color = Buffer->ReadColor(); Value.OutlineColor = Buffer->ReadColor(); if (PageID.IsEmpty()) Default = Value; else Storage.Add(PageID, MoveTemp(Value)); } void FGearColor::Apply() { FValue* Value = Storage.Find(Controller->GetSelectedPageID()); if (Value == nullptr) Value = &Default; if (TweenConfig.IsSet() && TweenConfig->bTween && UUIPackage::Constructing == 0 && !bDisableAllTweenEffect) { FColor curColor = Owner->GetProp(EObjectPropID::Color); FColor curOutlineColor = Owner->GetProp(EObjectPropID::OutlineColor); if (Value->OutlineColor != curOutlineColor) { Owner->bGearLocked = true; Owner->SetProp(EObjectPropID::OutlineColor, FNVariant(Value->OutlineColor)); Owner->bGearLocked = false; } FGTweener* tweener = FGTween::GetTween(TweenConfig->Handle); if (tweener != nullptr) { if (tweener->EndValue.GetColor() != Value->Color) tweener->Kill(true); else return; } if (Value->Color != curColor) { if (Owner->CheckGearController(0, Controller)) TweenConfig->DisplayLockToken = Owner->AddDisplayLock(); TweenConfig->Handle = FGTween::To(curColor, Value->Color, TweenConfig->Duration) ->SetDelay(TweenConfig->Delay) ->SetEase(TweenConfig->EaseType) ->SetTarget(Owner) ->OnUpdate(FTweenDelegate::CreateRaw(this, &FGearColor::OnTweenUpdate)) ->OnComplete(FSimpleDelegate::CreateRaw(this, &FGearColor::OnTweenComplete)) ->GetHandle(); } } else { Owner->bGearLocked = true; Owner->SetProp(EObjectPropID::Color, FNVariant(Value->Color)); Owner->SetProp(EObjectPropID::OutlineColor, FNVariant(Value->OutlineColor)); Owner->bGearLocked = false; } } void FGearColor::OnTweenUpdate(FGTweener* Tweener) { Owner->bGearLocked = true; Owner->SetProp(EObjectPropID::Color, FNVariant(Tweener->Value.GetColor())); Owner->bGearLocked = false; } void FGearColor::OnTweenComplete() { if (TweenConfig->DisplayLockToken != 0) { Owner->ReleaseDisplayLock(TweenConfig->DisplayLockToken); TweenConfig->DisplayLockToken = 0; } TweenConfig->Handle.Invalidate(); Owner->DispatchEvent(FUIEvents::GearStop); } void FGearColor::UpdateState() { FValue Value; Value.Color = Owner->GetProp(EObjectPropID::Color); Value.OutlineColor = Owner->GetProp(EObjectPropID::OutlineColor); Storage.Add(Controller->GetSelectedPageID(), MoveTemp(Value)); } ================================================ FILE: Source/FairyGUI/Private/UI/Gears/GearDisplay.cpp ================================================ #include "UI/Gears/GearDisplay.h" #include "UI/GController.h" #include "Utils/ByteBuffer.h" FGearDisplay::FGearDisplay(UGObject* InOwner) : FGearBase(InOwner), Visible(0), DisplayLockToken(1) { Type = EType::Display; } FGearDisplay::~FGearDisplay() { } void FGearDisplay::Apply() { DisplayLockToken++; if (DisplayLockToken == 0) DisplayLockToken = 1; if (Pages.Num() == 0) Visible = 1; else { if (Pages.Contains(Controller->GetSelectedPageID())) Visible = 1; else Visible = 0; } } void FGearDisplay::UpdateState() { } void FGearDisplay::AddStatus(const FString& PageID, FByteBuffer* Buffer) { } void FGearDisplay::Init() { Pages.Reset(); } uint32 FGearDisplay::AddLock() { Visible++; return DisplayLockToken; } void FGearDisplay::ReleaseLock(uint32 token) { if (token == DisplayLockToken) Visible--; } bool FGearDisplay::IsConnected() { return Controller == nullptr || Visible > 0; } ================================================ FILE: Source/FairyGUI/Private/UI/Gears/GearDisplay2.cpp ================================================ #include "UI/Gears/GearDisplay2.h" #include "UI/GController.h" #include "Utils/ByteBuffer.h" FGearDisplay2::FGearDisplay2(UGObject* InOwner) : FGearBase(InOwner), Condition(0), Visible(0) { Type = EType::Display2; } FGearDisplay2::~FGearDisplay2() { } void FGearDisplay2::Apply() { if (Controller == nullptr || Pages.Num() == 0) Visible = 1; else { if (Pages.Contains(Controller->GetSelectedPageID())) Visible = 1; else Visible = 0; } } bool FGearDisplay2::Evaluate(bool bConnected) { bool v = Controller == nullptr || Visible > 0; if (Condition == 0) v = v && bConnected; else v = v || bConnected; return v; } void FGearDisplay2::UpdateState() { } void FGearDisplay2::AddStatus(const FString& PageID, FByteBuffer* Buffer) { } void FGearDisplay2::Init() { Pages.Reset(); } ================================================ FILE: Source/FairyGUI/Private/UI/Gears/GearFontSize.cpp ================================================ #include "UI/Gears/GearFontSize.h" #include "UI/GObject.h" #include "UI/GController.h" #include "Utils/ByteBuffer.h" FGearFontSize::FGearFontSize(UGObject* InOwner) : FGearBase(InOwner) { Type = EType::FontSize; } FGearFontSize::~FGearFontSize() { } void FGearFontSize::Init() { Default = Owner->GetProp(EObjectPropID::FontSize); Storage.Reset(); } void FGearFontSize::AddStatus(const FString& PageID, FByteBuffer* Buffer) { if (PageID.IsEmpty()) Default = Buffer->ReadInt(); else Storage.Add(PageID, Buffer->ReadInt()); } void FGearFontSize::Apply() { int32* Value = Storage.Find(Controller->GetSelectedPageID()); if (Value == nullptr) Value = &Default; Owner->bGearLocked = true; Owner->SetProp(EObjectPropID::FontSize, FNVariant(*Value)); Owner->bGearLocked = false; } void FGearFontSize::UpdateState() { Storage.Add(Controller->GetSelectedPageID(), Owner->GetProp(EObjectPropID::FontSize)); } ================================================ FILE: Source/FairyGUI/Private/UI/Gears/GearIcon.cpp ================================================ #include "UI/Gears/GearIcon.h" #include "UI/GObject.h" #include "UI/GController.h" #include "Utils/ByteBuffer.h" FGearIcon::FGearIcon(UGObject * InOwner) :FGearBase(InOwner) { Type = EType::Icon; } FGearIcon::~FGearIcon() { } void FGearIcon::Init() { Default = Owner->GetIcon(); Storage.Reset(); } void FGearIcon::AddStatus(const FString& PageID, FByteBuffer* Buffer) { if (PageID.IsEmpty()) Default = Buffer->ReadS(); else Storage.Add(PageID, Buffer->ReadS()); } void FGearIcon::Apply() { FString* Value = Storage.Find(Controller->GetSelectedPageID()); if (Value == nullptr) Value = &Default; Owner->bGearLocked = true; Owner->SetIcon(*Value); Owner->bGearLocked = false; } void FGearIcon::UpdateState() { Storage.Add(Controller->GetSelectedPageID(), Owner->GetIcon()); } ================================================ FILE: Source/FairyGUI/Private/UI/Gears/GearLook.cpp ================================================ #include "UI/Gears/GearLook.h" #include "UI/GObject.h" #include "UI/UIPackage.h" #include "UI/GController.h" #include "Tween/GTween.h" #include "Utils/ByteBuffer.h" FGearLook::FValue::FValue() : Alpha(0), Rotation(0), bGrayed(false), bTouchable(false) { } FGearLook::FGearLook(UGObject* InOwner) : FGearBase(InOwner) { Type = EType::Look; } FGearLook::~FGearLook() { } void FGearLook::Init() { Default.Alpha = Owner->GetAlpha(); Default.Rotation = Owner->GetRotation(); Default.bGrayed = Owner->IsGrayed(); Default.bTouchable = Owner->IsTouchable(); Storage.Reset(); } void FGearLook::AddStatus(const FString& PageID, FByteBuffer* Buffer) { FValue Value; Value.Alpha = Buffer->ReadFloat(); Value.Rotation = Buffer->ReadFloat(); Value.bGrayed = Buffer->ReadBool(); Value.bTouchable = Buffer->ReadBool(); if (PageID.IsEmpty()) Default = Value; else Storage.Add(PageID, MoveTemp(Value)); } void FGearLook::Apply() { FValue* Value = Storage.Find(Controller->GetSelectedPageID()); if (Value == nullptr) Value = &Default; if (TweenConfig.IsSet() && TweenConfig->bTween && UUIPackage::Constructing == 0 && !bDisableAllTweenEffect) { Owner->bGearLocked = true; Owner->SetGrayed(Value->bGrayed); Owner->SetTouchable(Value->bTouchable); Owner->bGearLocked = false; FGTweener* tweener = FGTween::GetTween(TweenConfig->Handle); if (tweener != nullptr) { if (tweener->EndValue.X != Value->Alpha || tweener->EndValue.Y != Value->Rotation) tweener->Kill(true); else return; } bool a = Value->Alpha != Owner->GetAlpha(); bool b = Value->Rotation != Owner->GetRotation(); if (a || b) { if (Owner->CheckGearController(0, Controller)) TweenConfig->DisplayLockToken = Owner->AddDisplayLock(); TweenConfig->Handle = FGTween::To(FVector2D(Owner->GetAlpha(), Owner->GetRotation()), FVector2D(Value->Alpha, Value->Rotation), TweenConfig->Duration) ->SetDelay(TweenConfig->Delay) ->SetEase(TweenConfig->EaseType) ->SetTarget(Owner) ->SetUserData(FNVariant((a ? 1 : 0) + (b ? 2 : 0))) ->OnUpdate(FTweenDelegate::CreateRaw(this, &FGearLook::OnTweenUpdate)) ->OnComplete(FSimpleDelegate::CreateRaw(this, &FGearLook::OnTweenComplete)) ->GetHandle(); } } else { Owner->bGearLocked = true; Owner->SetAlpha(Value->Alpha); Owner->SetRotation(Value->Rotation); Owner->SetGrayed(Value->bGrayed); Owner->SetTouchable(Value->bTouchable); Owner->bGearLocked = false; } } void FGearLook::OnTweenUpdate(FGTweener* Tweener) { int32 flag = Tweener->GetUserData().AsInt(); Owner->bGearLocked = true; if ((flag & 1) != 0) Owner->SetAlpha(Tweener->Value.X); if ((flag & 2) != 0) Owner->SetRotation(Tweener->Value.Y); Owner->bGearLocked = false; } void FGearLook::OnTweenComplete() { if (TweenConfig->DisplayLockToken != 0) { Owner->ReleaseDisplayLock(TweenConfig->DisplayLockToken); TweenConfig->DisplayLockToken = 0; } TweenConfig->Handle.Invalidate(); Owner->DispatchEvent(FUIEvents::GearStop); } void FGearLook::UpdateState() { FValue Value; Value.Alpha = Owner->GetAlpha(); Value.Rotation = Owner->GetRotation(); Value.bGrayed = Owner->IsGrayed(); Value.bTouchable = Owner->IsTouchable(); Storage.Add(Controller->GetSelectedPageID(), MoveTemp(Value)); } ================================================ FILE: Source/FairyGUI/Private/UI/Gears/GearSize.cpp ================================================ #include "UI/Gears/GearSize.h" #include "UI/GObject.h" #include "UI/UIPackage.h" #include "UI/GController.h" #include "Tween/GTween.h" #include "Utils/ByteBuffer.h" FGearSize::FGearSize(UGObject* InOwner) : FGearBase(InOwner) { Type = EType::Size; } FGearSize::~FGearSize() { } void FGearSize::Init() { Default = FVector4(Owner->GetWidth(), Owner->GetHeight(), Owner->GetScaleX(), Owner->GetScaleY()); Storage.Reset(); } void FGearSize::AddStatus(const FString& PageID, FByteBuffer* Buffer) { FVector4 Value; Value.X = Buffer->ReadInt(); Value.Y = Buffer->ReadInt(); Value.Z = Buffer->ReadFloat(); Value.W = Buffer->ReadFloat(); if (PageID.IsEmpty()) Default = Value; else Storage.Add(PageID, MoveTemp(Value)); } void FGearSize::Apply() { FVector4* Value = Storage.Find(Controller->GetSelectedPageID()); if (Value == nullptr) Value = &Default; if (TweenConfig.IsSet() && TweenConfig->bTween && UUIPackage::Constructing == 0 && !bDisableAllTweenEffect) { FGTweener* tweener = FGTween::GetTween(TweenConfig->Handle); if (tweener != nullptr) { if (tweener->EndValue.GetVec4() != *Value) tweener->Kill(true); else return; } bool a = Value->X != Owner->GetWidth() || Value->Y != Owner->GetHeight(); bool b = Value->Z != Owner->GetScaleX() || Value->W != Owner->GetScaleY(); if (a || b) { if (Owner->CheckGearController(0, Controller)) TweenConfig->DisplayLockToken = Owner->AddDisplayLock(); TweenConfig->Handle = FGTween::To(FVector4(Owner->GetWidth(), Owner->GetHeight(), Owner->GetScaleX(), Owner->GetScaleY()), *Value, TweenConfig->Duration) ->SetDelay(TweenConfig->Delay) ->SetEase(TweenConfig->EaseType) ->SetTarget(Owner) ->SetUserData(FNVariant((a ? 1 : 0) + (b ? 2 : 0))) ->OnUpdate(FTweenDelegate::CreateRaw(this, &FGearSize::OnTweenUpdate)) ->OnComplete(FSimpleDelegate::CreateRaw(this, &FGearSize::OnTweenComplete)) ->GetHandle(); } } else { Owner->bGearLocked = true; Owner->SetSize(FVector2D(Value->X, Value->Y), Owner->CheckGearController(1, Controller)); Owner->SetScale(FVector2D(Value->Z, Value->W)); Owner->bGearLocked = false; } } void FGearSize::OnTweenUpdate(FGTweener* Tweener) { int32 flag = Tweener->GetUserData().AsInt(); Owner->bGearLocked = true; if ((flag & 1) != 0) Owner->SetSize(Tweener->Value.GetVec2(), Owner->CheckGearController(1, Controller)); if ((flag & 2) != 0) Owner->SetScale(FVector2D(Tweener->Value.Z, Tweener->Value.W)); Owner->bGearLocked = false; } void FGearSize::OnTweenComplete() { if (TweenConfig->DisplayLockToken != 0) { Owner->ReleaseDisplayLock(TweenConfig->DisplayLockToken); TweenConfig->DisplayLockToken = 0; } TweenConfig->Handle.Invalidate(); Owner->DispatchEvent(FUIEvents::GearStop); } void FGearSize::UpdateState() { Storage.Add(Controller->GetSelectedPageID(), FVector4(Owner->GetWidth(), Owner->GetHeight(), Owner->GetScaleX(), Owner->GetScaleY())); } void FGearSize::UpdateFromRelations(const FVector2D& Delta) { if (Controller != nullptr && Storage.Num() > 0) { for (auto It = Storage.CreateIterator(); It; ++It) { It->Value = FVector4(It->Value.X + Delta.X, It->Value.Y + Delta.Y, It->Value.Z, It->Value.W); } Default.X += Delta.X; Default.Y += Delta.Y; UpdateState(); } } ================================================ FILE: Source/FairyGUI/Private/UI/Gears/GearText.cpp ================================================ #include "UI/Gears/GearText.h" #include "UI/GObject.h" #include "UI/GController.h" #include "Utils/ByteBuffer.h" FGearText::FGearText(UGObject* InOwner) : FGearBase(InOwner) { Type = EType::Text; } FGearText::~FGearText() { } void FGearText::Init() { Default = Owner->GetText(); Storage.Reset(); } void FGearText::AddStatus(const FString& PageID, FByteBuffer* Buffer) { if (PageID.IsEmpty()) Default = Buffer->ReadS(); else Storage.Add(PageID, Buffer->ReadS()); } void FGearText::Apply() { FString* Value = Storage.Find(Controller->GetSelectedPageID()); if (Value == nullptr) Value = &Default; Owner->bGearLocked = true; Owner->SetText(*Value); Owner->bGearLocked = false; } void FGearText::UpdateState() { Storage.Add(Controller->GetSelectedPageID(), Owner->GetText()); } ================================================ FILE: Source/FairyGUI/Private/UI/Gears/GearXY.cpp ================================================ #include "UI/Gears/GearXY.h" #include "UI/GComponent.h" #include "UI/UIPackage.h" #include "UI/GController.h" #include "Tween/GTween.h" #include "Utils/ByteBuffer.h" FGearXY::FGearXY(UGObject* InOwner) : FGearBase(InOwner), bPositionsInPercent(false) { Type = EType::XY; } FGearXY::~FGearXY() { } void FGearXY::Init() { Default = FVector4(Owner->GetX(), Owner->GetY(), Owner->GetX() / Owner->GetParent()->GetWidth(), Owner->GetY() / Owner->GetParent()->GetHeight()); Storage.Reset(); } void FGearXY::AddStatus(const FString& PageID, FByteBuffer* Buffer) { FVector4 Value; Value.X = Buffer->ReadInt(); Value.Y = Buffer->ReadInt(); if (PageID.IsEmpty()) Default = Value; else Storage.Add(PageID, MoveTemp(Value)); } void FGearXY::AddExtStatus(const FString& PageID, FByteBuffer* Buffer) { FVector4* Value = PageID.IsEmpty() ? &Default : Storage.Find(Controller->GetSelectedPageID()); Value->Z = Buffer->ReadFloat(); Value->W = Buffer->ReadFloat(); } void FGearXY::Apply() { FVector4* Value = Storage.Find(Controller->GetSelectedPageID()); if (Value == nullptr) Value = &Default; FVector2D EndPt; if (bPositionsInPercent && Owner->GetParent()) { EndPt.X = Value->Z * Owner->GetParent()->GetWidth(); EndPt.Y = Value->W * Owner->GetParent()->GetHeight(); } else { EndPt.X = Value->X; EndPt.Y = Value->Y; } if (TweenConfig.IsSet() && TweenConfig->bTween && UUIPackage::Constructing == 0 && !bDisableAllTweenEffect) { FGTweener* tweener = FGTween::GetTween(TweenConfig->Handle); if (tweener != nullptr) { if (tweener->EndValue.GetVec2() != EndPt) tweener->Kill(true); else return; } FVector2D OriginPt(Owner->GetX(), Owner->GetY()); if (OriginPt != EndPt) { if (Owner->CheckGearController(0, Controller)) TweenConfig->DisplayLockToken = Owner->AddDisplayLock(); TweenConfig->Handle = FGTween::To(OriginPt, EndPt, TweenConfig->Duration) ->SetDelay(TweenConfig->Delay) ->SetEase(TweenConfig->EaseType) ->SetTarget(Owner) ->OnUpdate(FTweenDelegate::CreateRaw(this, &FGearXY::OnTweenUpdate)) ->OnComplete(FSimpleDelegate::CreateRaw(this, &FGearXY::OnTweenComplete)) ->GetHandle(); } } else { Owner->bGearLocked = true; Owner->SetPosition(EndPt); Owner->bGearLocked = false; } } void FGearXY::OnTweenUpdate(FGTweener* Tweener) { Owner->bGearLocked = true; Owner->SetPosition(Tweener->Value.GetVec2()); Owner->bGearLocked = false; } void FGearXY::OnTweenComplete() { if (TweenConfig->DisplayLockToken != 0) { Owner->ReleaseDisplayLock(TweenConfig->DisplayLockToken); TweenConfig->DisplayLockToken = 0; } TweenConfig->Handle.Invalidate(); Owner->DispatchEvent(FUIEvents::GearStop); } void FGearXY::UpdateState() { Storage.Add(Controller->GetSelectedPageID(), FVector4( Owner->GetX(), Owner->GetY(), Owner->GetX() / Owner->GetParent()->GetWidth(), Owner->GetY() / Owner->GetParent()->GetHeight())); } void FGearXY::UpdateFromRelations(const FVector2D& Delta) { if (Controller != nullptr && Storage.Num() > 0 && !bPositionsInPercent) { for (auto It = Storage.CreateIterator(); It; ++It) { It->Value = FVector4(It->Value.X + Delta.X, It->Value.Y + Delta.Y, It->Value.Z, It->Value.W); } Default.X += Delta.X; Default.Y += Delta.Y; UpdateState(); } } ================================================ FILE: Source/FairyGUI/Private/UI/PackageItem.cpp ================================================ #include "UI/PackageItem.h" #include "UI/UIPackage.h" #include "UI/GRoot.h" #include "Utils/ByteBuffer.h" FPackageItem::FPackageItem() : Owner(nullptr), Type(EPackageItemType::Unknown), ObjectType(EObjectType::Component), Size(0, 0), Texture(nullptr), bScaleByTile(false), TileGridIndice(0) { } void FPackageItem::Load() { Owner->GetItemAsset(AsShared()); } TSharedPtr FPackageItem::GetBranch() { if (Branches.IsSet() && Owner->BranchIndex != -1) { const FString& ItemID = Branches.GetValue()[Owner->BranchIndex]; if (!ItemID.IsEmpty()) return Owner->GetItem(ItemID); } return AsShared(); } TSharedPtr FPackageItem::GetHighResolution() { if (HighResolution.IsSet() && UGRoot::ContentScaleLevel > 0) { FString ItemID = HighResolution.GetValue()[UGRoot::ContentScaleLevel - 1]; if (!ItemID.IsEmpty()) return Owner->GetItem(ItemID); } return AsShared(); } void FPackageItem::AddReferencedObjects(FReferenceCollector& Collector) { if (Texture != nullptr) Collector.AddReferencedObject(Texture); } ================================================ FILE: Source/FairyGUI/Private/UI/PopupMenu.cpp ================================================ #include "UI/PopupMenu.h" #include "UI/GRoot.h" #include "UI/UIPackage.h" #include "UI/GController.h" const FName UPopupMenu::ClickMenu("ClickMenu"); UPopupMenu* UPopupMenu::CreatePopupMenu(const FString& ResourceURL, UObject* WorldContextObject) { UPopupMenu* Instance = NewObject(WorldContextObject); Instance->Create(ResourceURL); return Instance; } UPopupMenu::UPopupMenu() { } UPopupMenu::~UPopupMenu() { } void UPopupMenu::Create(const FString& ResourceURL) { FString url = ResourceURL; if (url.IsEmpty()) { url = FUIConfig::Config.PopupMenu; if (url.IsEmpty()) { UE_LOG(LogFairyGUI, Warning, TEXT("UIConfig.PopupMenu not defined")); return; } } ContentPane = UUIPackage::CreateObjectFromURL(url, this)->As(); ContentPane->On(FUIEvents::AddedToStage).AddUObject(this, &UPopupMenu::OnAddedToStage); List = ContentPane->GetChild("list")->As(); List->RemoveChildrenToPool(); List->AddRelation(ContentPane, ERelationType::Width); List->RemoveRelation(ContentPane, ERelationType::Height); ContentPane->AddRelation(List, ERelationType::Height); List->On(FUIEvents::ClickItem).AddUObject(this, &UPopupMenu::OnClickItem); } UGButton* UPopupMenu::AddItem(const FString& Caption, FGUIEventDelegate Callback) { UGButton* item = List->AddItemFromPool()->As(); item->SetTitle(Caption); item->SetGrayed(false); UGController* c = item->GetController("checked"); if (c != nullptr) c->SetSelectedIndex(0); item->On(ClickMenu).Clear(); if (Callback.IsBound()) item->On(ClickMenu).Add(Callback); return item; } UGButton* UPopupMenu::AddItem(const FString& Caption, const FGUIEventDynDelegate& Callback) { return AddItem(Caption, Callback.IsBound() ? FGUIEventDelegate::CreateUFunction(const_cast(Callback.GetUObject()), Callback.GetFunctionName()) : FGUIEventDelegate()); } UGButton* UPopupMenu::AddItemAt(const FString& Caption, int32 Index, FGUIEventDelegate Callback) { UGButton* item = List->GetFromPool(List->GetDefaultItem())->As(); List->AddChildAt(item, Index); item->SetTitle(Caption); item->SetGrayed(false); UGController* c = item->GetController("checked"); if (c != nullptr) c->SetSelectedIndex(0); if (Callback.IsBound()) item->On(ClickMenu).Add(Callback); return item; } UGButton* UPopupMenu::AddItemAt(const FString& Caption, int32 index, const FGUIEventDynDelegate& Callback) { return AddItemAt(Caption, index, Callback.IsBound() ? FGUIEventDelegate::CreateUFunction(const_cast(Callback.GetUObject()), Callback.GetFunctionName()) : FGUIEventDelegate()); } void UPopupMenu::AddSeperator() { if (FUIConfig::Config.PopupMenuSeperator.IsEmpty()) { UE_LOG(LogFairyGUI, Warning, TEXT("UIConfig.PopupMenuSeperator not defined")); return; } List->AddItemFromPool(FUIConfig::Config.PopupMenuSeperator); } const FString& UPopupMenu::GetItemName(int32 Index) const { UGButton* item = List->GetChildAt(Index)->As(); return item->Name; } void UPopupMenu::SetItemText(const FString& Name, const FString& Caption) { UGButton* item = List->GetChild(Name)->As(); item->SetTitle(Caption); } void UPopupMenu::SetItemVisible(const FString& Name, bool bVisible) { UGButton* item = List->GetChild(Name)->As(); if (item->IsVisible() != bVisible) { item->SetVisible(bVisible); List->SetBoundsChangedFlag(); } } void UPopupMenu::SetItemGrayed(const FString& Name, bool bGrayed) { UGButton* item = List->GetChild(Name)->As(); item->SetGrayed(bGrayed); } void UPopupMenu::SetItemCheckable(const FString& Name, bool bCheckable) { UGButton* item = List->GetChild(Name)->As(); UGController* c = item->GetController("checked"); if (c != nullptr) { if (bCheckable) { if (c->GetSelectedIndex() == 0) c->SetSelectedIndex(1); } else c->SetSelectedIndex(0); } } void UPopupMenu::SetItemChecked(const FString& Name, bool bCheck) { UGButton* item = List->GetChild(Name)->As(); UGController* c = item->GetController("checked"); if (c != nullptr) c->SetSelectedIndex(bCheck ? 2 : 1); } bool UPopupMenu::IsItemChecked(const FString& Name) const { UGButton* item = List->GetChild(Name)->As(); UGController* c = item->GetController("checked"); if (c != nullptr) return c->GetSelectedIndex() == 2; else return false; } bool UPopupMenu::RemoveItem(const FString& Name) { UGObject* item = List->GetChild(Name); if (item != nullptr) { int32 index = List->GetChildIndex(item); List->RemoveChildToPoolAt(index); item->On(ClickMenu).Clear(); return true; } else return false; } void UPopupMenu::ClearItems() { int32 cnt = List->NumChildren(); for (int32 i = 0; i < cnt; i++) List->GetChildAt(i)->On(ClickMenu).Clear(); List->RemoveChildrenToPool(); } int32 UPopupMenu::GetItemCount() const { return List->NumChildren(); } void UPopupMenu::Show(UGObject* AtObject, EPopupDirection Dir) { ContentPane->GetUIRoot()->ShowPopup(ContentPane, AtObject, Dir); } void UPopupMenu::OnClickItem(UEventContext* Context) { UGButton* item = Cast(Context->GetData().AsUObject()); if (item == nullptr) return; if (item->IsGrayed()) { List->SetSelectedIndex(-1); return; } UGController* c = item->GetController("checked"); if (c != nullptr && c->GetSelectedIndex() != 0) { if (c->GetSelectedIndex() == 1) c->SetSelectedIndex(2); else c->SetSelectedIndex(1); } ContentPane->GetUIRoot()->HidePopup(ContentPane); item->DispatchEvent(ClickMenu, Context->GetData()); } void UPopupMenu::OnAddedToStage(UEventContext* Context) { List->SetSelectedIndex(-1); List->ResizeToFit(INT_MAX, 10); } ================================================ FILE: Source/FairyGUI/Private/UI/RelationItem.cpp ================================================ #include "UI/RelationItem.h" #include "UI/Relations.h" #include "UI/GComponent.h" #include "UI/GGroup.h" #include "UI/Transition.h" FRelationItem::FRelationItem(UGObject* InOwner) : TargetData(ForceInit) { Owner = InOwner; } FRelationItem::~FRelationItem() { ReleaseRefTarget(); } void FRelationItem::SetTarget(UGObject* InTarget) { if (Target.Get() != InTarget) { ReleaseRefTarget(); Target = InTarget; if (InTarget) AddRefTarget(InTarget); } } void FRelationItem::Add(ERelationType RelationType, bool bUsePercent) { if (RelationType == ERelationType::Size) { Add(ERelationType::Width, bUsePercent); Add(ERelationType::Height, bUsePercent); return; } for (auto& it : Defs) { if (it.Type == RelationType) return; } InternalAdd(RelationType, bUsePercent); } void FRelationItem::InternalAdd(ERelationType RelationType, bool bUsePercent) { if (RelationType == ERelationType::Size) { InternalAdd(ERelationType::Width, bUsePercent); InternalAdd(ERelationType::Height, bUsePercent); return; } FRelationDef info; info.bPercent = bUsePercent; info.Type = RelationType; info.Axis = (RelationType <= ERelationType::Right_Right || RelationType == ERelationType::Width || (RelationType >= ERelationType::LeftExt_Left && RelationType <= ERelationType::RightExt_Right)) ? 0 : 1; Defs.Add(info); } void FRelationItem::Remove(ERelationType RelationType) { if (RelationType == ERelationType::Size) { Remove(ERelationType::Width); Remove(ERelationType::Height); return; } int32 i = 0; for (auto& def : Defs) { if (def.Type == RelationType) { Defs.RemoveAt(i); break; } i++; } } void FRelationItem::CopyFrom(const FRelationItem& Source) { SetTarget(Source.Target.Get()); Defs.Reset(); for (auto& it : Source.Defs) Defs.Add(it); } bool FRelationItem::IsEmpty() const { return Defs.Num() == 0; } void FRelationItem::ApplyOnSelfSizeChanged(float DeltaWidth, float DeltaHeight, bool bApplyPivot) { if (!Target.IsValid() || Defs.Num() == 0) return; FVector2D Pos = Owner->Position; for (auto& it : Defs) { switch (it.Type) { case ERelationType::Center_Center: Owner->SetX(Owner->Position.X - (0.5 - (bApplyPivot ? Owner->Pivot.X : 0)) * DeltaWidth); break; case ERelationType::Right_Center: case ERelationType::Right_Left: case ERelationType::Right_Right: Owner->SetX(Owner->Position.X - (1 - (bApplyPivot ? Owner->Pivot.X : 0)) * DeltaWidth); break; case ERelationType::Middle_Middle: Owner->SetY(Owner->Position.Y - (0.5 - (bApplyPivot ? Owner->Pivot.Y : 0)) * DeltaHeight); break; case ERelationType::Bottom_Middle: case ERelationType::Bottom_Top: case ERelationType::Bottom_Bottom: Owner->SetY(Owner->Position.Y - (1 - (bApplyPivot ? Owner->Pivot.Y : 0)) * DeltaHeight); break; default: break; } } if (Pos != Owner->Position) { FVector2D Delta = Owner->Position - Pos; Owner->UpdateGearFromRelations(1, Delta); if (Owner->Parent.IsValid()) { const TArray& arr = Owner->Parent->GetTransitions(); for (auto& it : arr) it->UpdateFromRelations(Owner->ID, Delta); } } } void FRelationItem::ApplyOnXYChanged(UGObject* InTarget, const FRelationDef& info, float dx, float dy) { float tmp; switch (info.Type) { case ERelationType::Left_Left: case ERelationType::Left_Center: case ERelationType::Left_Right: case ERelationType::Center_Center: case ERelationType::Right_Left: case ERelationType::Right_Center: case ERelationType::Right_Right: Owner->SetX(Owner->Position.X + dx); break; case ERelationType::Top_Top: case ERelationType::Top_Middle: case ERelationType::Top_Bottom: case ERelationType::Middle_Middle: case ERelationType::Bottom_Top: case ERelationType::Bottom_Middle: case ERelationType::Bottom_Bottom: Owner->SetY(Owner->Position.Y + dy); break; case ERelationType::Width: case ERelationType::Height: break; case ERelationType::LeftExt_Left: case ERelationType::LeftExt_Right: if (Owner != InTarget->Parent) { tmp = Owner->GetXMin(); Owner->SetWidth(Owner->RawSize.X - dx); Owner->SetXMin(tmp + dx); } else Owner->SetWidth(Owner->RawSize.X - dx); break; case ERelationType::RightExt_Left: case ERelationType::RightExt_Right: if (Owner != InTarget->Parent) { tmp = Owner->GetXMin(); Owner->SetWidth(Owner->RawSize.X + dx); Owner->SetXMin(tmp); } else Owner->SetWidth(Owner->RawSize.X + dx); break; case ERelationType::TopExt_Top: case ERelationType::TopExt_Bottom: if (Owner != InTarget->Parent) { tmp = Owner->GetYMin(); Owner->SetHeight(Owner->RawSize.Y - dy); Owner->SetYMin(tmp + dy); } else Owner->SetHeight(Owner->RawSize.Y - dy); break; case ERelationType::BottomExt_Top: case ERelationType::BottomExt_Bottom: if (Owner != InTarget->Parent) { tmp = Owner->GetYMin(); Owner->SetHeight(Owner->RawSize.Y + dy); Owner->SetYMin(tmp); } else Owner->SetHeight(Owner->RawSize.Y + dy); break; default: break; } } void FRelationItem::ApplyOnSizeChanged(UGObject* InTarget, const FRelationDef& info) { float pos = 0, pivot = 0, delta = 0; if (info.Axis == 0) { if (InTarget != Owner->Parent) { pos = InTarget->Position.X; if (InTarget->bPivotAsAnchor) pivot = InTarget->Pivot.X; } if (info.bPercent) { if (TargetData.Z != 0) delta = InTarget->Size.X / TargetData.Z; } else delta = InTarget->Size.X - TargetData.Z; } else { if (InTarget != Owner->Parent) { pos = InTarget->Position.Y; if (InTarget->bPivotAsAnchor) pivot = InTarget->Pivot.Y; } if (info.bPercent) { if (TargetData.W != 0) delta = InTarget->Size.Y / TargetData.W; } else delta = InTarget->Size.Y - TargetData.W; } float v, tmp; switch (info.Type) { case ERelationType::Left_Left: if (info.bPercent) Owner->SetXMin(pos + (Owner->GetXMin() - pos) * delta); else if (pivot != 0) Owner->SetX(Owner->Position.X + delta * (-pivot)); break; case ERelationType::Left_Center: if (info.bPercent) Owner->SetXMin(pos + (Owner->GetXMin() - pos) * delta); else Owner->SetX(Owner->Position.X + delta * (0.5f - pivot)); break; case ERelationType::Left_Right: if (info.bPercent) Owner->SetXMin(pos + (Owner->GetXMin() - pos) * delta); else Owner->SetX(Owner->Position.X + delta * (1 - pivot)); break; case ERelationType::Center_Center: if (info.bPercent) Owner->SetXMin(pos + (Owner->GetXMin() + Owner->RawSize.X * 0.5f - pos) * delta - Owner->RawSize.X * 0.5f); else Owner->SetX(Owner->Position.X + delta * (0.5f - pivot)); break; case ERelationType::Right_Left: if (info.bPercent) Owner->SetXMin(pos + (Owner->GetXMin() + Owner->RawSize.X - pos) * delta - Owner->RawSize.X); else if (pivot != 0) Owner->SetX(Owner->Position.X + delta * (-pivot)); break; case ERelationType::Right_Center: if (info.bPercent) Owner->SetXMin(pos + (Owner->GetXMin() + Owner->RawSize.X - pos) * delta - Owner->RawSize.X); else Owner->SetX(Owner->Position.X + delta * (0.5f - pivot)); break; case ERelationType::Right_Right: if (info.bPercent) Owner->SetXMin(pos + (Owner->GetXMin() + Owner->RawSize.X - pos) * delta - Owner->RawSize.X); else Owner->SetX(Owner->Position.X + delta * (1 - pivot)); break; case ERelationType::Top_Top: if (info.bPercent) Owner->SetYMin(pos + (Owner->GetYMin() - pos) * delta); else if (pivot != 0) Owner->SetY(Owner->Position.Y + delta * (-pivot)); break; case ERelationType::Top_Middle: if (info.bPercent) Owner->SetYMin(pos + (Owner->GetYMin() - pos) * delta); else Owner->SetY(Owner->Position.Y + delta * (0.5f - pivot)); break; case ERelationType::Top_Bottom: if (info.bPercent) Owner->SetYMin(pos + (Owner->GetYMin() - pos) * delta); else Owner->SetY(Owner->Position.Y + delta * (1 - pivot)); break; case ERelationType::Middle_Middle: if (info.bPercent) Owner->SetYMin(pos + (Owner->GetYMin() + Owner->RawSize.Y * 0.5f - pos) * delta - Owner->RawSize.Y * 0.5f); else Owner->SetY(Owner->Position.Y + delta * (0.5f - pivot)); break; case ERelationType::Bottom_Top: if (info.bPercent) Owner->SetYMin(pos + (Owner->GetYMin() + Owner->RawSize.Y - pos) * delta - Owner->RawSize.Y); else if (pivot != 0) Owner->SetY(Owner->Position.Y + delta * (-pivot)); break; case ERelationType::Bottom_Middle: if (info.bPercent) Owner->SetYMin(pos + (Owner->GetYMin() + Owner->RawSize.Y - pos) * delta - Owner->RawSize.Y); else Owner->SetY(Owner->Position.Y + delta * (0.5f - pivot)); break; case ERelationType::Bottom_Bottom: if (info.bPercent) Owner->SetYMin(pos + (Owner->GetYMin() + Owner->RawSize.Y - pos) * delta - Owner->RawSize.Y); else Owner->SetY(Owner->Position.Y + delta * (1 - pivot)); break; case ERelationType::Width: if (Owner->bUnderConstruct && Owner == InTarget->Parent) v = Owner->SourceSize.X - InTarget->InitSize.X; else v = Owner->RawSize.X - TargetData.Z; if (info.bPercent) v = v * delta; if (InTarget == Owner->Parent) { if (Owner->bPivotAsAnchor) { tmp = Owner->GetXMin(); Owner->SetSize(FVector2D(InTarget->Size.X + v, Owner->RawSize.Y), true); Owner->SetXMin(tmp); } else Owner->SetSize(FVector2D(InTarget->Size.X + v, Owner->RawSize.Y), true); } else Owner->SetWidth(InTarget->Size.X + v); break; case ERelationType::Height: if (Owner->bUnderConstruct && Owner == InTarget->Parent) v = Owner->SourceSize.Y - InTarget->InitSize.Y; else v = Owner->RawSize.Y - TargetData.W; if (info.bPercent) v = v * delta; if (InTarget == Owner->Parent) { if (Owner->bPivotAsAnchor) { tmp = Owner->GetYMin(); Owner->SetSize(FVector2D(Owner->RawSize.X, InTarget->Size.Y + v), true); Owner->SetYMin(tmp); } else Owner->SetSize(FVector2D(Owner->RawSize.X, InTarget->Size.Y + v), true); } else Owner->SetHeight(InTarget->Size.Y + v); break; case ERelationType::LeftExt_Left: tmp = Owner->GetXMin(); if (info.bPercent) v = pos + (tmp - pos) * delta - tmp; else v = delta * (-pivot); Owner->SetWidth(Owner->RawSize.X - v); Owner->SetXMin(tmp + v); break; case ERelationType::LeftExt_Right: tmp = Owner->GetXMin(); if (info.bPercent) v = pos + (tmp - pos) * delta - tmp; else v = delta * (1 - pivot); Owner->SetWidth(Owner->RawSize.X - v); Owner->SetXMin(tmp + v); break; case ERelationType::RightExt_Left: tmp = Owner->GetXMin(); if (info.bPercent) v = pos + (tmp + Owner->RawSize.X - pos) * delta - (tmp + Owner->RawSize.X); else v = delta * (-pivot); Owner->SetWidth(Owner->RawSize.X + v); Owner->SetXMin(tmp); break; case ERelationType::RightExt_Right: tmp = Owner->GetXMin(); if (info.bPercent) { if (Owner == InTarget->Parent) { if (Owner->bUnderConstruct) Owner->SetWidth(pos + InTarget->Size.X - InTarget->Size.X * pivot + (Owner->SourceSize.X - pos - InTarget->InitSize.X + InTarget->InitSize.X * pivot) * delta); else Owner->SetWidth(pos + (Owner->RawSize.X - pos) * delta); } else { v = pos + (tmp + Owner->RawSize.X - pos) * delta - (tmp + Owner->RawSize.X); Owner->SetWidth(Owner->RawSize.X + v); Owner->SetXMin(tmp); } } else { if (Owner == InTarget->Parent) { if (Owner->bUnderConstruct) Owner->SetWidth(Owner->SourceSize.X + (InTarget->Size.X - InTarget->InitSize.X) * (1 - pivot)); else Owner->SetWidth(Owner->RawSize.X + delta * (1 - pivot)); } else { v = delta * (1 - pivot); Owner->SetWidth(Owner->RawSize.X + v); Owner->SetXMin(tmp); } } break; case ERelationType::TopExt_Top: tmp = Owner->GetYMin(); if (info.bPercent) v = pos + (tmp - pos) * delta - tmp; else v = delta * (-pivot); Owner->SetHeight(Owner->RawSize.Y - v); Owner->SetYMin(tmp + v); break; case ERelationType::TopExt_Bottom: tmp = Owner->GetYMin(); if (info.bPercent) v = pos + (tmp - pos) * delta - tmp; else v = delta * (1 - pivot); Owner->SetHeight(Owner->RawSize.Y - v); Owner->SetYMin(tmp + v); break; case ERelationType::BottomExt_Top: tmp = Owner->GetYMin(); if (info.bPercent) v = pos + (tmp + Owner->RawSize.Y - pos) * delta - (tmp + Owner->RawSize.Y); else v = delta * (-pivot); Owner->SetHeight(Owner->RawSize.Y + v); Owner->SetYMin(tmp); break; case ERelationType::BottomExt_Bottom: tmp = Owner->GetYMin(); if (info.bPercent) { if (Owner == InTarget->Parent) { if (Owner->bUnderConstruct) Owner->SetHeight(pos + InTarget->Size.Y - InTarget->Size.Y * pivot + (Owner->SourceSize.Y - pos - InTarget->InitSize.Y + InTarget->InitSize.Y * pivot) * delta); else Owner->SetHeight(pos + (Owner->RawSize.Y - pos) * delta); } else { v = pos + (tmp + Owner->RawSize.Y - pos) * delta - (tmp + Owner->RawSize.Y); Owner->SetHeight(Owner->RawSize.Y + v); Owner->SetYMin(tmp); } } else { if (Owner == InTarget->Parent) { if (Owner->bUnderConstruct) Owner->SetHeight(Owner->SourceSize.Y + (InTarget->Size.Y - InTarget->InitSize.Y) * (1 - pivot)); else Owner->SetHeight(Owner->RawSize.Y + delta * (1 - pivot)); } else { v = delta * (1 - pivot); Owner->SetHeight(Owner->RawSize.Y + v); Owner->SetYMin(tmp); } } break; default: break; } } void FRelationItem::AddRefTarget(UGObject* InTarget) { if (!InTarget) return; if (InTarget != Owner->GetParent()) PositionDelegateHandle = InTarget->OnPositionChanged().AddRaw(this, &FRelationItem::OnTargetXYChanged); SizeDelegateHandle = InTarget->OnSizeChanged().AddRaw(this, &FRelationItem::OnTargetSizeChanged); TargetData.X = InTarget->Position.X; TargetData.Y = InTarget->Position.Y; TargetData.Z = InTarget->Size.X; TargetData.W = InTarget->Size.Y; } void FRelationItem::ReleaseRefTarget() { if (!Target.IsValid()) return; Target->OnPositionChanged().Remove(PositionDelegateHandle); Target->OnSizeChanged().Remove(SizeDelegateHandle); } void FRelationItem::OnTargetXYChanged() { if (Owner->Relations->Handling != nullptr || (Owner->Group.IsValid() && Owner->Group->Updating != 0)) { TargetData.X = Target->Position.X; TargetData.Y = Target->Position.Y; return; } Owner->Relations->Handling = Target.Get(); FVector2D Pos = Owner->Position; float dx = Target->Position.X - TargetData.X; float dy = Target->Position.Y - TargetData.Y; for (auto& it : Defs) ApplyOnXYChanged(Target.Get(), it, dx, dy); TargetData.X = Target->Position.X; TargetData.Y = Target->Position.Y; if (Pos != Owner->Position) { FVector2D Delta = Owner->Position - Pos; Owner->UpdateGearFromRelations(1, Delta); if (Owner->Parent.IsValid()) { const TArray& arr = Owner->Parent->GetTransitions(); for (auto& it : arr) it->UpdateFromRelations(Owner->ID, Delta); } } Owner->Relations->Handling = nullptr; } void FRelationItem::OnTargetSizeChanged() { if (Owner->Relations->Handling != nullptr || (Owner->Group.IsValid() && Owner->Group->Updating != 0)) { TargetData.Z = Target->Size.X; TargetData.W = Target->Size.Y; return; } Owner->Relations->Handling = Target.Get(); FVector2D Pos = Owner->Position; FVector2D RawSize = Owner->RawSize; for (auto& it : Defs) ApplyOnSizeChanged(Target.Get(), it); TargetData.Z = Target->Size.X; TargetData.W = Target->Size.Y; if (Pos != Owner->Position) { FVector2D Delta = Owner->Position - Pos; Owner->UpdateGearFromRelations(1, Delta); if (Owner->Parent.IsValid()) { const TArray& arr = Owner->Parent->GetTransitions(); for (auto& it : arr) it->UpdateFromRelations(Owner->ID, Delta); } } if (RawSize != Owner->RawSize) { FVector2D Delta = Owner->RawSize - RawSize; Owner->UpdateGearFromRelations(2, Delta); } Owner->Relations->Handling = nullptr; } ================================================ FILE: Source/FairyGUI/Private/UI/Relations.cpp ================================================ #include "UI/Relations.h" #include "UI/GComponent.h" #include "Utils/ByteBuffer.h" FRelations::FRelations(UGObject* InOwner) : Handling(nullptr) { Owner = InOwner; } FRelations::~FRelations() { } void FRelations::Add(UGObject * InTarget, ERelationType ERelationType) { Add(InTarget, ERelationType, false); } void FRelations::Add(UGObject * InTarget, ERelationType ERelationType, bool bUsePercent) { verifyf(InTarget, TEXT("target is null")); for (auto& it : Items) { if (it.GetTarget() == InTarget) { it.Add(ERelationType, bUsePercent); return; } } FRelationItem* newItem = new FRelationItem(Owner); newItem->SetTarget(InTarget); newItem->Add(ERelationType, bUsePercent); Items.Add(newItem); } void FRelations::Remove(UGObject * InTarget, ERelationType ERelationType) { int32 Index = 0; while (Index < Items.Num()) { FRelationItem& Item = Items[Index]; if (Item.GetTarget() == InTarget) { Item.Remove(ERelationType); if (Item.IsEmpty()) { Items.RemoveAt(Index); } else Index++; } else Index++; } } bool FRelations::Contains(UGObject * InTarget) { for (auto& it : Items) { if (it.GetTarget() == InTarget) return true; } return false; } void FRelations::ClearFor(UGObject * InTarget) { int32 Index = 0; while (Index < Items.Num()) { FRelationItem& Item = Items[Index]; if (Item.GetTarget() == InTarget) Items.RemoveAt(Index); else Index++; } } void FRelations::ClearAll() { Items.Reset(); } void FRelations::CopyFrom(const FRelations & Source) { ClearAll(); for (auto& it : Source.Items) { FRelationItem* item = new FRelationItem(Owner); item->CopyFrom(it); Items.Add(item); } } void FRelations::OnOwnerSizeChanged(const FVector2D& Delta, bool bApplyPivot) { for (auto& it : Items) it.ApplyOnSelfSizeChanged(Delta.X, Delta.Y, bApplyPivot); } bool FRelations::IsEmpty() const { return Items.Num() == 0; } void FRelations::Setup(FByteBuffer * Buffer, bool bParentToChild) { int32 cnt = Buffer->ReadByte(); UGObject* target; for (int32 i = 0; i < cnt; i++) { int16 targetIndex = Buffer->ReadShort(); if (targetIndex == -1) target = Owner->GetParent(); else if (bParentToChild) target = (Cast(Owner))->GetChildAt(targetIndex); else target = Owner->GetParent()->GetChildAt(targetIndex); FRelationItem* newItem = new FRelationItem(Owner); newItem->SetTarget(target); Items.Add(newItem); int32 cnt2 = Buffer->ReadByte(); for (int32 j = 0; j < cnt2; j++) { ERelationType rt = (ERelationType)Buffer->ReadByte(); bool usePercent = Buffer->ReadBool(); newItem->InternalAdd(rt, usePercent); } } } ================================================ FILE: Source/FairyGUI/Private/UI/ScrollPane.cpp ================================================ #include "UI/ScrollPane.h" #include "Engine/World.h" #include "Engine/GameViewportClient.h" #include "TimerManager.h" #include "UI/UIPackage.h" #include "UI/GList.h" #include "UI/GController.h" #include "UI/GScrollBar.h" #include "Utils/ByteBuffer.h" #include "Tween/GTween.h" #include "Widgets/SContainer.h" #include "FairyApplication.h" TWeakObjectPtr UScrollPane::DraggingPane; int32 UScrollPane::GestureFlag = 0; static const float TWEEN_TIME_GO = 0.5f; //tween time for SetPos(ani) static const float TWEEN_TIME_DEFAULT = 0.3f; //min tween time for inertial scroll static const float PULL_RATIO = 0.5f; //pull down/up ratio static inline float sp_EaseFunc(float t, float d) { t = t / d - 1; return t * t * t + 1; //cubicOut } UScrollPane::UScrollPane() { } UScrollPane::~UScrollPane() { } void UScrollPane::Setup(FByteBuffer* Buffer) { Owner = Cast(GetOuter()); Container = Owner->Container; ScrollStep = FUIConfig::Config.DefaultScrollStep; DecelerationRate = FUIConfig::Config.DefaultScrollDecelerationRate; bTouchEffect = FUIConfig::Config.DefaultScrollTouchEffect; bBouncebackEffect = FUIConfig::Config.DefaultScrollBounceEffect; bMouseWheelEnabled = true; PageSize.Set(0, 0); MaskContainer = SNew(SContainer); MaskContainer->SetOpaque(false); Owner->RootContainer->RemoveChild(Container.ToSharedRef()); Owner->RootContainer->AddChild(MaskContainer.ToSharedRef()); MaskContainer->AddChild(Container.ToSharedRef()); Owner->On(FUIEvents::MouseWheel).AddUObject(this, &UScrollPane::OnMouseWheel); Owner->On(FUIEvents::TouchBegin).AddUObject(this, &UScrollPane::OnTouchBegin); Owner->On(FUIEvents::TouchMove).AddUObject(this, &UScrollPane::OnTouchMove); Owner->On(FUIEvents::TouchEnd).AddUObject(this, &UScrollPane::OnTouchEnd); Owner->On(FUIEvents::RemovedFromStage).AddLambda([this](UEventContext*) { if (DraggingPane.Get() == this) DraggingPane.Reset(); }); ScrollType = (EScrollType)Buffer->ReadByte(); EScrollBarDisplayType scrollBarDisplay = (EScrollBarDisplayType)Buffer->ReadByte(); int32 flags = Buffer->ReadInt(); if (Buffer->ReadBool()) { ScrollBarMargin.Top = Buffer->ReadInt(); ScrollBarMargin.Bottom = Buffer->ReadInt(); ScrollBarMargin.Left = Buffer->ReadInt(); ScrollBarMargin.Right = Buffer->ReadInt(); } const FString& vtScrollBarRes = Buffer->ReadS(); const FString& hzScrollBarRes = Buffer->ReadS(); const FString& headerRes = Buffer->ReadS(); const FString& footerRes = Buffer->ReadS(); bDisplayOnLeft = (flags & 1) != 0; bSnapToItem = (flags & 2) != 0; bDisplayInDemand = (flags & 4) != 0; bPageMode = (flags & 8) != 0; if ((flags & 16) != 0) bTouchEffect = true; else if ((flags & 32) != 0) bTouchEffect = false; if ((flags & 64) != 0) bBouncebackEffect = true; else if ((flags & 128) != 0) bBouncebackEffect = false; bInertiaDisabled = (flags & 256) != 0; if ((flags & 512) == 0) MaskContainer->SetClipping(EWidgetClipping::ClipToBoundsAlways); bFloating = (flags & 1024) != 0; bDontClipMargin = (flags & 2048) != 0; if (scrollBarDisplay == EScrollBarDisplayType::Default) scrollBarDisplay = FUIConfig::Config.DefaultScrollBarDisplay; if (scrollBarDisplay != EScrollBarDisplayType::Hidden) { if (ScrollType == EScrollType::Both || ScrollType == EScrollType::Vertical) { const FString& res = vtScrollBarRes.Len() == 0 ? FUIConfig::Config.VerticalScrollBar : vtScrollBarRes; if (res.Len() > 0) { VtScrollBar = Cast(UUIPackage::CreateObjectFromURL(res, Owner)); if (VtScrollBar == nullptr) { UE_LOG(LogFairyGUI, Warning, TEXT("cannot create scrollbar from %s"), *res); } else { VtScrollBar->SetScrollPane(this, true); Owner->RootContainer->AddChild(VtScrollBar->GetDisplayObject()); } } } if (ScrollType == EScrollType::Both || ScrollType == EScrollType::Horizontal) { const FString& res = hzScrollBarRes.Len() == 0 ? FUIConfig::Config.HorizontalScrollBar : hzScrollBarRes; if (res.Len() > 0) { HzScrollBar = Cast(UUIPackage::CreateObjectFromURL(res, Owner)); if (HzScrollBar == nullptr) { UE_LOG(LogFairyGUI, Warning, TEXT("cannot create scrollbar from %s"), *res); } else { HzScrollBar->SetScrollPane(this, false); Owner->RootContainer->AddChild(HzScrollBar->GetDisplayObject()); } } } bScrollBarDisplayAuto = scrollBarDisplay == EScrollBarDisplayType::Auto; if (bScrollBarDisplayAuto) { if (VtScrollBar != nullptr) VtScrollBar->SetVisible(false); if (HzScrollBar != nullptr) HzScrollBar->SetVisible(false); Owner->On(FUIEvents::RollOver).AddUObject(this, &UScrollPane::OnRollOver); Owner->On(FUIEvents::RollOut).AddUObject(this, &UScrollPane::OnRollOut); } } else bMouseWheelEnabled = false; if (headerRes.Len() > 0) { Header = Cast(UUIPackage::CreateObjectFromURL(headerRes, Owner)); if (Header == nullptr) { UE_LOG(LogFairyGUI, Warning, TEXT("cannot create UScrollPane header from %s"), *headerRes); } else { Header->SetVisible(false); Owner->RootContainer->AddChild(Header->GetDisplayObject()); } } if (footerRes.Len() > 0) { Footer = Cast(UUIPackage::CreateObjectFromURL(footerRes, Owner)); if (Footer == nullptr) { UE_LOG(LogFairyGUI, Warning, TEXT("cannot create UScrollPane footer from %s"), *footerRes); } else { Footer->SetVisible(false); Owner->RootContainer->AddChild(Footer->GetDisplayObject()); } } if (Header != nullptr || Footer != nullptr) RefreshBarAxis = (ScrollType == EScrollType::Both || ScrollType == EScrollType::Vertical) ? 1 : 0; SetSize(Owner->GetSize()); } void UScrollPane::SetPosX(float Value, bool bAnimation) { Owner->EnsureBoundsCorrect(); if (LoopMode == 1) LoopCheckingNewPos(Value, 0); Value = FMath::Clamp(Value, 0.f, OverlapSize.X); if (Value != XPos) { XPos = Value; PosChanged(bAnimation); } } void UScrollPane::SetPosY(float Value, bool bAnimation) { Owner->EnsureBoundsCorrect(); if (LoopMode == 2) LoopCheckingNewPos(Value, 1); Value = FMath::Clamp(Value, 0.f, OverlapSize.Y); if (Value != YPos) { YPos = Value; PosChanged(bAnimation); } } float UScrollPane::GetPercX() const { return OverlapSize.X == 0 ? 0 : XPos / OverlapSize.X; } void UScrollPane::SetPercX(float Value, bool bAnimation) { Owner->EnsureBoundsCorrect(); SetPosX(OverlapSize.X * FMath::Clamp(Value, 0.f, 1.f), bAnimation); } float UScrollPane::GetPercY() const { return OverlapSize.Y == 0 ? 0 : YPos / OverlapSize.Y; } void UScrollPane::SetPercY(float Value, bool bAnimation) { Owner->EnsureBoundsCorrect(); SetPosY(OverlapSize.Y * FMath::Clamp(Value, 0.f, 1.f), bAnimation); } bool UScrollPane::IsBottomMost() const { return YPos == OverlapSize.Y || OverlapSize.Y == 0; } bool UScrollPane::IsRightMost() const { return XPos == OverlapSize.X || OverlapSize.X == 0; } void UScrollPane::ScrollLeft(float Ratio, bool bAnimation) { if (bPageMode) SetPosX(XPos - PageSize.X * Ratio, bAnimation); else SetPosX(XPos - ScrollStep * Ratio, bAnimation); } void UScrollPane::ScrollRight(float Ratio, bool bAnimation) { if (bPageMode) SetPosX(XPos + PageSize.X * Ratio, bAnimation); else SetPosX(XPos + ScrollStep * Ratio, bAnimation); } void UScrollPane::ScrollUp(float Ratio, bool bAnimation) { if (bPageMode) SetPosY(YPos - PageSize.Y * Ratio, bAnimation); else SetPosY(YPos - ScrollStep * Ratio, bAnimation); } void UScrollPane::ScrollDown(float Ratio, bool bAnimation) { if (bPageMode) SetPosY(YPos + PageSize.Y * Ratio, bAnimation); else SetPosY(YPos + ScrollStep * Ratio, bAnimation); } void UScrollPane::ScrollTop(bool bAnimation) { SetPercY(0, bAnimation); } void UScrollPane::ScrollBottom(bool bAnimation) { SetPercY(1, bAnimation); } void UScrollPane::ScrollToView(UGObject* Obj, bool bAnimation, bool bSetFirst) { Owner->EnsureBoundsCorrect(); if (bNeedRefresh) Refresh(); FBox2D rect(Obj->GetPosition(), Obj->GetPosition() + Obj->GetSize()); if (Obj->GetParent() != Owner) { rect = Obj->GetParent()->LocalToGlobalRect(rect); rect = Owner->GlobalToLocalRect(rect); } ScrollToView(rect, bAnimation, bSetFirst); } void UScrollPane::ScrollToView(const FBox2D& Rect, bool bAnimation, bool bSetFirst) { Owner->EnsureBoundsCorrect(); if (bNeedRefresh) Refresh(); if (OverlapSize.Y > 0) { float bottom = YPos + ViewSize.Y; if (bSetFirst || Rect.Min.Y <= YPos || Rect.GetSize().Y >= ViewSize.Y) { if (bPageMode) SetPosY(FMath::FloorToFloat(Rect.Min.Y / PageSize.Y) * PageSize.Y, bAnimation); else SetPosY(Rect.Min.Y, bAnimation); } else if (Rect.Max.Y > bottom) { if (bPageMode) SetPosY(FMath::FloorToFloat(Rect.Min.Y / PageSize.Y) * PageSize.Y, bAnimation); else if (Rect.GetSize().Y <= ViewSize.Y / 2) SetPosY(Rect.Min.Y + Rect.GetSize().Y * 2 - ViewSize.Y, bAnimation); else SetPosY(Rect.Max.Y - ViewSize.Y, bAnimation); } } if (OverlapSize.X > 0) { float right = XPos + ViewSize.X; if (bSetFirst || Rect.Min.X <= XPos || Rect.GetSize().X >= ViewSize.X) { if (bPageMode) SetPosX(FMath::FloorToFloat(Rect.Min.X / PageSize.X) * PageSize.X, bAnimation); SetPosX(Rect.Min.X, bAnimation); } else if (Rect.Max.X > right) { if (bPageMode) SetPosX(FMath::FloorToFloat(Rect.Min.X / PageSize.X) * PageSize.X, bAnimation); else if (Rect.GetSize().X <= ViewSize.X / 2) SetPosX(Rect.Min.X + Rect.GetSize().X * 2 - ViewSize.X, bAnimation); else SetPosX(Rect.Max.X - ViewSize.X, bAnimation); } } if (!bAnimation && bNeedRefresh) Refresh(); } bool UScrollPane::IsChildInView(UGObject* Obj) const { if (OverlapSize.Y > 0) { float dist = Obj->GetY() + Container->GetPosition().Y; if (dist <= -Obj->GetHeight() || dist >= ViewSize.Y) return false; } if (OverlapSize.X > 0) { float dist = Obj->GetX() + Container->GetPosition().X; if (dist <= -Obj->GetWidth() || dist >= ViewSize.X) return false; } return true; } int32 UScrollPane::GetPageX() const { if (!bPageMode) return 0; int32 page = FMath::FloorToInt(XPos / PageSize.X); if (XPos - page * PageSize.X > PageSize.X * 0.5f) page++; return page; } void UScrollPane::SetPageX(int32 Value, bool bAnimation) { if (!bPageMode) return; Owner->EnsureBoundsCorrect(); if (OverlapSize.X > 0) SetPosX(Value * PageSize.X, bAnimation); } int32 UScrollPane::GetPageY() const { if (!bPageMode) return 0; int32 page = FMath::FloorToInt(YPos / PageSize.Y); if (YPos - page * PageSize.Y > PageSize.Y * 0.5f) page++; return page; } void UScrollPane::SetPageY(int32 Value, bool bAnimation) { if (!bPageMode) return; Owner->EnsureBoundsCorrect(); if (OverlapSize.Y > 0) SetPosY(Value * PageSize.Y, bAnimation); } float UScrollPane::GetScrollingPosX() const { return FMath::Clamp(-Container->GetPosition().X, 0.f, OverlapSize.X); } float UScrollPane::GetScrollingPosY() const { return FMath::Clamp(-Container->GetPosition().Y, 0.f, OverlapSize.Y); } void UScrollPane::SetViewWidth(float Width) { Width = Width + Owner->Margin.Left + Owner->Margin.Right; if (VtScrollBar != nullptr && !bFloating) Width += VtScrollBar->GetWidth(); Owner->SetWidth(Width); } void UScrollPane::SetViewHeight(float Height) { Height = Height + Owner->Margin.Top + Owner->Margin.Bottom; if (HzScrollBar != nullptr && !bFloating) Height += HzScrollBar->GetHeight(); Owner->SetHeight(Height); } void UScrollPane::LockHeader(int32 Size) { if (HeaderLockedSize == Size) return; const FVector2D& cpos = Container->GetPosition(); HeaderLockedSize = Size; if (!bDispatchingPullDown && cpos.Component(RefreshBarAxis) >= 0) { TweenStart = cpos; TweenChange.Set(0, 0); TweenChange[RefreshBarAxis] = HeaderLockedSize - TweenStart.Component(RefreshBarAxis); TweenDuration.Set(TWEEN_TIME_DEFAULT, TWEEN_TIME_DEFAULT); StartTween(2); } } void UScrollPane::LockFooter(int32 Size) { if (FooterLockedSize == Size) return; const FVector2D& cpos = Container->GetPosition(); FooterLockedSize = Size; if (!bDispatchingPullUp && cpos.Component(RefreshBarAxis) >= 0) { TweenStart = cpos; TweenChange.Set(0, 0); float max = OverlapSize.Component(RefreshBarAxis); if (max == 0) max = FMath::Max(ContentSize.Component(RefreshBarAxis) + FooterLockedSize - ViewSize.Component(RefreshBarAxis), 0.f); else max += FooterLockedSize; TweenChange.Component(RefreshBarAxis) = -max - TweenStart.Component(RefreshBarAxis); TweenDuration.Set(TWEEN_TIME_DEFAULT, TWEEN_TIME_DEFAULT); StartTween(2); } } void UScrollPane::CancelDragging() { if (DraggingPane.Get() == this) DraggingPane.Reset(); GestureFlag = 0; bDragged = false; } void UScrollPane::HandleControllerChanged(UGController* Controller) { if (PageController == Controller) { if (ScrollType == EScrollType::Horizontal) SetPageX(Controller->GetSelectedIndex(), true); else SetPageY(Controller->GetSelectedIndex(), true); } } void UScrollPane::UpdatePageController() { if (PageController != nullptr && !PageController->bChanging) { int32 index; if (ScrollType == EScrollType::Horizontal) index = GetPageX(); else index = GetPageY(); if (index < PageController->GetPageCount()) { UGController* Controller = PageController; PageController = nullptr; //avoid calling handleControllerChanged Controller->SetSelectedIndex(index); PageController = Controller; } } } void UScrollPane::AdjustMaskContainer() { FVector2D Pos; if (bDisplayOnLeft && VtScrollBar != nullptr && !bFloating) Pos.X = FMath::FloorToFloat(Owner->Margin.Left + VtScrollBar->GetWidth()); else Pos.X = FMath::FloorToFloat(Owner->Margin.Left); Pos.Y = FMath::FloorToFloat(Owner->Margin.Top); Pos += Owner->AlignOffset; MaskContainer->SetPosition(Pos); } void UScrollPane::OnOwnerSizeChanged() { SetSize(Owner->GetSize()); PosChanged(false); } void UScrollPane::SetSize(const FVector2D& InSize) { if (HzScrollBar != nullptr) { HzScrollBar->SetY(InSize.Y - HzScrollBar->GetHeight()); if (VtScrollBar != nullptr) { HzScrollBar->SetWidth(InSize.X - VtScrollBar->GetWidth() - ScrollBarMargin.Left - ScrollBarMargin.Right); if (bDisplayOnLeft) HzScrollBar->SetX(ScrollBarMargin.Left + VtScrollBar->GetWidth()); else HzScrollBar->SetX(ScrollBarMargin.Left); } else { HzScrollBar->SetWidth(InSize.X - ScrollBarMargin.Left - ScrollBarMargin.Right); HzScrollBar->SetX(ScrollBarMargin.Left); } } if (VtScrollBar != nullptr) { if (!bDisplayOnLeft) VtScrollBar->SetX(InSize.X - VtScrollBar->GetWidth()); if (HzScrollBar != nullptr) VtScrollBar->SetHeight(InSize.Y - HzScrollBar->GetHeight() - ScrollBarMargin.Top - ScrollBarMargin.Bottom); else VtScrollBar->SetHeight(InSize.Y - ScrollBarMargin.Top - ScrollBarMargin.Bottom); VtScrollBar->SetY(ScrollBarMargin.Top); } ViewSize = InSize; if (HzScrollBar != nullptr && !bFloating) ViewSize.Y -= HzScrollBar->GetHeight(); if (VtScrollBar != nullptr && !bFloating) ViewSize.X -= VtScrollBar->GetWidth(); ViewSize.X -= (Owner->Margin.Left + Owner->Margin.Right); ViewSize.Y -= (Owner->Margin.Top + Owner->Margin.Bottom); ViewSize.X = FMath::Max(1.f, ViewSize.X); ViewSize.Y = FMath::Max(1.f, ViewSize.Y); PageSize = ViewSize; AdjustMaskContainer(); HandleSizeChanged(); } void UScrollPane::SetContentSize(const FVector2D& InSize) { if (ContentSize == InSize) return; ContentSize = InSize; HandleSizeChanged(); } void UScrollPane::ChangeContentSizeOnScrolling(float DeltaWidth, float DeltaHeight, float DeltaPosX, float DeltaPosY) { bool isRightmost = XPos == OverlapSize.X; bool isBottom = YPos == OverlapSize.Y; ContentSize.X += DeltaWidth; ContentSize.Y += DeltaHeight; HandleSizeChanged(); if (Tweening == 1) { if (DeltaWidth != 0 && isRightmost && TweenChange.X < 0) { XPos = OverlapSize.X; TweenChange.X = -XPos - TweenStart.X; } if (DeltaHeight != 0 && isBottom && TweenChange.Y < 0) { YPos = OverlapSize.Y; TweenChange.Y = -YPos - TweenStart.Y; } } else if (Tweening == 2) { if (DeltaPosX != 0) { Container->SetX(Container->GetPosition().X - DeltaPosX); TweenStart.X -= DeltaPosX; XPos = -Container->GetPosition().X; } if (DeltaPosY != 0) { Container->SetY(Container->GetPosition().Y - DeltaPosY); TweenStart.Y -= DeltaPosY; YPos = -Container->GetPosition().Y; } } else if (bDragged) { if (DeltaPosX != 0) { Container->SetX(Container->GetPosition().X - DeltaPosX); ContainerPos.X -= DeltaPosX; XPos = -Container->GetPosition().X; } if (DeltaPosY != 0) { Container->SetY(Container->GetPosition().Y - DeltaPosY); ContainerPos.Y -= DeltaPosY; YPos = -Container->GetPosition().Y; } } else { if (DeltaWidth != 0 && isRightmost) { XPos = OverlapSize.X; Container->SetX(Container->GetPosition().X - XPos); } if (DeltaHeight != 0 && isBottom) { YPos = OverlapSize.Y; Container->SetY(Container->GetPosition().Y - YPos); } } if (bPageMode) UpdatePageController(); } void UScrollPane::HandleSizeChanged() { if (bDisplayInDemand) { bVScrollNone = ContentSize.Y <= ViewSize.Y; bHScrollNone = ContentSize.X <= ViewSize.X; } if (VtScrollBar != nullptr) { if (ContentSize.Y == 0) VtScrollBar->SetDisplayPerc(0); else VtScrollBar->SetDisplayPerc(FMath::Min(1.f, ViewSize.Y / ContentSize.Y)); } if (HzScrollBar != nullptr) { if (ContentSize.X == 0) HzScrollBar->SetDisplayPerc(0); else HzScrollBar->SetDisplayPerc(FMath::Min(1.f, ViewSize.X / ContentSize.X)); } UpdateScrollBarVisible(); MaskContainer->SetSize(ViewSize); FBox2D maskRect(-Owner->AlignOffset, -Owner->AlignOffset + ViewSize); if (bVScrollNone && VtScrollBar != nullptr) maskRect.Max.X += VtScrollBar->GetWidth(); if (bHScrollNone && HzScrollBar != nullptr) maskRect.Max.Y += HzScrollBar->GetHeight(); if (bDontClipMargin) { maskRect.ShiftBy(FVector2D(-Owner->Margin.Left, -Owner->Margin.Top)); maskRect.Max.X += Owner->Margin.Left + Owner->Margin.Right; maskRect.Max.Y += Owner->Margin.Top + Owner->Margin.Bottom; } MaskContainer->SetCullingBoundsExtension(FMargin(-maskRect.Min.X, -maskRect.Min.Y, maskRect.Max.X - ViewSize.X, maskRect.Max.Y - ViewSize.Y)); if (ScrollType == EScrollType::Horizontal || ScrollType == EScrollType::Both) OverlapSize.X = FMath::CeilToFloat(FMath::Max(0.f, ContentSize.X - ViewSize.X)); else OverlapSize.X = 0; if (ScrollType == EScrollType::Vertical || ScrollType == EScrollType::Both) OverlapSize.Y = FMath::CeilToFloat(FMath::Max(0.f, ContentSize.Y - ViewSize.Y)); else OverlapSize.Y = 0; XPos = FMath::Clamp(XPos, 0.f, OverlapSize.X); YPos = FMath::Clamp(YPos, 0.f, OverlapSize.Y); float max = OverlapSize.Component(RefreshBarAxis); if (max == 0) max = FMath::Max(ContentSize.Component(RefreshBarAxis) + FooterLockedSize - ViewSize.Component(RefreshBarAxis), 0.f); else max += FooterLockedSize; const FVector2D& Pos = Container->GetPosition(); if (RefreshBarAxis == 0) Container->SetPosition(FVector2D(FMath::Clamp(Pos.X, -max, HeaderLockedSize), FMath::Clamp(Pos.Y, -OverlapSize.Y, 0.f))); else Container->SetPosition(FVector2D(FMath::Clamp(Pos.X, -OverlapSize.X, 0.f), FMath::Clamp(Pos.Y, -max, HeaderLockedSize))); if (Header != nullptr) { if (RefreshBarAxis == 0) Header->SetHeight(ViewSize.Y); else Header->SetWidth(ViewSize.X); } if (Footer != nullptr) { if (RefreshBarAxis == 0) Footer->SetHeight(ViewSize.Y); else Footer->SetWidth(ViewSize.X); } UpdateScrollBarPos(); if (bPageMode) UpdatePageController(); } void UScrollPane::PosChanged(bool bAnimation) { if (AniFlag == 0) AniFlag = bAnimation ? 1 : -1; else if (AniFlag == 1 && !bAnimation) AniFlag = -1; bNeedRefresh = true; Owner->GetApp()->DelayCall(RefreshTimerHandle, this, &UScrollPane::Refresh); } void UScrollPane::Refresh() { Owner->GetApp()->CancelDelayCall(RefreshTimerHandle); bNeedRefresh = false; if (bPageMode || bSnapToItem) { FVector2D pos(-XPos, -YPos); AlignPosition(pos, false); XPos = -pos.X; YPos = -pos.Y; } Refresh2(); Owner->DispatchEvent(FUIEvents::Scroll); if (bNeedRefresh) //pos may change in onScroll { bNeedRefresh = false; Owner->GetApp()->CancelDelayCall(RefreshTimerHandle); Refresh2(); } UpdateScrollBarPos(); AniFlag = 0; } void UScrollPane::Refresh2() { if (AniFlag == 1 && !bDragged) { FVector2D pos; if (OverlapSize.X > 0) pos.X = -(int32)XPos; else { if (Container->GetPosition().X != 0) Container->SetX(0); pos.X = 0; } if (OverlapSize.Y > 0) pos.Y = -(int32)YPos; else { if (Container->GetPosition().Y != 0) Container->SetY(0); pos.Y = 0; } if (pos != Container->GetPosition()) { TweenDuration.Set(TWEEN_TIME_GO, TWEEN_TIME_GO); TweenStart = Container->GetPosition(); TweenChange = pos - TweenStart; StartTween(1); } else if (Tweening != 0) KillTween(); } else { if (Tweening != 0) KillTween(); Container->SetPosition(FVector2D((int32)-XPos, (int32)-YPos)); LoopCheckingCurrent(); } if (bPageMode) UpdatePageController(); } void UScrollPane::UpdateScrollBarPos() { if (VtScrollBar != nullptr) VtScrollBar->SetScrollPerc(OverlapSize.Y == 0 ? 0 : FMath::Clamp(-Container->GetPosition().Y, 0.f, OverlapSize.Y) / OverlapSize.Y); if (HzScrollBar != nullptr) HzScrollBar->SetScrollPerc(OverlapSize.X == 0 ? 0 : FMath::Clamp(-Container->GetPosition().X, 0.f, OverlapSize.X) / OverlapSize.X); CheckRefreshBar(); } void UScrollPane::UpdateScrollBarVisible() { if (VtScrollBar != nullptr) { if (ViewSize.Y <= VtScrollBar->GetMinSize() || bVScrollNone) VtScrollBar->SetVisible(false); else UpdateScrollBarVisible2(VtScrollBar); } if (HzScrollBar != nullptr) { if (ViewSize.X <= HzScrollBar->GetMinSize() || bHScrollNone) HzScrollBar->SetVisible(false); else UpdateScrollBarVisible2(HzScrollBar); } } void UScrollPane::UpdateScrollBarVisible2(UGScrollBar* Bar) { if (bScrollBarDisplayAuto) FGTween::Kill(Bar, false); if (bScrollBarDisplayAuto && !bHover && Tweening == 0 && !bDragged && !Bar->bGripDragging) { if (Bar->IsVisible()) FGTween::To(1, 0, 0.5f) ->SetDelay(0.5f) ->OnUpdate(FTweenDelegate::CreateStatic(&FGTweenAction::SetAlpha)) ->OnComplete(FTweenDelegate::CreateUObject(this, &UScrollPane::OnBarTweenComplete)) ->SetTarget(Bar); } else { Bar->SetAlpha(1); Bar->SetVisible(true); } } void UScrollPane::OnBarTweenComplete(FGTweener* Tweener) { UGObject* bar = (UGObject*)Tweener->GetTarget(); bar->SetAlpha(1); bar->SetVisible(false); } float UScrollPane::GetLoopPartSize(float Division, int32 Axis) { return (ContentSize.Component(Axis) + (Axis == 0 ? ((UGList*)Owner)->GetColumnGap() : ((UGList*)Owner)->GetLineGap())) / Division; } bool UScrollPane::LoopCheckingCurrent() { bool changed = false; if (LoopMode == 1 && OverlapSize.X > 0) { if (XPos < 0.001f) { XPos += GetLoopPartSize(2, 0); changed = true; } else if (XPos >= OverlapSize.X) { XPos -= GetLoopPartSize(2, 0); changed = true; } } else if (LoopMode == 2 && OverlapSize.Y > 0) { if (YPos < 0.001f) { YPos += GetLoopPartSize(2, 1); changed = true; } else if (YPos >= OverlapSize.Y) { YPos -= GetLoopPartSize(2, 1); changed = true; } } if (changed) Container->SetPosition(FVector2D((int32)-XPos, (int32)-YPos)); return changed; } void UScrollPane::LoopCheckingTarget(FVector2D& EndPos) { if (LoopMode == 1) LoopCheckingTarget(EndPos, 0); if (LoopMode == 2) LoopCheckingTarget(EndPos, 1); } void UScrollPane::LoopCheckingTarget(FVector2D& EndPos, int32 Axis) { if (EndPos.Component(Axis) > 0) { float halfSize = GetLoopPartSize(2, Axis); float tmp = TweenStart.Component(Axis) - halfSize; if (tmp <= 0 && tmp >= -OverlapSize.Component(Axis)) { EndPos.Component(Axis) = -halfSize; TweenStart.Component(Axis) = tmp; } } else if (EndPos.Component(Axis) < -OverlapSize.Component(Axis)) { float halfSize = GetLoopPartSize(2, Axis); float tmp = TweenStart.Component(Axis) + halfSize; if (tmp <= 0 && tmp >= -OverlapSize.Component(Axis)) { EndPos.Component(Axis) += halfSize; TweenStart.Component(Axis) += tmp; } } } void UScrollPane::LoopCheckingNewPos(float& Value, int32 Axis) { float overlapSize = OverlapSize.Component(Axis); if (overlapSize == 0) return; float pos = Axis == 0 ? XPos : YPos; bool changed = false; if (Value < 0.001f) { Value += GetLoopPartSize(2, Axis); if (Value > pos) { float v = GetLoopPartSize(6, Axis); v = FMath::CeilToFloat((Value - pos) / v) * v; pos = FMath::Clamp(pos + v, 0.f, overlapSize); changed = true; } } else if (Value >= overlapSize) { Value -= GetLoopPartSize(2, Axis); if (Value < pos) { float v = GetLoopPartSize(6, Axis); v = FMath::CeilToFloat((pos - Value) / v) * v; pos = FMath::Clamp(pos - v, 0.f, overlapSize); changed = true; } } if (changed) { if (Axis == 0) Container->SetX(-(int32)pos); else Container->SetY(-(int32)pos); } } void UScrollPane::AlignPosition(FVector2D& Pos, bool bInertialScrolling) { if (bPageMode) { Pos.X = AlignByPage(Pos.X, 0, bInertialScrolling); Pos.Y = AlignByPage(Pos.Y, 1, bInertialScrolling); } else if (bSnapToItem) { FVector2D tmp = Owner->GetSnappingPosition(-Pos); if (Pos.X < 0 && Pos.X > -OverlapSize.X) Pos.X = -tmp.X; if (Pos.Y < 0 && Pos.Y > -OverlapSize.Y) Pos.Y = -tmp.Y; } } float UScrollPane::AlignByPage(float Pos, int32 Axis, bool bInertialScrolling) { int32 page; float pageSize = PageSize.Component(Axis); float overlapSize = OverlapSize.Component(Axis); float contentSize = ContentSize.Component(Axis); if (Pos > 0) page = 0; else if (Pos < -overlapSize) page = FMath::CeilToFloat(contentSize / pageSize) - 1; else { page = FMath::FloorToInt(-Pos / pageSize); float change = bInertialScrolling ? (Pos - ContainerPos.Component(Axis)) : (Pos - Container->GetPosition().Component(Axis)); float testPageSize = FMath::Min(pageSize, contentSize - (page + 1) * pageSize); float delta = -Pos - page * pageSize; if (FMath::Abs(change) > pageSize) { if (delta > testPageSize * 0.5f) page++; } else { if (delta > testPageSize * (change < 0 ? 0.3f : 0.7f)) page++; } Pos = -page * pageSize; if (Pos < -overlapSize) Pos = -overlapSize; } if (bInertialScrolling) { float oldPos = TweenStart.Component(Axis); int32 oldPage; if (oldPos > 0) oldPage = 0; else if (oldPos < -overlapSize) oldPage = FMath::CeilToInt(contentSize / pageSize) - 1; else oldPage = FMath::FloorToInt(-oldPos / pageSize); int32 startPage = FMath::FloorToInt(-ContainerPos.Component(Axis) / pageSize); if (FMath::Abs(page - startPage) > 1 && FMath::Abs(oldPage - startPage) <= 1) { if (page > startPage) page = startPage + 1; else page = startPage - 1; Pos = -page * pageSize; } } return Pos; } FVector2D UScrollPane::UpdateTargetAndDuration(const FVector2D& OrignPos) { FVector2D ret(0, 0); ret.X = UpdateTargetAndDuration(OrignPos.X, 0); ret.Y = UpdateTargetAndDuration(OrignPos.Y, 1); return ret; } float UScrollPane::UpdateTargetAndDuration(float Pos, int32 Axis) { float v = Velocity.Component(Axis); float duration = 0; if (Pos > 0) Pos = 0; else if (Pos < -OverlapSize.Component(Axis)) Pos = -OverlapSize.Component(Axis); else { float v2 = FMath::Abs(v) * VelocityScale; float ratio = 0; if (FPlatformMisc::DesktopTouchScreen()) { if (v2 > 500) ratio = FMath::Pow((v2 - 500) / 500, 2); } else { FVector2D winSize; GWorld->GetGameViewport()->GetViewportSize(winSize); v2 *= 1136.0f / FMath::Max(winSize.X, winSize.Y); if (bPageMode) { if (v2 > 500) ratio = FMath::Pow((v2 - 500) / 500, 2); } else { if (v2 > 1000) ratio = FMath::Pow((v2 - 1000) / 1000, 2); } } if (ratio != 0) { if (ratio > 1) ratio = 1; v2 *= ratio; v *= ratio; Velocity.Component(Axis) = v; duration = FMath::Loge(60 / v2) / FMath::Loge(DecelerationRate) / 60; float change = FMath::FloorToFloat(v * duration * 0.4f); Pos += change; } } if (duration < TWEEN_TIME_DEFAULT) duration = TWEEN_TIME_DEFAULT; TweenDuration.Component(Axis) = duration; return Pos; } void UScrollPane::FixDuration(int32 Axis, float OldChange) { float tweenChange = TweenChange.Component(Axis); if (tweenChange == 0 || FMath::Abs(tweenChange) >= FMath::Abs(OldChange)) return; float newDuration = FMath::Abs(tweenChange / OldChange) * TweenDuration.Component(Axis); if (newDuration < TWEEN_TIME_DEFAULT) newDuration = TWEEN_TIME_DEFAULT; TweenDuration.Component(Axis) = newDuration; } void UScrollPane::StartTween(int32 Type) { TweenTime.Set(0, 0); Tweening = Type; GWorld->GetTimerManager().SetTimer(TickTimerHandle, FTimerDelegate::CreateUObject(this, &UScrollPane::TweenUpdate), 0.016f, true); UpdateScrollBarVisible(); } void UScrollPane::KillTween() { if (Tweening == 1) { FVector2D t = TweenStart + TweenChange; Container->SetPosition(t); Owner->DispatchEvent(FUIEvents::Scroll); } Tweening = 0; GWorld->GetTimerManager().ClearTimer(TickTimerHandle); Owner->DispatchEvent(FUIEvents::ScrollEnd); } void UScrollPane::CheckRefreshBar() { if (Header == nullptr && Footer == nullptr) return; float pos = Container->GetPosition().Component(RefreshBarAxis); if (Header != nullptr) { if (pos > 0) { Header->SetVisible(true); FVector2D vec; vec = Header->GetSize(); vec.Component(RefreshBarAxis) = pos; Header->SetSize(vec); } else Header->SetVisible(false); } if (Footer != nullptr) { float max = OverlapSize.Component(RefreshBarAxis); if (pos < -max || (max == 0 && FooterLockedSize > 0)) { Footer->SetVisible(true); FVector2D vec; vec = Footer->GetPosition(); if (max > 0) vec.Component(RefreshBarAxis) = pos + ContentSize.Component(RefreshBarAxis); else vec.Component(RefreshBarAxis) = FMath::Max(FMath::Min(pos + ViewSize.Component(RefreshBarAxis), ViewSize.Component(RefreshBarAxis) - FooterLockedSize), ViewSize.Component(RefreshBarAxis) - ContentSize.Component(RefreshBarAxis)); Footer->SetPosition(vec); vec = Footer->GetSize(); if (max > 0) vec.Component(RefreshBarAxis) = -max - pos; else vec.Component(RefreshBarAxis) = ViewSize.Component(RefreshBarAxis) - Footer->GetPosition().Component(RefreshBarAxis); Footer->SetSize(vec); } else Footer->SetVisible(false); } } void UScrollPane::TweenUpdate() { float dt = GWorld->GetTimerManager().GetTimerElapsed(TickTimerHandle); float nx = RunTween(0, dt); float ny = RunTween(1, dt); Container->SetPosition(FVector2D(nx, ny)); if (Tweening == 2) { if (OverlapSize.X > 0) XPos = FMath::Clamp(-nx, 0.f, OverlapSize.X); if (OverlapSize.Y > 0) YPos = FMath::Clamp(-ny, 0.f, OverlapSize.Y); if (bPageMode) UpdatePageController(); } if (TweenChange.X == 0 && TweenChange.Y == 0) { Tweening = 0; GWorld->GetTimerManager().ClearTimer(TickTimerHandle); LoopCheckingCurrent(); UpdateScrollBarPos(); UpdateScrollBarVisible(); Owner->DispatchEvent(FUIEvents::Scroll); Owner->DispatchEvent(FUIEvents::ScrollEnd); } else { UpdateScrollBarPos(); Owner->DispatchEvent(FUIEvents::Scroll); } } float UScrollPane::RunTween(int32 Axis, float DeltaTime) { float newValue; if (TweenChange.Component(Axis) != 0) { TweenTime.Component(Axis) += DeltaTime; if (TweenTime.Component(Axis) >= TweenDuration.Component(Axis)) { newValue = TweenStart.Component(Axis) + TweenChange.Component(Axis); TweenChange.Component(Axis) = 0; } else { float ratio = sp_EaseFunc(TweenTime.Component(Axis), TweenDuration.Component(Axis)); newValue = TweenStart.Component(Axis) + (int32)(TweenChange.Component(Axis) * ratio); } float threshold1 = 0; float threshold2 = -OverlapSize.Component(Axis); if (HeaderLockedSize > 0 && RefreshBarAxis == Axis) threshold1 = HeaderLockedSize; if (FooterLockedSize > 0 && RefreshBarAxis == Axis) { float max = OverlapSize.Component(RefreshBarAxis); if (max == 0) max = FMath::Max(ContentSize.Component(RefreshBarAxis) + FooterLockedSize - ViewSize.Component(RefreshBarAxis), 0.f); else max += FooterLockedSize; threshold2 = -max; } if (Tweening == 2 && bBouncebackEffect) { if ((newValue > 20 + threshold1 && TweenChange.Component(Axis) > 0) || (newValue > threshold1 && TweenChange.Component(Axis) == 0)) { TweenTime.Component(Axis) = 0; TweenDuration.Component(Axis) = TWEEN_TIME_DEFAULT; TweenChange.Component(Axis) = -newValue + threshold1; TweenStart.Component(Axis) = newValue; } else if ((newValue < threshold2 - 20 && TweenChange.Component(Axis) < 0) || (newValue < threshold2 && TweenChange.Component(Axis) == 0)) { TweenTime.Component(Axis) = 0; TweenDuration.Component(Axis) = TWEEN_TIME_DEFAULT; TweenChange.Component(Axis) = threshold2 - newValue; TweenStart.Component(Axis) = newValue; } } else { if (newValue > threshold1) { newValue = threshold1; TweenChange.Component(Axis) = 0; } else if (newValue < threshold2) { newValue = threshold2; TweenChange.Component(Axis) = 0; } } } else newValue = Container->GetPosition().Component(Axis); return newValue; } void UScrollPane::OnTouchBegin(UEventContext* Context) { if (!bTouchEffect) return; Context->CaptureTouch(); FVector2D pt = Owner->GlobalToLocal(Context->GetPointerPosition()); if (Tweening != 0) { KillTween(); Owner->GetApp()->CancelClick(Context->GetUserIndex(), Context->GetPointerIndex()); bDragged = true; } else bDragged = false; ContainerPos = Container->GetPosition(); BeginTouchPos = LastTouchPos = pt; LastTouchGlobalPos = Context->GetPointerPosition(); bIsHoldAreaDone = false; Velocity.Set(0, 0); VelocityScale = 1; LastMoveTime = GWorld->GetTimeSeconds(); } void UScrollPane::OnTouchMove(UEventContext* Context) { if (!bTouchEffect) return; if ((DraggingPane.IsValid() && DraggingPane.Get() != this) || UGObject::GetDraggingObject() != nullptr) return; FVector2D pt = Owner->GlobalToLocal(Context->GetPointerPosition()); int32 sensitivity; if (FPlatformMisc::DesktopTouchScreen()) sensitivity = 8; else sensitivity = FUIConfig::Config.TouchScrollSensitivity; float diff; bool sv = false, sh = false; if (ScrollType == EScrollType::Vertical) { if (!bIsHoldAreaDone) { GestureFlag |= 1; diff = FMath::Abs(BeginTouchPos.Y - pt.Y); if (diff < sensitivity) return; if ((GestureFlag & 2) != 0) { float diff2 = FMath::Abs(BeginTouchPos.X - pt.X); if (diff < diff2) return; } } sv = true; } else if (ScrollType == EScrollType::Horizontal) { if (!bIsHoldAreaDone) { GestureFlag |= 2; diff = FMath::Abs(BeginTouchPos.X - pt.X); if (diff < sensitivity) return; if ((GestureFlag & 1) != 0) { float diff2 = FMath::Abs(BeginTouchPos.Y - pt.Y); if (diff < diff2) return; } } sh = true; } else { GestureFlag = 3; if (!bIsHoldAreaDone) { diff = FMath::Abs(BeginTouchPos.Y - pt.Y); if (diff < sensitivity) { diff = FMath::Abs(BeginTouchPos.X - pt.X); if (diff < sensitivity) return; } } sv = sh = true; } FVector2D newPos = (ContainerPos + pt - BeginTouchPos).RoundToVector(); if (sv) { if (newPos.Y > 0) { if (!bBouncebackEffect) Container->SetY(0); else if (Header != nullptr && Header->MaxSize.Y != 0) Container->SetY(((int32)FMath::Min(newPos.Y * 0.5f, Header->MaxSize.Y))); else Container->SetY(((int32)FMath::Min(newPos.Y * 0.5f, ViewSize.Y * PULL_RATIO))); } else if (newPos.Y < -OverlapSize.Y) { if (!bBouncebackEffect) Container->SetY(-OverlapSize.Y); else if (Footer != nullptr && Footer->MaxSize.Y > 0) Container->SetY(((int32)FMath::Max((newPos.Y + OverlapSize.Y) * 0.5f, -Footer->MaxSize.Y) - OverlapSize.Y)); else Container->SetY(((int32)FMath::Max((newPos.Y + OverlapSize.Y) * 0.5f, -ViewSize.Y * PULL_RATIO) - OverlapSize.Y)); } else Container->SetY(newPos.Y); } if (sh) { if (newPos.X > 0) { if (!bBouncebackEffect) Container->SetX(0); else if (Header != nullptr && Header->MaxSize.X != 0) Container->SetX((int32)FMath::Min(newPos.X * 0.5f, Header->MaxSize.X)); else Container->SetX((int32)FMath::Min(newPos.X * 0.5f, ViewSize.X * PULL_RATIO)); } else if (newPos.X < 0 - OverlapSize.X) { if (!bBouncebackEffect) Container->SetX(-OverlapSize.X); else if (Footer != nullptr && Footer->MaxSize.X > 0) Container->SetX((int32)FMath::Max((newPos.X + OverlapSize.X) * 0.5f, -Footer->MaxSize.X) - OverlapSize.X); else Container->SetX((int32)FMath::Max((newPos.X + OverlapSize.X) * 0.5f, -ViewSize.X * PULL_RATIO) - OverlapSize.X); } else Container->SetX(newPos.X); } float deltaTime = FSlateApplication::Get().GetDeltaTime();// GWorld->GetDeltaSeconds(); float elapsed = GWorld->GetTimeSeconds() - LastMoveTime; elapsed = elapsed * 60 - 1; if (elapsed > 1) Velocity *= FMath::Pow(0.833f, elapsed); FVector2D deltaPosition = pt - LastTouchPos; if (!sh) deltaPosition.X = 0; if (!sv) deltaPosition.Y = 0; Velocity = FMath::Lerp(Velocity, deltaPosition / deltaTime, deltaTime * 10); FVector2D deltaGlobalPosition = LastTouchGlobalPos - Context->GetPointerPosition(); if (deltaPosition.X != 0) VelocityScale = FMath::Abs(deltaGlobalPosition.X / deltaPosition.X); else if (deltaPosition.Y != 0) VelocityScale = FMath::Abs(deltaGlobalPosition.Y / deltaPosition.Y); LastTouchPos = pt; LastTouchGlobalPos = Context->GetPointerPosition(); LastMoveTime = GWorld->GetTimeSeconds(); if (OverlapSize.X > 0) XPos = FMath::Clamp(-Container->GetPosition().X, 0.f, OverlapSize.X); if (OverlapSize.Y > 0) YPos = FMath::Clamp(-Container->GetPosition().Y, 0.f, OverlapSize.Y); if (LoopMode != 0) { newPos = Container->GetPosition(); if (LoopCheckingCurrent()) ContainerPos += Container->GetPosition() - newPos; } DraggingPane = this; bIsHoldAreaDone = true; bDragged = true; UpdateScrollBarPos(); UpdateScrollBarVisible(); if (bPageMode) UpdatePageController(); Owner->DispatchEvent(FUIEvents::Scroll); } void UScrollPane::OnTouchEnd(UEventContext* Context) { if (DraggingPane.Get() == this) DraggingPane.Reset(); GestureFlag = 0; if (!bDragged || !bTouchEffect) { bDragged = false; return; } bDragged = false; TweenStart = Container->GetPosition(); FVector2D endPos = TweenStart; bool flag = false; if (Container->GetPosition().X > 0) { endPos.X = 0; flag = true; } else if (Container->GetPosition().X < -OverlapSize.X) { endPos.X = -OverlapSize.X; flag = true; } if (Container->GetPosition().Y > 0) { endPos.Y = 0; flag = true; } else if (Container->GetPosition().Y < -OverlapSize.Y) { endPos.Y = -OverlapSize.Y; flag = true; } if (flag) { TweenChange = endPos - TweenStart; if (TweenChange.X < -FUIConfig::Config.TouchDragSensitivity || TweenChange.Y < -FUIConfig::Config.TouchDragSensitivity) Owner->DispatchEvent(FUIEvents::PullDownRelease); else if (TweenChange.X > FUIConfig::Config.TouchDragSensitivity || TweenChange.Y > FUIConfig::Config.TouchDragSensitivity) Owner->DispatchEvent(FUIEvents::PullUpRelease); if (HeaderLockedSize > 0 && endPos.Component(RefreshBarAxis) == 0) { endPos.Component(RefreshBarAxis) = HeaderLockedSize; TweenChange = endPos - TweenStart; } else if (FooterLockedSize > 0 && endPos.Component(RefreshBarAxis) == -OverlapSize.Component(RefreshBarAxis)) { float max = OverlapSize.Component(RefreshBarAxis); if (max == 0) max = FMath::Max(ContentSize.Component(RefreshBarAxis) + FooterLockedSize - ViewSize.Component(RefreshBarAxis), 0.f); else max += FooterLockedSize; endPos.Component(RefreshBarAxis) = -max; TweenChange = endPos - TweenStart; } TweenDuration.Set(TWEEN_TIME_DEFAULT, TWEEN_TIME_DEFAULT); } else { if (!bInertiaDisabled) { float elapsed = GWorld->GetTimeSeconds() - LastMoveTime; elapsed = elapsed * 60 - 1; if (elapsed > 1) Velocity *= FMath::Pow(0.833f, elapsed); endPos = UpdateTargetAndDuration(TweenStart); } else TweenDuration.Set(TWEEN_TIME_DEFAULT, TWEEN_TIME_DEFAULT); FVector2D oldChange = endPos - TweenStart; LoopCheckingTarget(endPos); if (bPageMode || bSnapToItem) AlignPosition(endPos, true); TweenChange = endPos - TweenStart; if (TweenChange.X == 0 && TweenChange.Y == 0) { UpdateScrollBarVisible(); return; } if (bPageMode || bSnapToItem) { FixDuration(0, oldChange.X); FixDuration(1, oldChange.Y); } } StartTween(2); } void UScrollPane::OnMouseWheel(UEventContext* Context) { if (!bMouseWheelEnabled) return; float delta = -Context->GetPointerEvent().GetWheelDelta(); if (bSnapToItem && FMath::Abs(delta) < 1) delta = FMath::Sign(delta); if (OverlapSize.X > 0 && OverlapSize.Y == 0) { float step = bPageMode ? PageSize.X : ScrollStep; SetPosX(XPos + step * delta, false); } else { float step = bPageMode ? PageSize.Y : ScrollStep; SetPosY(YPos + step * delta, false); } } void UScrollPane::OnRollOver(UEventContext* Context) { bHover = true; UpdateScrollBarVisible(); } void UScrollPane::OnRollOut(UEventContext* Context) { bHover = false; UpdateScrollBarVisible(); } ================================================ FILE: Source/FairyGUI/Private/UI/Transition.cpp ================================================ #include "UI/Transition.h" #include "UI/GComponent.h" #include "UI/UIPackage.h" #include "UI/GController.h" #include "Utils/ByteBuffer.h" #include "Tween/GPath.h" const int32 OPTION_IGNORE_DISPLAY_CONTROLLER = 1; const int32 OPTION_AUTO_STOP_DISABLED = 2; const int32 OPTION_AUTO_STOP_AT_END = 4; struct FAniData { int32 Frame; bool bPlaying; bool bFlag; }; struct FSoundData { FString URL; float Volume; }; struct FInnerTransData { FString Name; int32 PlayTimes; UTransition* Instance; float StopTime; }; struct FShakeData { float Amplitude; float Duration; FVector2D LastOffset; FVector2D Offset; }; struct FTransitionItemData { float f1; float f2; float f3; float f4; bool b1; bool b2; bool b3; FTransitionItemData(); FVector2D GetVec2() const; void SetVec2(const FVector2D& value); FVector4 GetVec4() const; void SetVec4(const FVector4& value); FColor GetColor() const; void SetColor(const FColor& value); }; FTransitionItemData::FTransitionItemData() { f1 = f2 = f3 = f4 = 0; b1 = b2 = true; b3 = false; } FVector2D FTransitionItemData::GetVec2() const { return FVector2D(f1, f2); } void FTransitionItemData::SetVec2(const FVector2D& value) { f1 = value.X; f2 = value.Y; } FVector4 FTransitionItemData::GetVec4() const { return FVector4(f1, f2, f3, f4); } void FTransitionItemData::SetVec4(const FVector4& value) { f1 = value.X; f2 = value.Y; f3 = value.Z; f4 = value.W; } FColor FTransitionItemData::GetColor() const { return FColor(f1*255.f, f2*255.f, f3*255.f, f4*255.f); } void FTransitionItemData::SetColor(const FColor& value) { f1 = value.R / 255.f; f2 = value.G / 255.f; f3 = value.B / 255.f; f4 = value.A / 255.f; } struct FTweenConfig { float Duration; EEaseType EaseType; int32 Repeat; bool bYoyo; FTransitionItemData StartData; FTransitionItemData EndData; TSharedPtr Path; FString EndLabel; FSimpleDelegate EndHook; FTweenConfig(); }; FTweenConfig::FTweenConfig() : EaseType(EEaseType::QuadOut) { } struct FTransitionItem { float Time; FString TargetID; ETransitionActionType Type; TOptional TweenConfig; FString Label; FSimpleDelegate Hook; TOptional Data; TOptional VisibleData; TOptional AniData; TOptional SoundData; TOptional TransData; TOptional ShakeData; TOptional TextData; //running properties FGTweener* Tweener; UGObject* Target; uint32 DisplayLockToken; FTransitionItem(ETransitionActionType aType); ~FTransitionItem(); }; FTransitionItem::FTransitionItem(ETransitionActionType InType) : Time(0), Type(InType), Tweener(nullptr), Target(nullptr), DisplayLockToken(0) { switch (InType) { case ETransitionActionType::XY: case ETransitionActionType::Size: case ETransitionActionType::Scale: case ETransitionActionType::Pivot: case ETransitionActionType::Skew: case ETransitionActionType::Alpha: case ETransitionActionType::Rotation: case ETransitionActionType::Color: case ETransitionActionType::ColorFilter: Data.Emplace(); break; case ETransitionActionType::Animation: AniData.Emplace(); break; case ETransitionActionType::Shake: ShakeData.Emplace(); break; case ETransitionActionType::Sound: SoundData.Emplace(); break; case ETransitionActionType::Transition: TransData.Emplace(); break; case ETransitionActionType::Visible: VisibleData.Emplace(); break; case ETransitionActionType::Text: case ETransitionActionType::Icon: TextData.Emplace(); break; default: break; } } FTransitionItem::~FTransitionItem() { if (Tweener != nullptr) Tweener->Kill(); } UTransition::UTransition() : TotalTimes(0), TotalTasks(0), bPlaying(false), bPaused(false), Options(0), bReversed(false), TotalDuration(0), bAutoPlay(false), AutoPlayDelay(0), TimeScale(1), StartTime(0), EndTime(0) { } UTransition::~UTransition() { if (DelayHandle.IsValid()) FGTween::Kill(DelayHandle); for (auto &it : Items) delete it; } void UTransition::Play(int32 InTimes, float InDelay, float InStartTime, float InEndTime, bool bInReverse, FSimpleDelegate InCompleteCallback) { Stop(true, true); TotalTimes = InTimes; bReversed = bInReverse; StartTime = InStartTime; EndTime = InEndTime; bPlaying = true; bPaused = false; CompleteCallback = InCompleteCallback; int32 cnt = Items.Num(); for (int32 i = 0; i < cnt; i++) { FTransitionItem* item = Items[i]; if (item->Target == nullptr) { if (!item->TargetID.IsEmpty()) item->Target = Owner->GetChildByID(item->TargetID); else item->Target = Owner; } else if (item->Target != Owner && item->Target->GetParent() != Owner) //maybe removed item->Target = nullptr; if (item->Target != nullptr && item->Type == ETransitionActionType::Transition) { UTransition* trans = Cast(item->Target)->GetTransition(item->TransData->Name); if (trans == this) trans = nullptr; if (trans != nullptr) { if (item->TransData->PlayTimes == 0) //stop { int32 j; for (j = i - 1; j >= 0; j--) { FTransitionItem* item2 = Items[j]; if (item2->Type == ETransitionActionType::Transition) { if (item2->TransData->Instance == trans) { item2->TransData->StopTime = item->Time - item2->Time; break; } } } if (j < 0) item->TransData->StopTime = 0; else trans = nullptr; //no need to handle stop anymore } else item->TransData->StopTime = -1; } item->TransData->Instance = trans; } } if (InDelay == 0) OnDelayedPlay(); else DelayHandle = FGTween::DelayedCall(InDelay)->OnComplete(FSimpleDelegate::CreateUObject(this, &UTransition::OnDelayedPlay))->GetHandle(); } void UTransition::ChangePlayTimes(int32 InTimes) { TotalTimes = InTimes; } void UTransition::SetAutoPlay(bool bInAutoPlay, int32 InTimes, float InDelay) { if (bAutoPlay != bInAutoPlay) { bAutoPlay = bInAutoPlay; AutoPlayTimes = InTimes; AutoPlayDelay = InDelay; if (bAutoPlay) { if (Owner->OnStage()) Play(AutoPlayTimes, AutoPlayDelay); } else { if (!Owner->OnStage()) Stop(false, true); } } } void UTransition::Stop(bool bSetToComplete, bool bProcessCallback) { if (!bPlaying) return; bPlaying = false; TotalTasks = 0; TotalTimes = 0; FSimpleDelegate func = CompleteCallback; CompleteCallback.Unbind(); int32 cnt = Items.Num(); if (bReversed) { for (int32 i = cnt - 1; i >= 0; i--) { FTransitionItem* item = Items[i]; if (item->Target == nullptr) continue; StopItem(item, bSetToComplete); } } else { for (int32 i = 0; i < cnt; i++) { FTransitionItem* item = Items[i]; if (item->Target == nullptr) continue; StopItem(item, bSetToComplete); } } if (bProcessCallback) func.ExecuteIfBound(); } void UTransition::StopItem(FTransitionItem* item, bool bSetToComplete) { if (item->DisplayLockToken != 0) { item->Target->ReleaseDisplayLock(item->DisplayLockToken); item->DisplayLockToken = 0; } if (item->Tweener != nullptr) { item->Tweener->Kill(bSetToComplete); item->Tweener = nullptr; if (item->Type == ETransitionActionType::Shake && !bSetToComplete) { item->Target->bGearLocked = true; item->Target->SetPosition(item->Target->GetPosition() - item->ShakeData->LastOffset); item->Target->bGearLocked = false; } } } void UTransition::SetPaused(bool bInPaused) { if (!bPlaying || bPaused == bInPaused) return; bPaused = bInPaused; FGTweener* tweener = FGTween::GetTween(DelayHandle); if (tweener != nullptr) tweener->SetPaused(bPaused); for (auto& item : Items) { if (item->Target == nullptr) continue; if (item->Type == ETransitionActionType::Transition) { if (item->TransData->Instance != nullptr) item->TransData->Instance->SetPaused(bPaused); } else if (item->Type == ETransitionActionType::Animation) { if (bPaused) { item->AniData->bFlag = item->Target->GetProp(EObjectPropID::Playing); item->Target->SetProp(EObjectPropID::Playing, FNVariant(false)); } else item->Target->SetProp(EObjectPropID::Playing, FNVariant(item->AniData->bFlag)); } if (item->Tweener != nullptr) item->Tweener->SetPaused(bPaused); } } void UTransition::SetValue(const FString& InLabel, const TArray& InValues) { FTransitionItemData* Value = nullptr; for (auto& item : Items) { if (item->Label == InLabel) { if (item->TweenConfig.IsSet()) Value = &item->TweenConfig->StartData; else if (item->Data.IsSet()) Value = &item->Data.GetValue(); } else if (item->TweenConfig.IsSet() && item->TweenConfig->EndLabel == InLabel) { Value = &item->TweenConfig->EndData; } else continue; switch (item->Type) { case ETransitionActionType::XY: case ETransitionActionType::Size: case ETransitionActionType::Pivot: case ETransitionActionType::Scale: case ETransitionActionType::Skew: { Value->b1 = true; Value->b2 = true; Value->f1 = InValues[0].AsFloat(); Value->f2 = InValues[1].AsFloat(); break; } case ETransitionActionType::Alpha: case ETransitionActionType::Rotation: Value->f1 = InValues[0].AsFloat(); break; case ETransitionActionType::Color: { Value->SetColor(InValues[0].AsColor()); break; } case ETransitionActionType::Animation: { item->AniData->Frame = InValues[0].AsInt(); if (InValues.Num() > 1) item->AniData->bPlaying = InValues[0].AsBool(); break; } case ETransitionActionType::Visible: item->VisibleData = InValues[0].AsBool(); break; case ETransitionActionType::Sound: { item->SoundData->URL = InValues[0].AsString(); if (InValues.Num() > 1) item->SoundData->Volume = InValues[1].AsFloat(); break; } case ETransitionActionType::Transition: { item->TransData->Name = InValues[0].AsString(); if (InValues.Num() > 1) item->TransData->PlayTimes = InValues[1].AsInt(); break; } case ETransitionActionType::Shake: { item->ShakeData->Amplitude = InValues[0].AsFloat(); if (InValues.Num() > 1) item->ShakeData->Duration = InValues[1].AsFloat(); break; } case ETransitionActionType::ColorFilter: { Value->f1 = InValues[0].AsFloat(); Value->f2 = InValues[1].AsFloat(); Value->f3 = InValues[2].AsFloat(); Value->f4 = InValues[3].AsFloat(); break; } case ETransitionActionType::Text: case ETransitionActionType::Icon: item->TextData = InValues[0].AsString(); break; default: break; } } } void UTransition::SetHook(const FString& InLabel, FSimpleDelegate Callback) { for (auto& item : Items) { if (item->Label == InLabel) { item->Hook = Callback; break; } else if (item->TweenConfig.IsSet() && item->TweenConfig->EndLabel == InLabel) { item->TweenConfig->EndHook = Callback; break; } } } void UTransition::ClearHooks() { for (auto& item : Items) { item->Hook.Unbind(); if (item->TweenConfig.IsSet()) item->TweenConfig->EndHook.Unbind(); } } void UTransition::SetTarget(const FString& InLabel, UGObject* InTarget) { for (auto& item : Items) { if (item->Label == InLabel) { item->TargetID = InTarget->ID; item->Target = nullptr; } } } void UTransition::SetDuration(const FString& InLabel, float InDuration) { for (auto& item : Items) { if (item->TweenConfig.IsSet() && item->Label == InLabel) item->TweenConfig->Duration = InDuration; } } float UTransition::GetLabelTime(const FString& InLabel) const { for (auto& item : Items) { if (item->Label == InLabel) { if (item->TweenConfig.IsSet()) return item->Time + item->TweenConfig->Duration; else return item->Time; } } return NAN; } void UTransition::SetTimeScale(float InTimeScale) { if (TimeScale != InTimeScale) { TimeScale = InTimeScale; for (auto& item : Items) { if (item->Tweener != nullptr) item->Tweener->SetTimeScale(InTimeScale); else if (item->Type == ETransitionActionType::Transition) { if (item->TransData->Instance != nullptr) item->TransData->Instance->SetTimeScale(InTimeScale); } else if (item->Type == ETransitionActionType::Animation) { if (item->Target != nullptr) item->Target->SetProp(EObjectPropID::TimeScale, FNVariant(InTimeScale)); } } } } void UTransition::UpdateFromRelations(const FString& TargetID, const FVector2D& Delta) { int32 cnt = Items.Num(); if (cnt == 0) return; for (auto& item : Items) { if (item->Type == ETransitionActionType::XY && item->TargetID == TargetID) { if (item->TweenConfig.IsSet()) { if (!item->TweenConfig->StartData.b3) { item->TweenConfig->StartData.f1 += Delta.X; item->TweenConfig->StartData.f2 += Delta.Y; item->TweenConfig->EndData.f1 += Delta.X; item->TweenConfig->EndData.f2 += Delta.Y; } } else { if (!item->Data->b3) { item->Data->f1 += Delta.X; item->Data->f2 += Delta.Y; } } } } } void UTransition::OnOwnerAddedToStage() { if (bAutoPlay && !bPlaying) Play(AutoPlayTimes, AutoPlayDelay); } void UTransition::OnOwnerRemovedFromStage() { if ((Options & OPTION_AUTO_STOP_DISABLED) == 0) Stop((Options & OPTION_AUTO_STOP_AT_END) != 0 ? true : false, false); } void UTransition::OnDelayedPlay() { InternalPlay(); bPlaying = TotalTasks > 0; if (bPlaying) { if ((Options & OPTION_IGNORE_DISPLAY_CONTROLLER) != 0) { for (auto& item : Items) { if (item->Target != nullptr && item->Target != Owner) item->DisplayLockToken = item->Target->AddDisplayLock(); } } } else if (CompleteCallback.IsBound()) { FSimpleDelegate func = CompleteCallback; CompleteCallback.Unbind(); func.Execute(); } } void UTransition::InternalPlay() { OwnerBasePos = Owner->GetPosition(); TotalTasks = 0; bool bNeedSkipAnimations = false; int32 cnt = Items.Num(); if (!bReversed) { for (int32 i = 0; i < cnt; i++) { FTransitionItem* item = Items[i]; if (item->Target == nullptr) continue; if (item->Type == ETransitionActionType::Animation && StartTime != 0 && item->Time <= StartTime) { bNeedSkipAnimations = true; item->AniData->bFlag = false; } else PlayItem(item); } } else { for (int32 i = cnt - 1; i >= 0; i--) { FTransitionItem* item = Items[i]; if (item->Target == nullptr) continue; PlayItem(item); } } if (bNeedSkipAnimations) SkipAnimations(); } void UTransition::PlayItem(FTransitionItem* item) { float time; if (item->TweenConfig.IsSet()) { if (bReversed) time = (TotalDuration - item->Time - item->TweenConfig->Duration); else time = item->Time; if (EndTime == -1 || time <= EndTime) { FTransitionItemData* startValue; FTransitionItemData* endValue; if (bReversed) { startValue = &item->TweenConfig->EndData; endValue = &item->TweenConfig->StartData; } else { startValue = &item->TweenConfig->StartData; endValue = &item->TweenConfig->EndData; } item->Data->b1 = startValue->b1 || endValue->b1; item->Data->b2 = startValue->b2 || endValue->b2; switch (item->Type) { case ETransitionActionType::XY: case ETransitionActionType::Size: case ETransitionActionType::Scale: case ETransitionActionType::Skew: item->Tweener = FGTween::To(startValue->GetVec2(), endValue->GetVec2(), item->TweenConfig->Duration); break; case ETransitionActionType::Alpha: case ETransitionActionType::Rotation: item->Tweener = FGTween::To(startValue->f1, endValue->f1, item->TweenConfig->Duration); break; case ETransitionActionType::Color: item->Tweener = FGTween::To(startValue->GetColor(), endValue->GetColor(), item->TweenConfig->Duration); break; case ETransitionActionType::ColorFilter: item->Tweener = FGTween::To(startValue->GetVec4(), endValue->GetVec4(), item->TweenConfig->Duration); break; default: break; } item->Tweener->SetDelay(time) ->SetEase(item->TweenConfig->EaseType) ->SetRepeat(item->TweenConfig->Repeat, item->TweenConfig->bYoyo) ->SetTimeScale(TimeScale) ->SetUserData(FNVariant(item)) ->OnStart(FTweenDelegate::CreateUObject(this, &UTransition::OnTweenStart)) ->OnUpdate(FTweenDelegate::CreateUObject(this, &UTransition::OnTweenUpdate)) ->OnComplete(FTweenDelegate::CreateUObject(this, &UTransition::OnTweenComplete)); if (EndTime >= 0) item->Tweener->SetBreakpoint(EndTime - time); TotalTasks++; } } else if (item->Type == ETransitionActionType::Shake) { if (bReversed) time = (TotalDuration - item->Time - item->ShakeData->Duration); else time = item->Time; if (EndTime == -1 || time <= EndTime) { item->ShakeData->LastOffset.Set(0, 0); item->ShakeData->Offset.Set(0, 0); item->Tweener = FGTween::Shake(FVector2D::ZeroVector, item->ShakeData->Amplitude, item->ShakeData->Duration) ->SetDelay(time) ->SetTimeScale(TimeScale) ->SetUserData(FNVariant(item)) ->OnStart(FTweenDelegate::CreateUObject(this, &UTransition::OnTweenStart)) ->OnUpdate(FTweenDelegate::CreateUObject(this, &UTransition::OnTweenUpdate)) ->OnComplete(FTweenDelegate::CreateUObject(this, &UTransition::OnTweenComplete)); if (EndTime >= 0) item->Tweener->SetBreakpoint(EndTime - item->Time); TotalTasks++; } } else { if (bReversed) time = (TotalDuration - item->Time); else time = item->Time; if (time <= StartTime) { ApplyValue(item); CallHook(item, false); } else if (EndTime == -1 || time <= EndTime) { TotalTasks++; item->Tweener = FGTween::DelayedCall(time) ->SetTimeScale(TimeScale) ->SetUserData(FNVariant(item)) ->OnComplete(FTweenDelegate::CreateUObject(this, &UTransition::OnDelayedPlayItem)); } } if (item->Tweener != nullptr) item->Tweener->Seek(StartTime); } void UTransition::SkipAnimations() { int32 frame; float playStartTime; float playTotalTime; UGObject* target; int32 cnt = Items.Num(); for (int32 i = 0; i < cnt; i++) { FTransitionItem* item = Items[i]; if (item->Type != ETransitionActionType::Animation || item->Time > StartTime) continue; if (item->AniData->bFlag) continue; target = item->Target; frame = target->GetProp(EObjectPropID::Frame); playStartTime = target->GetProp(EObjectPropID::Playing) ? 0 : -1; playTotalTime = 0; for (int32 j = i; j < cnt; j++) { item = Items[j]; if (item->Type != ETransitionActionType::Animation || item->Target != target || item->Time > StartTime) continue; item->AniData->bFlag = true; if (item->AniData->Frame != -1) { frame = item->AniData->Frame; if (item->AniData->bPlaying) playStartTime = item->Time; else playStartTime = -1; playTotalTime = 0; } else { if (item->AniData->bPlaying) { if (playStartTime < 0) playStartTime = item->Time; } else { if (playStartTime >= 0) playTotalTime += (item->Time - playStartTime); playStartTime = -1; } } CallHook(item, false); } if (playStartTime >= 0) playTotalTime += (StartTime - playStartTime); target->SetProp(EObjectPropID::Playing, FNVariant(playStartTime >= 0)); target->SetProp(EObjectPropID::Frame, FNVariant(frame)); if (playTotalTime > 0) target->SetProp(EObjectPropID::DeltaTime, FNVariant(playTotalTime)); } } void UTransition::OnDelayedPlayItem(FGTweener* Tweener) { FTransitionItem* item = (FTransitionItem*)Tweener->GetUserData().As(); item->Tweener = nullptr; TotalTasks--; ApplyValue(item); CallHook(item, false); CheckAllComplete(); } void UTransition::OnTweenStart(FGTweener* Tweener) { FTransitionItem* item = (FTransitionItem*)Tweener->GetUserData().As(); if (item->Type == ETransitionActionType::XY || item->Type == ETransitionActionType::Size) { FTransitionItemData* startValue; FTransitionItemData* endValue; if (bReversed) { startValue = &item->TweenConfig->EndData; endValue = &item->TweenConfig->StartData; } else { startValue = &item->TweenConfig->StartData; endValue = &item->TweenConfig->EndData; } if (item->Type == ETransitionActionType::XY) { if (item->Target != Owner) { if (!startValue->b1) Tweener->StartValue.X = item->Target->GetX(); else if (startValue->b3) //percent Tweener->StartValue.X = startValue->f1 * Owner->GetWidth(); if (!startValue->b2) Tweener->StartValue.Y = item->Target->GetY(); else if (startValue->b3) //percent Tweener->StartValue.Y = startValue->f2 * Owner->GetHeight(); if (!endValue->b1) Tweener->EndValue.X = Tweener->StartValue.X; else if (endValue->b3) Tweener->EndValue.X = endValue->f1 * Owner->GetWidth(); if (!endValue->b2) Tweener->EndValue.Y = Tweener->StartValue.Y; else if (endValue->b3) Tweener->EndValue.Y = endValue->f2 * Owner->GetHeight(); } else { if (!startValue->b1) Tweener->StartValue.X = item->Target->GetX() - OwnerBasePos.X; if (!startValue->b2) Tweener->StartValue.Y = item->Target->GetY() - OwnerBasePos.Y; if (!endValue->b1) Tweener->EndValue.X = Tweener->StartValue.X; if (!endValue->b2) Tweener->EndValue.Y = Tweener->StartValue.Y; } } else { if (!startValue->b1) Tweener->StartValue.X = item->Target->GetWidth(); if (!startValue->b2) Tweener->StartValue.Y = item->Target->GetHeight(); if (!endValue->b1) Tweener->EndValue.X = Tweener->StartValue.X; if (!endValue->b2) Tweener->EndValue.Y = Tweener->StartValue.Y; } if (item->TweenConfig->Path.IsValid()) { item->Data->b1 = item->Data->b2 = true; Tweener->SetPath(item->TweenConfig->Path); } } CallHook(item, false); } void UTransition::OnTweenUpdate(FGTweener* Tweener) { FTransitionItem* item = (FTransitionItem*)Tweener->GetUserData().As(); switch (item->Type) { case ETransitionActionType::XY: case ETransitionActionType::Size: case ETransitionActionType::Scale: case ETransitionActionType::Skew: if (item->TweenConfig->Path.IsValid()) item->Data->SetVec2(Tweener->Value.GetVec2() + Tweener->StartValue.GetVec2()); else item->Data->SetVec2(Tweener->Value.GetVec2()); break; case ETransitionActionType::Alpha: case ETransitionActionType::Rotation: item->Data->f1 = Tweener->Value.X; break; case ETransitionActionType::Color: item->Data->SetColor(Tweener->Value.GetColor()); break; case ETransitionActionType::ColorFilter: item->Data->SetVec4(Tweener->Value.GetVec4()); break; case ETransitionActionType::Shake: item->ShakeData->Offset = Tweener->DeltaValue.GetVec2(); break; default: break; } ApplyValue(item); } void UTransition::OnTweenComplete(FGTweener* Tweener) { FTransitionItem* item = (FTransitionItem*)Tweener->GetUserData().As(); item->Tweener = nullptr; TotalTasks--; if (Tweener->AllCompleted()) CallHook(item, true); CheckAllComplete(); } void UTransition::OnPlayTransCompleted(FTransitionItem* item) { TotalTasks--; CheckAllComplete(); } void UTransition::CallHook(FTransitionItem* item, bool bTweenEnd) { if (bTweenEnd) { if (item->TweenConfig.IsSet() && item->TweenConfig->EndHook.IsBound()) item->TweenConfig->EndHook.Execute(); } else { if (item->Time >= StartTime && item->Hook.IsBound()) item->Hook.Execute(); } } void UTransition::CheckAllComplete() { if (bPlaying && TotalTasks == 0) { if (TotalTimes < 0) { InternalPlay(); } else { TotalTimes--; if (TotalTimes > 0) InternalPlay(); else { bPlaying = false; for (auto& item : Items) { if (item->Target != nullptr && item->DisplayLockToken != 0) { item->Target->ReleaseDisplayLock(item->DisplayLockToken); item->DisplayLockToken = 0; } } if (CompleteCallback.IsBound()) { FSimpleDelegate func = CompleteCallback; CompleteCallback.Unbind(); func.Execute(); } } } } } void UTransition::ApplyValue(FTransitionItem* item) { item->Target->bGearLocked = true; switch (item->Type) { case ETransitionActionType::XY: { if (item->Target == Owner) { if (item->Data->b1 && item->Data->b2) item->Target->SetPosition(item->Data->GetVec2() + OwnerBasePos); else if (item->Data->b1) item->Target->SetX(item->Data->f1 + OwnerBasePos.X); else item->Target->SetY(item->Data->f2 + OwnerBasePos.Y); } else { if (item->Data->b3) //position in percent { if (item->Data->b1 && item->Data->b2) item->Target->SetPosition(item->Data->GetVec2() * Owner->GetSize()); else if (item->Data->b1) item->Target->SetX(item->Data->f1 * Owner->GetWidth()); else if (item->Data->b2) item->Target->SetY(item->Data->f2 * Owner->GetHeight()); } else { if (item->Data->b1 && item->Data->b2) item->Target->SetPosition(item->Data->GetVec2()); else if (item->Data->b1) item->Target->SetX(item->Data->f1); else if (item->Data->b2) item->Target->SetY(item->Data->f2); } } } break; case ETransitionActionType::Size: { if (!item->Data->b1) item->Data->f1 = item->Target->GetWidth(); if (!item->Data->b2) item->Data->f2 = item->Target->GetHeight(); item->Target->SetSize(item->Data->GetVec2()); } break; case ETransitionActionType::Pivot: item->Target->SetPivot(item->Data->GetVec2(), item->Target->IsPivotAsAnchor()); break; case ETransitionActionType::Alpha: item->Target->SetAlpha(item->Data->f1); break; case ETransitionActionType::Rotation: item->Target->SetRotation(item->Data->f1); break; case ETransitionActionType::Scale: item->Target->SetScale(item->Data->GetVec2()); break; case ETransitionActionType::Skew: item->Target->SetSkew(item->Data->GetVec2()); break; case ETransitionActionType::Color: item->Target->SetProp(EObjectPropID::Color, FNVariant(item->Data->GetColor())); break; case ETransitionActionType::Animation: { if (item->AniData->Frame >= 0) item->Target->SetProp(EObjectPropID::Frame, FNVariant(item->AniData->Frame)); item->Target->SetProp(EObjectPropID::Playing, FNVariant(item->AniData->bPlaying)); item->Target->SetProp(EObjectPropID::TimeScale, FNVariant(TimeScale)); break; } case ETransitionActionType::Visible: item->Target->SetVisible(item->VisibleData.GetValue()); break; case ETransitionActionType::Shake: { item->Target->SetPosition(item->Target->GetPosition() - item->ShakeData->LastOffset + item->ShakeData->Offset); item->ShakeData->LastOffset = item->ShakeData->Offset; break; } case ETransitionActionType::Transition: if (bPlaying) { if (item->TransData->Instance != nullptr) { TotalTasks++; float playStartTime = StartTime > item->Time ? (StartTime - item->Time) : 0; float playEndTime = EndTime >= 0 ? (EndTime - item->Time) : -1; if (item->TransData->StopTime >= 0 && (playEndTime < 0 || playEndTime > item->TransData->StopTime)) playEndTime = item->TransData->StopTime; item->TransData->Instance->SetTimeScale(TimeScale); item->TransData->Instance->Play(item->TransData->PlayTimes, 0, playStartTime, playEndTime, bReversed, FSimpleDelegate::CreateUObject(this, &UTransition::OnPlayTransCompleted, item)); } } break; case ETransitionActionType::Sound: if (bPlaying && item->Time >= StartTime) { if (!item->SoundData->URL.IsEmpty()) Owner->GetApp()->PlaySound(item->SoundData->URL, item->SoundData->Volume); break; } case ETransitionActionType::ColorFilter: break; case ETransitionActionType::Text: item->Target->SetText(item->TextData.GetValue()); break; case ETransitionActionType::Icon: item->Target->SetIcon(item->TextData.GetValue()); break; default: break; } item->Target->bGearLocked = false; } void UTransition::Setup(FByteBuffer* Buffer) { Owner = Cast(GetOuter()); Name = Buffer->ReadS(); Options = Buffer->ReadInt(); bAutoPlay = Buffer->ReadBool(); AutoPlayTimes = Buffer->ReadInt(); AutoPlayDelay = Buffer->ReadFloat(); int32 cnt = Buffer->ReadShort(); for (int32 i = 0; i < cnt; i++) { int32 dataLen = Buffer->ReadShort(); int32 curPos = Buffer->GetPos(); Buffer->Seek(curPos, 0); Items.Add(new FTransitionItem((ETransitionActionType)Buffer->ReadByte())); FTransitionItem* item = Items.Last(); item->Time = Buffer->ReadFloat(); int32 TargetID = Buffer->ReadShort(); if (TargetID < 0) item->TargetID = G_EMPTY_STRING; else item->TargetID = Owner->GetChildAt(TargetID)->ID; item->Label = Buffer->ReadS(); if (Buffer->ReadBool()) { Buffer->Seek(curPos, 1); item->TweenConfig.Emplace(); item->TweenConfig->Duration = Buffer->ReadFloat(); if (item->Time + item->TweenConfig->Duration > TotalDuration) TotalDuration = item->Time + item->TweenConfig->Duration; item->TweenConfig->EaseType = (EEaseType)Buffer->ReadByte(); item->TweenConfig->Repeat = Buffer->ReadInt(); item->TweenConfig->bYoyo = Buffer->ReadBool(); item->TweenConfig->EndLabel = Buffer->ReadS(); Buffer->Seek(curPos, 2); DecodeValue(item, Buffer, &item->TweenConfig->StartData); Buffer->Seek(curPos, 3); DecodeValue(item, Buffer, &item->TweenConfig->EndData); if (Buffer->Version >= 2) { int32 pathLen = Buffer->ReadInt(); if (pathLen > 0) { item->TweenConfig->Path = MakeShareable(new FGPath()); TArray pts; FVector v0(ForceInit), v1(ForceInit), v2(ForceInit); for (int32 j = 0; j < pathLen; j++) { FGPathPoint::ECurveType curveType = (FGPathPoint::ECurveType)Buffer->ReadByte(); switch (curveType) { case FGPathPoint::ECurveType::Bezier: v0.X = Buffer->ReadFloat(); v0.Y = Buffer->ReadFloat(); v1.X = Buffer->ReadFloat(); v1.Y = Buffer->ReadFloat(); pts.Add(FGPathPoint(v0, v1)); break; case FGPathPoint::ECurveType::CubicBezier: v0.X = Buffer->ReadFloat(); v0.Y = Buffer->ReadFloat(); v1.X = Buffer->ReadFloat(); v1.Y = Buffer->ReadFloat(); v2.X = Buffer->ReadFloat(); v2.Y = Buffer->ReadFloat(); pts.Add(FGPathPoint(v0, v1, v2)); break; default: v0.X = Buffer->ReadFloat(); v0.Y = Buffer->ReadFloat(); pts.Add(FGPathPoint(v0, curveType)); break; } } item->TweenConfig->Path->Create(pts.GetData(), pts.Num()); } } } else { if (item->Time > TotalDuration) TotalDuration = item->Time; Buffer->Seek(curPos, 2); DecodeValue(item, Buffer, item->Data.IsSet() ? &item->Data.GetValue() : nullptr); } Buffer->SetPos(curPos + dataLen); } } void UTransition::DecodeValue(FTransitionItem* item, FByteBuffer* Buffer, FTransitionItemData* Value) { switch (item->Type) { case ETransitionActionType::XY: case ETransitionActionType::Size: case ETransitionActionType::Pivot: case ETransitionActionType::Skew: { Value->b1 = Buffer->ReadBool(); Value->b2 = Buffer->ReadBool(); Value->f1 = Buffer->ReadFloat(); Value->f2 = Buffer->ReadFloat(); if (Buffer->Version >= 2 && item->Type == ETransitionActionType::XY) Value->b3 = Buffer->ReadBool(); //percent break; } case ETransitionActionType::Alpha: case ETransitionActionType::Rotation: Value->f1 = Buffer->ReadFloat(); break; case ETransitionActionType::Scale: { Value->f1 = Buffer->ReadFloat(); Value->f2 = Buffer->ReadFloat(); break; } case ETransitionActionType::Color: Value->SetColor(Buffer->ReadColor()); break; case ETransitionActionType::Animation: { item->AniData->bPlaying = Buffer->ReadBool(); item->AniData->Frame = Buffer->ReadInt(); break; } case ETransitionActionType::Visible: item->VisibleData = Buffer->ReadBool(); break; case ETransitionActionType::Sound: { item->SoundData->URL = Buffer->ReadS(); item->SoundData->Volume = Buffer->ReadFloat(); break; } case ETransitionActionType::Transition: { item->TransData->Name = Buffer->ReadS(); item->TransData->PlayTimes = Buffer->ReadInt(); break; } case ETransitionActionType::Shake: { item->ShakeData->Amplitude = Buffer->ReadFloat(); item->ShakeData->Duration = Buffer->ReadFloat(); break; } case ETransitionActionType::ColorFilter: { Value->f1 = Buffer->ReadFloat(); Value->f2 = Buffer->ReadFloat(); Value->f3 = Buffer->ReadFloat(); Value->f4 = Buffer->ReadFloat(); break; } case ETransitionActionType::Text: case ETransitionActionType::Icon: item->TextData = Buffer->ReadS(); break; default: break; } } ================================================ FILE: Source/FairyGUI/Private/UI/TranslationHelper.cpp ================================================ #include "UI/TranslationHelper.h" TMap> FTranslationHelper::Strings; void FTranslationHelper::LoadFromXML(const FString XmlString) { } void FTranslationHelper::TranslateComponent(const TSharedPtr& Item) { } ================================================ FILE: Source/FairyGUI/Private/UI/UIConfig.cpp ================================================ #include "UI/UIConfig.h" #include "FairyApplication.h" FUIConfig FUIConfig::Config; FUIConfig::FUIConfig() : ButtonSoundVolumeScale(1), DefaultScrollStep(25), DefaultScrollDecelerationRate(0.967f), DefaultScrollTouchEffect(true), DefaultScrollBounceEffect(true), DefaultScrollBarDisplay(EScrollBarDisplayType::Default), TouchDragSensitivity(10), ClickDragSensitivity(2), TouchScrollSensitivity(20), DefaultComboBoxVisibleItemCount(10), ModalLayerColor(0, 0, 0, 120), BringWindowToFrontOnClick(true) { } ================================================ FILE: Source/FairyGUI/Private/UI/UIObjectFactory.cpp ================================================ #include "UI/UIObjectFactory.h" #include "UI/UIPackage.h" #include "UI/PackageItem.h" #include "UI/GComponent.h" #include "UI/GImage.h" #include "UI/GMovieClip.h" #include "UI/GTextField.h" #include "UI/GRichTextField.h" #include "UI/GTextInput.h" #include "UI/GGraph.h" #include "UI/GLoader.h" #include "UI/GLoader3D.h" #include "UI/GGroup.h" #include "UI/GLabel.h" #include "UI/GButton.h" #include "UI/GComboBox.h" #include "UI/GProgressBar.h" #include "UI/GSlider.h" #include "UI/GScrollBar.h" #include "UI/GList.h" #include "UI/GTree.h" TMap FUIObjectFactory::PackageItemExtensions; TSubclassOf FUIObjectFactory::LoaderExtension; void FUIObjectFactory::SetExtension(const FString& URL, FGComponentCreator Creator) { if (URL.IsEmpty()) { UE_LOG(LogFairyGUI, Warning, TEXT("Invaild url: %s"), *URL); return; } TSharedPtr PackageItem = UUIPackage::GetItemByURL(URL); if (PackageItem.IsValid()) PackageItem->ExtensionCreator = Creator; PackageItemExtensions.Add(URL, Creator); } void FUIObjectFactory::SetExtension(const FString& URL, TSubclassOf ClassType) { SetExtension(URL, FGComponentCreator::CreateLambda([ClassType](UObject* Outer) { return ::NewObject(Outer, ClassType); })); } UGObject* FUIObjectFactory::NewObject(const TSharedPtr& PackageItem, UObject* Outer) { UGObject* obj = nullptr; if (PackageItem->ExtensionCreator.IsBound()) obj = PackageItem->ExtensionCreator.Execute(Outer); else obj = NewObject(PackageItem->ObjectType, Outer); if (obj != nullptr) obj->PackageItem = PackageItem; return obj; } UGObject* FUIObjectFactory::NewObject(EObjectType Type, UObject* Outer) { switch (Type) { case EObjectType::Image: return ::NewObject(Outer); case EObjectType::MovieClip: return ::NewObject(Outer); case EObjectType::Component: return ::NewObject(Outer); case EObjectType::Text: return ::NewObject(Outer); case EObjectType::RichText: return ::NewObject(Outer); case EObjectType::InputText: return ::NewObject(Outer); case EObjectType::Group: return ::NewObject(Outer); case EObjectType::List: return ::NewObject(Outer); case EObjectType::Graph: return ::NewObject(Outer); case EObjectType::Loader: if (LoaderExtension != nullptr) return ::NewObject(Outer, LoaderExtension); else return ::NewObject(Outer); case EObjectType::Button: return ::NewObject(Outer); case EObjectType::Label: return ::NewObject(Outer); case EObjectType::ProgressBar: return ::NewObject(Outer); case EObjectType::Slider: return ::NewObject(Outer); case EObjectType::ScrollBar: return ::NewObject(Outer); case EObjectType::ComboBox: return ::NewObject(Outer); case EObjectType::Tree: return ::NewObject(Outer); case EObjectType::Loader3D: return ::NewObject(Outer); default: return nullptr; } } void FUIObjectFactory::ResolvePackageItemExtension(const TSharedPtr& PackageItem) { auto it = PackageItemExtensions.Find("ui://" + PackageItem->Owner->GetID() + PackageItem->ID); if (it != nullptr) { PackageItem->ExtensionCreator = *it; return; } it = PackageItemExtensions.Find("ui://" + PackageItem->Owner->GetName() + "/" + PackageItem->Name); if (it != nullptr) { PackageItem->ExtensionCreator = *it; return; } PackageItem->ExtensionCreator = nullptr; } ================================================ FILE: Source/FairyGUI/Private/UI/UIPackage.cpp ================================================ #include "UI/UIPackage.h" #include "Sound/SoundBase.h" #include "UIPackageAsset.h" #include "UI/PackageItem.h" #include "UI/GObject.h" #include "Widgets/NTexture.h" #include "Widgets/SMovieClip.h" #include "Widgets/BitmapFont.h" #include "Utils/ByteBuffer.h" #include "UI/UIObjectFactory.h" int32 UUIPackage::Constructing = 0; struct FAtlasSprite { FAtlasSprite() : Rect(ForceInit), OriginalSize(ForceInit), Offset(ForceInit), bRotated(false) { } TSharedPtr Atlas; FBox2D Rect; FVector2D OriginalSize; FVector2D Offset; bool bRotated; }; const FString& UUIPackage::GetBranch() { return UUIPackageStatic::Get().Branch; } void UUIPackage::SetBranch(const FString& InBranch) { UUIPackageStatic::Get().Branch = InBranch; bool empty = InBranch.IsEmpty(); for (auto& it : UUIPackageStatic::Get().PackageInstByID) { UUIPackage*& Pkg = it.Value; if (empty) Pkg->BranchIndex = -1; else if (Pkg->Branches.Num() > 0) Pkg->BranchIndex = Pkg->Branches.Find(InBranch); } } FString UUIPackage::GetVar(const FString& VarKey) { FString* Value = UUIPackageStatic::Get().Vars.Find(VarKey); if (Value != nullptr) return *Value; else return G_EMPTY_STRING; } void UUIPackage::SetVar(const FString& VarKey, const FString& VarValue) { UUIPackageStatic::Get().Vars.Add(VarKey, VarValue); } UUIPackage* UUIPackage::AddPackage(const TCHAR* InAssetPath, UObject* WorldContextObject) { UUIPackageAsset* PackageAsset = Cast(StaticLoadObject(UUIPackageAsset::StaticClass(), nullptr, InAssetPath)); verifyf(PackageAsset != nullptr, TEXT("Asset not found %s"), InAssetPath); return AddPackage(PackageAsset, WorldContextObject); } UUIPackage* UUIPackage::AddPackage(UUIPackageAsset* InAsset, UObject* WorldContextObject) { verifyf(WorldContextObject != nullptr, TEXT("Null WorldContextObject?")); UWorld* World = WorldContextObject->GetWorld(); verifyf(World != nullptr, TEXT("Null World?")); verifyf(World->IsGameWorld(), TEXT("Not a Game World?")); UUIPackage* Pkg = UUIPackageStatic::Get().PackageInstByID.FindRef(InAsset->GetPathName()); if (Pkg != nullptr) { if (Pkg->RefWorlds.Contains(World->GetUniqueID())) { UE_LOG(LogFairyGUI, Warning, TEXT("Package already addedd")); } else Pkg->RefWorlds.Add(World->GetUniqueID()); return Pkg; } FByteBuffer Buffer(InAsset->Data.GetData(), 0, InAsset->Data.Num(), false); Pkg = NewObject(); Pkg->RefWorlds.Add(World->GetUniqueID()); Pkg->Asset = InAsset; Pkg->AssetPath = InAsset->GetPathName(); Pkg->Load(&Buffer); UUIPackageStatic::Get().PackageList.Add(Pkg); UUIPackageStatic::Get().PackageInstByID.Add(Pkg->ID, Pkg); UUIPackageStatic::Get().PackageInstByID.Add(Pkg->AssetPath, Pkg); UUIPackageStatic::Get().PackageInstByName.Add(Pkg->Name, Pkg); return Pkg; } void UUIPackage::RemovePackage(const FString& IDOrName, UObject* WorldContextObject) { verifyf(WorldContextObject != nullptr, TEXT("Null WorldContextObject?")); UUIPackage* Pkg = GetPackageByName(IDOrName); if (Pkg == nullptr) Pkg = GetPackageByID(IDOrName); if (Pkg != nullptr) { UWorld* World = WorldContextObject->GetWorld(); verifyf(World != nullptr, TEXT("Null World?")); verifyf(World->IsGameWorld(), TEXT("Not a Game World?")); Pkg->RefWorlds.Remove(World->GetUniqueID()); if (Pkg->RefWorlds.Num() > 0) return; UUIPackageStatic::Get().PackageList.Remove(Pkg); UUIPackageStatic::Get().PackageInstByID.Remove(Pkg->ID); UUIPackageStatic::Get().PackageInstByID.Remove(Pkg->AssetPath); UUIPackageStatic::Get().PackageInstByName.Remove(Pkg->Name); } else UE_LOG(LogFairyGUI, Error, TEXT("invalid package name or id: %s"), *IDOrName); } void UUIPackage::RemoveAllPackages() { UUIPackageStatic::Get().PackageList.Reset(); UUIPackageStatic::Get().PackageInstByID.Reset(); UUIPackageStatic::Get().PackageInstByName.Reset(); } UUIPackage* UUIPackage::GetPackageByID(const FString& PackageID) { auto it = UUIPackageStatic::Get().PackageInstByID.Find(PackageID); if (it != nullptr) return *it; else return nullptr; } UUIPackage* UUIPackage::GetPackageByName(const FString& PackageName) { auto it = UUIPackageStatic::Get().PackageInstByName.Find(PackageName); if (it != nullptr) return *it; else return nullptr; } UGObject* UUIPackage::CreateObject(const FString& PackageName, const FString& ResourceName, UObject* WorldContextObject, TSubclassOf ClassType) { UUIPackage* pkg = UUIPackage::GetPackageByName(PackageName); if (pkg) return pkg->CreateObject(ResourceName, WorldContextObject); else return nullptr; } UGObject* UUIPackage::CreateObjectFromURL(const FString& URL, UObject* WorldContextObject, TSubclassOf ClassType) { TSharedPtr pii = UUIPackage::GetItemByURL(URL); if (pii.IsValid()) return pii->Owner->CreateObject(pii, WorldContextObject); else return nullptr; } FString UUIPackage::GetItemURL(const FString& PackageName, const FString& ResourceName) { UUIPackage* pkg = GetPackageByName(PackageName); if (pkg != nullptr) { TSharedPtr pii = pkg->GetItemByName(ResourceName); if (pii.IsValid()) return "ui://" + pkg->GetID() + pii->ID; } return ""; } TSharedPtr UUIPackage::GetItemByURL(const FString& URL) { if (URL.IsEmpty()) return nullptr; int32 pos1; if (!URL.FindChar('/', pos1)) return nullptr; int32 pos2 = URL.Find("/", ESearchCase::CaseSensitive, ESearchDir::FromStart, pos1 + 2); if (pos2 == -1) { if (URL.Len() > 13) { FString pkgId = URL.Mid(5, 8); UUIPackage* pkg = GetPackageByID(pkgId); if (pkg != nullptr) { FString srcId = URL.Mid(13); return pkg->GetItem(srcId); } } } else { FString pkgName = URL.Mid(pos1 + 2, pos2 - pos1 - 2); UUIPackage* pkg = GetPackageByName(pkgName); if (pkg != nullptr) { FString srcName = URL.Mid(pos2 + 1); return pkg->GetItemByName(srcName); } } return nullptr; } FString UUIPackage::NormalizeURL(const FString& URL) { if (URL.IsEmpty()) return URL; int32 pos1; if (!URL.FindChar('/', pos1)) return URL; int32 pos2 = URL.Find("/", ESearchCase::CaseSensitive, ESearchDir::FromStart, pos1 + 2); if (pos2 == -1) return URL; else { FString pkgName = URL.Mid(pos1 + 2, pos2 - pos1 - 2); FString srcName = URL.Mid(pos2 + 1); return GetItemURL(pkgName, srcName); } } UUIPackage::UUIPackage() { } UUIPackage::~UUIPackage() { for (auto& it : Sprites) delete it.Value; } TSharedPtr UUIPackage::GetItem(const FString& ItemID) const { auto it = ItemsByID.Find(ItemID); if (it != nullptr) return *it; else return nullptr; } TSharedPtr UUIPackage::GetItemByName(const FString& ResourceName) { auto it = ItemsByName.Find(ResourceName); if (it != nullptr) return *it; else return nullptr; } UGObject* UUIPackage::CreateObject(const FString& ResourceName, UObject* WorldContextObject) { TSharedPtr item = GetItemByName(ResourceName); verifyf(item.IsValid(), TEXT("FairyGUI: resource not found - %s in %s"), *ResourceName, *Name); return CreateObject(item, WorldContextObject); } UGObject* UUIPackage::CreateObject(const TSharedPtr& Item, UObject* WorldContextObject) { UGObject* g = FUIObjectFactory::NewObject(Item, WorldContextObject); if (g == nullptr) return nullptr; Constructing++; g->ConstructFromResource(); Constructing--; return g; } void UUIPackage::RegisterFont(const FString& FontFace, UObject* Font) { UUIPackageStatic::Get().Fonts.Add(FontFace, Font); } void UUIPackage::Load(FByteBuffer* Buffer) { if (Buffer->ReadUint() != 0x46475549) { UE_LOG(LogFairyGUI, Error, TEXT("not valid package format in %d '%s'"), Buffer->ReadUint(), *AssetPath); return; } Buffer->Version = Buffer->ReadInt(); bool ver2 = Buffer->Version >= 2; Buffer->ReadBool(); //compressed ID = Buffer->ReadString(); Name = Buffer->ReadString(); Buffer->Skip(20); int32 indexTablePos = Buffer->GetPos(); int32 cnt; Buffer->Seek(indexTablePos, 4); cnt = Buffer->ReadInt(); TArray* StringTable = new TArray(); StringTable->SetNum(cnt, true); for (int32 i = 0; i < cnt; i++) { (*StringTable)[i] = Buffer->ReadString(); } Buffer->StringTable = MakeShareable(StringTable); Buffer->Seek(indexTablePos, 0); cnt = Buffer->ReadShort(); for (int32 i = 0; i < cnt; i++) { TMap info; info.Add("id", Buffer->ReadS()); info.Add("name", Buffer->ReadS()); Dependencies.Push(info); } bool branchIncluded = false; if (ver2) { cnt = Buffer->ReadShort(); if (cnt > 0) { Buffer->ReadSArray(Branches, cnt); if (!UUIPackageStatic::Get().Branch.IsEmpty()) BranchIndex = Branches.Find(UUIPackageStatic::Get().Branch); } branchIncluded = cnt > 0; } Buffer->Seek(indexTablePos, 1); FString path = FPaths::GetPath(AssetPath); FString fileName = FPaths::GetBaseFilename(AssetPath); cnt = Buffer->ReadShort(); for (int32 i = 0; i < cnt; i++) { int32 nextPos = Buffer->ReadInt(); nextPos += Buffer->GetPos(); TSharedPtr pii = MakeShared(); pii->Owner = this; pii->Type = (EPackageItemType)Buffer->ReadByte(); pii->ID = Buffer->ReadS(); pii->Name = Buffer->ReadS(); Buffer->Skip(2); //path pii->File = Buffer->ReadS(); Buffer->ReadBool(); //exported pii->Size.X = Buffer->ReadInt(); pii->Size.Y = Buffer->ReadInt(); switch (pii->Type) { case EPackageItemType::Image: { pii->ObjectType = EObjectType::Image; int32 scaleOption = Buffer->ReadByte(); if (scaleOption == 1) { FBox2D scale9Grid(ForceInit); scale9Grid.Min.X = Buffer->ReadInt(); scale9Grid.Min.Y = Buffer->ReadInt(); scale9Grid.Max.X = scale9Grid.Min.X + Buffer->ReadInt(); scale9Grid.Max.Y = scale9Grid.Min.Y + Buffer->ReadInt(); pii->Scale9Grid = scale9Grid; pii->TileGridIndice = Buffer->ReadInt(); } else if (scaleOption == 2) pii->bScaleByTile = true; Buffer->ReadBool(); //smoothing break; } case EPackageItemType::MovieClip: { Buffer->ReadBool(); //smoothing pii->ObjectType = EObjectType::MovieClip; pii->RawData = Buffer->ReadBuffer(false); break; } case EPackageItemType::Font: { pii->RawData = Buffer->ReadBuffer(false); break; } case EPackageItemType::Component: { int32 extension = Buffer->ReadByte(); if (extension > 0) pii->ObjectType = (EObjectType)extension; else pii->ObjectType = EObjectType::Component; pii->RawData = Buffer->ReadBuffer(false); FUIObjectFactory::ResolvePackageItemExtension(pii); break; } case EPackageItemType::Atlas: case EPackageItemType::Sound: case EPackageItemType::Misc: { FString file = fileName + "_" + FPaths::GetBaseFilename(pii->File); pii->File = path + "/" + file + "." + file; break; } case EPackageItemType::Spine: case EPackageItemType::DragonBones: { pii->File = path + pii->File; break; } default: break; } if (ver2) { FString str = Buffer->ReadS(); //branch if (!str.IsEmpty()) pii->Name = str + "/" + pii->Name; int32 branchCnt = Buffer->ReadUbyte(); if (branchCnt > 0) { if (branchIncluded) { pii->Branches.Emplace(); Buffer->ReadSArray(pii->Branches.GetValue(), branchCnt); } else ItemsByID.Add(Buffer->ReadS(), pii); } int32 highResCnt = Buffer->ReadUbyte(); if (highResCnt > 0) { pii->HighResolution.Emplace(); Buffer->ReadSArray(pii->HighResolution.GetValue(), highResCnt); } } Items.Push(pii); ItemsByID.Add(pii->ID, pii); if (!pii->Name.IsEmpty()) ItemsByName.Add(pii->Name, pii); Buffer->SetPos(nextPos); } Buffer->Seek(indexTablePos, 2); cnt = Buffer->ReadShort(); for (int32 i = 0; i < cnt; i++) { int32 nextPos = Buffer->ReadShort(); nextPos += Buffer->GetPos(); const FString& itemId = Buffer->ReadS(); const TSharedPtr& pii = ItemsByID[Buffer->ReadS()]; FAtlasSprite* sprite = new FAtlasSprite(); sprite->Atlas = pii; sprite->Rect.Min.X = Buffer->ReadInt(); sprite->Rect.Min.Y = Buffer->ReadInt(); sprite->Rect.Max.X = sprite->Rect.Min.X + Buffer->ReadInt(); sprite->Rect.Max.Y = sprite->Rect.Min.Y + Buffer->ReadInt(); sprite->bRotated = Buffer->ReadBool(); if (ver2 && Buffer->ReadBool()) { sprite->Offset.X = Buffer->ReadInt(); sprite->Offset.Y = Buffer->ReadInt(); sprite->OriginalSize.X = Buffer->ReadInt(); sprite->OriginalSize.Y = Buffer->ReadInt(); } else if (sprite->bRotated) { sprite->Offset.Set(0, 0); sprite->OriginalSize.X = sprite->Rect.GetSize().Y; sprite->OriginalSize.Y = sprite->Rect.GetSize().X; } else { sprite->Offset.Set(0, 0); sprite->OriginalSize = sprite->Rect.GetSize(); } Sprites.Add(itemId, sprite); Buffer->SetPos(nextPos); } if (Buffer->Seek(indexTablePos, 3)) { cnt = Buffer->ReadShort(); for (int32 i = 0; i < cnt; i++) { int32 nextPos = Buffer->ReadInt(); nextPos += Buffer->GetPos(); TSharedPtr pii = ItemsByID.FindRef(Buffer->ReadS()); if (pii.IsValid() && pii->Type == EPackageItemType::Image) { pii->PixelHitTestData = MakeShareable(new FPixelHitTestData()); pii->PixelHitTestData->Load(Buffer); } Buffer->SetPos(nextPos); } } } void* UUIPackage::GetItemAsset(const TSharedPtr& Item) { switch (Item->Type) { case EPackageItemType::Image: if (Item->Texture == nullptr) LoadImage(Item); return Item->Texture; case EPackageItemType::Atlas: if (Item->Texture == nullptr) LoadAtlas(Item); return Item->Texture; case EPackageItemType::Font: if (Item->BitmapFont == nullptr) LoadFont(Item); return Item->BitmapFont.Get(); case EPackageItemType::MovieClip: if (!Item->MovieClipData.IsValid()) LoadMovieClip(Item); return Item->MovieClipData.Get(); case EPackageItemType::Sound: if (!Item->Sound.IsValid()) LoadSound(Item); return Item->Sound.Get(); default: return nullptr; } } void UUIPackage::LoadAtlas(const TSharedPtr& Item) { UObject* Texture = StaticLoadObject(UTexture2D::StaticClass(), this, *Item->File); Item->Texture = NewObject(this); Item->Texture->Init(Cast(Texture)); } void UUIPackage::LoadImage(const TSharedPtr& Item) { FAtlasSprite* sprite = Sprites.FindRef(Item->ID); if (sprite != nullptr) { UNTexture* atlas = (UNTexture*)GetItemAsset(sprite->Atlas); if (atlas->GetSize() == sprite->Rect.GetSize()) Item->Texture = atlas; else { Item->Texture = NewObject(this); Item->Texture->Init(atlas, sprite->Rect, sprite->bRotated, sprite->OriginalSize, sprite->Offset); } } } void UUIPackage::LoadMovieClip(const TSharedPtr& Item) { TSharedPtr Data = MakeShared(); Item->MovieClipData = Data; FByteBuffer* Buffer = Item->RawData.Get(); Buffer->Seek(0, 0); Data->Interval = Buffer->ReadInt() / 1000.0f; Data->bSwing = Buffer->ReadBool(); Data->RepeatDelay = Buffer->ReadInt() / 1000.0f; Buffer->Seek(0, 1); int32 frameCount = Buffer->ReadShort(); Data->Frames.Reserve(frameCount); FAtlasSprite* sprite; for (int32 i = 0; i < frameCount; i++) { int32 nextPos = Buffer->ReadShort(); nextPos += Buffer->GetPos(); FMovieClipData::Frame Frame; FBox2D FrameRect; FrameRect.Min.X = Buffer->ReadInt(); FrameRect.Min.Y = Buffer->ReadInt(); FrameRect.Max.X = FrameRect.Min.X + Buffer->ReadInt(); FrameRect.Max.Y = FrameRect.Min.Y + Buffer->ReadInt(); Frame.AddDelay = Buffer->ReadInt() / 1000.0f; const FString& spriteId = Buffer->ReadS(); if (!spriteId.IsEmpty() && (sprite = Sprites.FindRef(spriteId)) != nullptr) { Frame.Texture = NewObject(this); Frame.Texture->Init((UNTexture*)GetItemAsset(sprite->Atlas), sprite->Rect, sprite->bRotated, Item->Size, FrameRect.Min); } Data->Frames.Add(MoveTemp(Frame)); Buffer->SetPos(nextPos); } Item->RawData.Reset(); } void UUIPackage::LoadFont(const TSharedPtr& Item) { TSharedPtr BitmapFont = MakeShared(); Item->BitmapFont = BitmapFont; FByteBuffer* Buffer = Item->RawData.Get(); Buffer->Seek(0, 0); bool bTTF = Buffer->ReadBool(); BitmapFont->bCanTint = Buffer->ReadBool(); BitmapFont->bResizable = Buffer->ReadBool(); BitmapFont->bHasChannel = Buffer->ReadBool(); //hasChannel BitmapFont->FontSize = Buffer->ReadInt(); int32 XAdvance = Buffer->ReadInt(); int32 LineHeight = Buffer->ReadInt(); FVector2D GlyphTexCoords(0, 0); FVector2D GlyphOffset(0, 0); FVector2D GlyphSize(0, 0); const FAtlasSprite* MainSprite = nullptr; if (bTTF && (MainSprite = Sprites.FindRef(Item->ID)) != nullptr) BitmapFont->Texture = (UNTexture*)GetItemAsset(MainSprite->Atlas); Buffer->Seek(0, 1); int32 cnt = Buffer->ReadInt(); for (int32 i = 0; i < cnt; i++) { int32 nextPos = Buffer->ReadShort(); nextPos += Buffer->GetPos(); FBitmapFont::FGlyph Glyph; TCHAR ch = Buffer->ReadUshort(); const FString& img = Buffer->ReadS(); GlyphTexCoords.X = Buffer->ReadInt(); GlyphTexCoords.Y = Buffer->ReadInt(); GlyphOffset.X = Buffer->ReadInt(); GlyphOffset.Y = Buffer->ReadInt(); GlyphSize.X = Buffer->ReadInt(); GlyphSize.Y = Buffer->ReadInt(); Glyph.XAdvance = Buffer->ReadInt(); Glyph.Channel = Buffer->ReadByte(); if (bTTF) { FVector2D TexCoords = MainSprite->Rect.Min + GlyphTexCoords; Glyph.UVRect = FBox2D(TexCoords / BitmapFont->Texture->GetSize(), (TexCoords + GlyphSize) / BitmapFont->Texture->GetSize()); Glyph.Offset = GlyphOffset; Glyph.Size = GlyphSize; Glyph.LineHeight = LineHeight; } else { TSharedPtr CharImg = GetItem(img); if (CharImg.IsValid()) { CharImg = CharImg->GetBranch(); GlyphSize = CharImg->Size; CharImg = CharImg->GetHighResolution(); GetItemAsset(CharImg); Glyph.UVRect = CharImg->Texture->UVRect; FVector2D TexScale = GlyphSize / CharImg->Size; Glyph.Offset = GlyphOffset + CharImg->Texture->Offset * TexScale; Glyph.Size = CharImg->Size * TexScale; if (BitmapFont->Texture == nullptr) BitmapFont->Texture = CharImg->Texture->Root; } if (BitmapFont->FontSize == 0) BitmapFont->FontSize = (int32)GlyphSize.Y; if (Glyph.XAdvance == 0) { if (XAdvance == 0) Glyph.XAdvance = GlyphOffset.X + GlyphSize.X; else Glyph.XAdvance = XAdvance; } Glyph.LineHeight = GlyphOffset.Y < 0 ? GlyphSize.Y : (GlyphOffset.Y + GlyphSize.Y); if (Glyph.LineHeight < BitmapFont->FontSize) Glyph.LineHeight = BitmapFont->FontSize; } BitmapFont->Glyphs.Add(ch, Glyph); Buffer->SetPos(nextPos); } Item->RawData.Reset(); } void UUIPackage::LoadSound(const TSharedPtr& Item) { TSharedPtr Sound = MakeShared(); Item->Sound = Sound; UObject* SoundObject = StaticLoadObject(USoundBase::StaticClass(), this, *Item->File); Sound->SetResourceObject(SoundObject); } UUIPackageStatic* UUIPackageStatic::Singleton = nullptr; UUIPackageStatic& UUIPackageStatic::Get() { if (Singleton == nullptr) { Singleton = NewObject(); Singleton->AddToRoot(); } return *Singleton; } void UUIPackageStatic::Destroy() { if (Singleton != nullptr) { Singleton->RemoveFromRoot(); Singleton = nullptr; } } ================================================ FILE: Source/FairyGUI/Private/UIPackageAsset.cpp ================================================ #include "UIPackageAsset.h" #include "EditorFramework/AssetImportData.h" #if WITH_EDITORONLY_DATA void UUIPackageAsset::GetAssetRegistryTags(TArray& OutTags) const { if (AssetImportData) { OutTags.Add(FAssetRegistryTag(SourceFileTagName(), AssetImportData->GetSourceData().ToJson(), FAssetRegistryTag::TT_Hidden)); #if WITH_EDITOR AssetImportData->AppendAssetRegistryTags(OutTags); #endif } Super::GetAssetRegistryTags(OutTags); } #endif ================================================ FILE: Source/FairyGUI/Private/Utils/ByteBuffer.cpp ================================================ #include "Utils/ByteBuffer.h" FByteBuffer::FByteBuffer(const uint8* InBuffer, int32 InOffset, int32 InLen, bool bInTransferOwnerShip) : bLittleEndian(false), Version(0), Buffer(InBuffer), Offset(InOffset), Length(InLen), Position(0), bOwnsBuffer(bInTransferOwnerShip) { } FByteBuffer::~FByteBuffer() { if (bOwnsBuffer && Buffer != nullptr) FMemory::Free((void *)Buffer); } int32 FByteBuffer::GetBytesAvailable() const { return Length - Position; } int8 FByteBuffer::ReadByte() { signed char val = Buffer[Offset + Position]; if (val > 127) val = val - 255; Position += 1; return val; } uint8 FByteBuffer::ReadUbyte() { unsigned char val = Buffer[Offset + Position]; Position += 1; return val; } bool FByteBuffer::ReadBool() { return ReadByte() == 1; } int16 FByteBuffer::ReadShort() { int32 startIndex = Offset + Position; Position += 2; uint8* pbyte = (uint8*)(Buffer + startIndex); if (bLittleEndian) return (int16)((*pbyte) | (*(pbyte + 1) << 8)); else return (int16)((*pbyte << 8) | (*(pbyte + 1))); } uint16 FByteBuffer::ReadUshort() { return (uint16)ReadShort(); } int32 FByteBuffer::ReadInt() { int32 startIndex = Offset + Position; Position += 4; uint8* pbyte = (uint8*)(Buffer + startIndex); if (bLittleEndian) return (*pbyte) | (*(pbyte + 1) << 8) | (*(pbyte + 2) << 16) | (*(pbyte + 3) << 24); else return (*pbyte << 24) | (*(pbyte + 1) << 16) | (*(pbyte + 2) << 8) | (*(pbyte + 3)); } uint32 FByteBuffer::ReadUint() { return (uint32)ReadInt(); } float FByteBuffer::ReadFloat() { int32 val = ReadInt(); return *(float*)&val; } FString FByteBuffer::ReadString() { int32 len = ReadUshort(); return ReadString(len); } FString FByteBuffer::ReadString(int32 InLen) { uint8* value = (uint8*)FMemory::Malloc(InLen + 1); value[InLen] = '\0'; FMemory::Memcpy(value, Buffer + Position, InLen); Position += InLen; FString str = UTF8_TO_TCHAR(value); FMemory::Free(value); return str; } const FString& FByteBuffer::ReadS() { uint16 index = ReadUshort(); if (index == 65534 || index == 65533) return G_EMPTY_STRING; else return (*StringTable)[index]; } bool FByteBuffer::ReadS(FString& OutString) { uint16 index = ReadUshort(); if (index == 65534) //null return false; else if (index == 65533) { OutString.Reset(); return true; } else { OutString = (*StringTable)[index]; return true; } } const FString* FByteBuffer::ReadSP() { uint16 index = ReadUshort(); if (index == 65534) //null return nullptr; else if (index == 65533) return &G_EMPTY_STRING; else return &(*StringTable)[index]; } void FByteBuffer::ReadSArray(TArray& OutArray, int32 InCount) { for (int32 i = 0; i < InCount; i++) OutArray.Push(ReadS()); } void FByteBuffer::WriteS(const FString& InString) { uint16 index = ReadUshort(); if (index != 65534 && index != 65533) (*StringTable)[index] = InString; } FColor FByteBuffer::ReadColor() { int32 startIndex = Offset + Position; uint8 r = Buffer[startIndex]; uint8 g = Buffer[startIndex + 1]; uint8 b = Buffer[startIndex + 2]; uint8 a = Buffer[startIndex + 3]; Position += 4; return FColor(r, g, b, a); } TSharedPtr FByteBuffer::ReadBuffer(bool bCloneBuffer) { int32 count = ReadInt(); FByteBuffer* ba; if (bCloneBuffer) { uint8* p = (uint8*)FMemory::Malloc(count); memcpy(p, Buffer + Position, count); ba = new FByteBuffer(p, 0, count, true); } else ba = new FByteBuffer(Buffer, Position, count, false); ba->StringTable = StringTable; ba->Version = Version; Position += count; return MakeShareable(ba); } bool FByteBuffer::Seek(int32 IndexTablePos, int32 BlockIndex) { int32 tmp = Position; Position = IndexTablePos; int32 segCount = Buffer[Offset + Position++]; if (BlockIndex < segCount) { bool useShort = Buffer[Offset + Position++] == 1; int32 newPos; if (useShort) { Position += 2 * BlockIndex; newPos = ReadShort(); } else { Position += 4 * BlockIndex; newPos = ReadInt(); } if (newPos > 0) { Position = IndexTablePos + newPos; return true; } else { Position = tmp; return false; } } else { Position = tmp; return false; } } ================================================ FILE: Source/FairyGUI/Private/Utils/HTMLElement.cpp ================================================ #include "Utils/HTMLElement.h" ================================================ FILE: Source/FairyGUI/Private/Utils/HTMLParser.cpp ================================================ #include "Utils/HTMLParser.h" #include "Utils/XMLIterator.h" enum class SupportedTagNames { INVALID, B, I, U, STRIKE, SUB, SUP, FONT, BR, IMG, A, INPUT, SELECT, P, UI, DIV, LI, HTML, BODY, HEAD, STYLE, SCRIPT, FORM }; FHTMLParser FHTMLParser::DefaultParser; FHTMLParseOptions FHTMLParser::DefaultParseOptions; FHTMLParser::FHTMLParser() { } void FHTMLParser::Parse(const FString& InText, const FNTextFormat& InFormat, TArray& OutElements, const FHTMLParseOptions& InParseOptions) { ParseOptions = InParseOptions; Elements = &OutElements; TextFormatStack.Reset(); (FNTextFormat&)Format = InFormat; Format.bColorChanged = false; int32 skipText = 0; bool ignoreWhiteSpace = ParseOptions.bIgnoreWhiteSpace; bool skipNextCR = false; FString text; static const TMap TagConstMap = { { "b", SupportedTagNames::B }, { "i", SupportedTagNames::I }, { "u", SupportedTagNames::U }, { "strike", SupportedTagNames::STRIKE }, { "sub", SupportedTagNames::SUP }, { "font", SupportedTagNames::FONT }, { "br", SupportedTagNames::BR }, { "img", SupportedTagNames::IMG }, { "a", SupportedTagNames::A }, { "input", SupportedTagNames::INPUT }, { "select", SupportedTagNames::SELECT }, { "p", SupportedTagNames::P }, { "ui", SupportedTagNames::UI }, { "div", SupportedTagNames::DIV }, { "li", SupportedTagNames::LI }, { "html", SupportedTagNames::HTML }, { "body", SupportedTagNames::BODY }, { "head", SupportedTagNames::HEAD }, { "style", SupportedTagNames::STYLE }, { "script", SupportedTagNames::SCRIPT }, { "form", SupportedTagNames::FORM }, }; FXMLIterator XMLIterator; XMLIterator.Begin(InText, true); while (XMLIterator.NextTag()) { if (skipText == 0) { text = XMLIterator.GetText(ignoreWhiteSpace); if (text.Len() > 0) { if (skipNextCR && text[0] == '\n') text = text.Mid(1); AppendText(text); } } skipNextCR = false; switch (TagConstMap.FindRef(XMLIterator.TagName)) { case SupportedTagNames::B: if (XMLIterator.TagType == EXMLTagType::Start) { PushTextFormat(); Format.bBold = true; } else PopTextFormat(); break; case SupportedTagNames::I: if (XMLIterator.TagType == EXMLTagType::Start) { PushTextFormat(); Format.bItalic = true; } else PopTextFormat(); break; case SupportedTagNames::U: if (XMLIterator.TagType == EXMLTagType::Start) { PushTextFormat(); Format.bUnderline = true; } else PopTextFormat(); break; case SupportedTagNames::STRIKE: if (XMLIterator.TagType == EXMLTagType::Start) { PushTextFormat(); //Format.strikethrough = true; } else PopTextFormat(); break; case SupportedTagNames::SUB: break; case SupportedTagNames::SUP: break; case SupportedTagNames::FONT: if (XMLIterator.TagType == EXMLTagType::Start) { PushTextFormat(); XMLIterator.ParseAttributes(); Format.Size = XMLIterator.Attributes.GetInt("size", Format.Size); const FString& color = XMLIterator.Attributes.Get("color"); if (color.Len() > 0) { Format.Color = FColor::FromHex(color); Format.bColorChanged = true; } } else if (XMLIterator.TagType == EXMLTagType::End) PopTextFormat(); break; case SupportedTagNames::BR: AppendText("\n"); break; case SupportedTagNames::IMG: if (XMLIterator.TagType == EXMLTagType::Start || XMLIterator.TagType == EXMLTagType::Void) { XMLIterator.ParseAttributes(); FHTMLElement element; element.Type = EHTMLElementType::Image; element.Attributes.Append(XMLIterator.Attributes); element.Name = element.Attributes.Get("name"); element.Format.Align = Format.Align; Elements->Add(MoveTemp(element)); } break; case SupportedTagNames::A: if (XMLIterator.TagType == EXMLTagType::Start) { PushTextFormat(); Format.bUnderline = Format.bUnderline || ParseOptions.bLinkUnderline; if (!Format.bColorChanged && ParseOptions.LinkColor.A != 0) Format.Color = ParseOptions.LinkColor; FHTMLElement element; element.Type = EHTMLElementType::Link; XMLIterator.ParseAttributes(); element.Attributes.Append(XMLIterator.Attributes); element.Name = element.Attributes.Get("name"); element.Format.Align = Format.Align; Elements->Add(MoveTemp(element)); } else if (XMLIterator.TagType == EXMLTagType::End) { PopTextFormat(); FHTMLElement element; element.Type = EHTMLElementType::LinkEnd; Elements->Add(MoveTemp(element)); } break; case SupportedTagNames::INPUT: { FHTMLElement element; element.Type = EHTMLElementType::Input; XMLIterator.ParseAttributes(); element.Attributes.Append(XMLIterator.Attributes); element.Name = element.Attributes.Get("name"); element.Format = Format; Elements->Add(element); } break; case SupportedTagNames::SELECT: { if (XMLIterator.TagType == EXMLTagType::Start || XMLIterator.TagType == EXMLTagType::Void) { FHTMLElement element; element.Type = EHTMLElementType::Select; XMLIterator.ParseAttributes(); if (XMLIterator.TagType == EXMLTagType::Start) { FString Items, Values; while (XMLIterator.NextTag()) { if (XMLIterator.TagName == "select") break; if (XMLIterator.TagName == "option") { if (XMLIterator.TagType == EXMLTagType::Start || XMLIterator.TagType == EXMLTagType::Void) { if (!Values.IsEmpty()) Values.AppendChar(','); Values.Append(XMLIterator.Attributes.Get("value")); } else { if (!Items.IsEmpty()) Items.AppendChar(','); Items.Append(XMLIterator.GetText()); } } } element.Attributes.Add("items", Items); element.Attributes.Add("values", Values); } element.Name = element.Attributes.Get("name"); element.Format = Format; Elements->Add(element); } } break; case SupportedTagNames::P: if (XMLIterator.TagType == EXMLTagType::Start) { PushTextFormat(); const FString& align = XMLIterator.Attributes.Get("align"); if (align == "center") Format.Align = EAlignType::Center; else if (align == "right") Format.Align = EAlignType::Right; if (!IsNewLine()) AppendText("\n"); } else if (XMLIterator.TagType == EXMLTagType::End) { AppendText("\n"); skipNextCR = true; PopTextFormat(); } break; case SupportedTagNames::UI: case SupportedTagNames::DIV: case SupportedTagNames::LI: if (XMLIterator.TagType == EXMLTagType::Start) { if (!IsNewLine()) AppendText("\n"); } else { AppendText("\n"); skipNextCR = true; } break; case SupportedTagNames::HTML: case SupportedTagNames::BODY: //full html ignoreWhiteSpace = true; break; case SupportedTagNames::HEAD: case SupportedTagNames::STYLE: case SupportedTagNames::SCRIPT: case SupportedTagNames::FORM: if (XMLIterator.TagType == EXMLTagType::Start) skipText++; else if (XMLIterator.TagType == EXMLTagType::End) skipText--; break; } } if (skipText == 0) { text = XMLIterator.GetText(ignoreWhiteSpace); if (text.Len() > 0) { if (skipNextCR && text[0] == '\n') text = text.Mid(1); AppendText(text); } } } void FHTMLParser::PushTextFormat() { TextFormatStack.Add(Format); } void FHTMLParser::PopTextFormat() { Format = TextFormatStack.Pop(); } bool FHTMLParser::IsNewLine() { if (Elements->Num() > 0) { const FHTMLElement& element = Elements->Last(); if (element.Type == EHTMLElementType::Text) return element.Text.EndsWith("\n"); else return false; } return true; } void FHTMLParser::AppendText(const FString& Text) { if (Elements->Num() > 0) { FHTMLElement& element = Elements->Last(); if (element.Type == EHTMLElementType::Text && element.Format.EqualStyle(Format)) { element.Text.Append(Text); return; } } { FHTMLElement element; element.Type = EHTMLElementType::Text; element.Text = Text; element.Format = Format; Elements->Add(element); } } ================================================ FILE: Source/FairyGUI/Private/Utils/NVariant.cpp ================================================ #include "Utils/NVariant.h" const FNVariant FNVariant::Null; FNVariant::FNVariant() { } FNVariant::~FNVariant() { } FNVariant::FNVariant(const FNVariant& other) { *this = other; } FNVariant::FNVariant(FNVariant&& other) { *this = MoveTemp(other); } FNVariant::FNVariant(bool bValue) { TheUnion.SetSubtype(bValue); } FNVariant::FNVariant(int32 Value) { TheUnion.SetSubtype(Value); } FNVariant::FNVariant(float Value) { TheUnion.SetSubtype(Value); } FNVariant::FNVariant(const FString& Value) { TheUnion.SetSubtype(Value); } FNVariant::FNVariant(const FColor& Value) { TheUnion.SetSubtype(Value); } FNVariant::FNVariant(void* Value) { TheUnion.SetSubtype(Value); } FNVariant& FNVariant::operator= (const FNVariant& other) { if (this != &other) TheUnion = other.TheUnion; return *this; } FNVariant& FNVariant::operator= (FNVariant&& other) { if (this != &other) TheUnion = other.TheUnion; return *this; } FNVariant& FNVariant::operator= (bool bValue) { TheUnion.SetSubtype(bValue); return *this; } FNVariant& FNVariant::operator= (int32 Value) { TheUnion.SetSubtype(Value); return *this; } FNVariant& FNVariant::operator= (float Value) { TheUnion.SetSubtype(Value); return *this; } FNVariant& FNVariant::operator= (const FString& Value) { TheUnion.SetSubtype(Value); return *this; } FNVariant& FNVariant::operator= (const FColor& Value) { TheUnion.SetSubtype(Value); return *this; } FNVariant& FNVariant::operator= (void* Value) { TheUnion.SetSubtype(Value); return *this; } ================================================ FILE: Source/FairyGUI/Private/Utils/UBBParser.cpp ================================================ #include "Utils/UBBParser.h" extern const FString FAIRYGUI_API G_EMPTY_STRING; FUBBParser FUBBParser::DefaultParser; const FString LEFT_BRACKET = "["; const FString RIGHT_BRACKET = "]"; FUBBParser::FUBBParser() : DefaultImgWidth(0), DefaultImgHeight(0), Source(nullptr), ReadPos(0) { Handlers.Add("url", FTagHandler::CreateRaw(this, &FUBBParser::OnTag_URL)); Handlers.Add("img", FTagHandler::CreateRaw(this, &FUBBParser::OnTag_IMG)); Handlers.Add("b", FTagHandler::CreateRaw(this, &FUBBParser::OnTag_Simple)); Handlers.Add("i", FTagHandler::CreateRaw(this, &FUBBParser::OnTag_Simple)); Handlers.Add("u", FTagHandler::CreateRaw(this, &FUBBParser::OnTag_Simple)); Handlers.Add("sup", FTagHandler::CreateRaw(this, &FUBBParser::OnTag_Simple)); Handlers.Add("sub", FTagHandler::CreateRaw(this, &FUBBParser::OnTag_Simple)); Handlers.Add("color", FTagHandler::CreateRaw(this, &FUBBParser::OnTag_COLOR)); Handlers.Add("font", FTagHandler::CreateRaw(this, &FUBBParser::OnTag_FONT)); Handlers.Add("size", FTagHandler::CreateRaw(this, &FUBBParser::OnTag_SIZE)); Handlers.Add("align", FTagHandler::CreateRaw(this, &FUBBParser::OnTag_ALIGN)); } FUBBParser::~FUBBParser() { } FString FUBBParser::Parse(const FString& Text, bool bRemove) { Source = &Text; ReadPos = 0; LastColor.Reset(); LastFontSize.Reset(); int32 pos1 = 0, pos2, pos3; bool bEnd; FString tag, attr; FString buffer; while ((pos2 = Text.Find(LEFT_BRACKET, ESearchCase::CaseSensitive, ESearchDir::FromStart, pos1)) != -1) { if (pos2 > 0 && Text[pos2 - 1] == '\\') { buffer.Append(*Text + pos1, pos2 - pos1 - 1); buffer.Append(LEFT_BRACKET); pos1 = pos2 + 1; continue; } buffer.Append(*Text + pos1, pos2 - pos1); pos1 = pos2; pos2 = Text.Find(RIGHT_BRACKET, ESearchCase::CaseSensitive, ESearchDir::FromStart, pos1); if (pos2 == -1) break; if (pos2 == pos1 + 1) { buffer.Append(*Text + pos1, 2); pos1 = pos2 + 1; continue; } bEnd = Text[pos1 + 1] == '/'; pos3 = bEnd ? pos1 + 2 : pos1 + 1; tag = Text.Mid(pos3, pos2 - pos3); ReadPos = pos2 + 1; attr.Reset(); if (tag.FindChar('=', pos3)) { attr = tag.Mid(pos3 + 1); tag = tag.Mid(0, pos3); } tag = tag.ToLower(); FTagHandler* func = Handlers.Find(tag); if (func != nullptr) { FString repl = (*func).Execute(tag, bEnd, attr); if(!bRemove) buffer.Append(repl); } else if (DefaultTagHandler.IsBound()) { FString value; if (DefaultTagHandler.Execute(tag, bEnd, attr, value)) { if (!bRemove) buffer.Append(value); } else buffer.Append(*Text + pos1, pos2 - pos1 + 1); } else { buffer.Append(*Text + pos1, pos2 - pos1 + 1); } pos1 = ReadPos; } if (buffer.Len() == 0) return Text; else { if (pos1 < Text.Len()) buffer.Append(*Text + pos1, Text.Len() - pos1); return buffer; } } FString FUBBParser::GetTagText(bool bRemove) { int32 pos1 = ReadPos; int32 pos2; FString buffer; while ((pos2 = Source->Find(LEFT_BRACKET, ESearchCase::CaseSensitive, ESearchDir::FromStart, pos1)) != -1) { if ((*Source)[pos2 - 1] == '\\') { buffer.Append(**Source + pos1, pos2 - pos1 - 1); buffer.Append(LEFT_BRACKET); pos1 = pos2 + 1; } else { buffer.Append(**Source + pos1, pos2 - pos1); break; } } if (pos2 == -1) return G_EMPTY_STRING; if (bRemove) ReadPos = pos2; return buffer; } FString FUBBParser::OnTag_URL(const FString& TagName, bool bEnd, const FString& Attr) { if (!bEnd) { if (!Attr.IsEmpty()) return ""; else { FString Href = GetTagText(false); return ""; } } else return""; } FString FUBBParser::OnTag_IMG(const FString& TagName, bool bEnd, const FString& Attr) { if (!bEnd) { FString src = GetTagText(true); if (src.IsEmpty()) return src; if (DefaultImgWidth != 0) return ""; else return ""; } else return G_EMPTY_STRING; } FString FUBBParser::OnTag_Simple(const FString& TagName, bool bEnd, const FString& Attr) { return bEnd ? ("") : ("<" + TagName + ">"); } FString FUBBParser::OnTag_COLOR(const FString& TagName, bool bEnd, const FString& Attr) { if (!bEnd) { LastColor = Attr; return ""; } else return ""; } FString FUBBParser::OnTag_FONT(const FString& TagName, bool bEnd, const FString& Attr) { if (!bEnd) return ""; else return ""; } FString FUBBParser::OnTag_SIZE(const FString& TagName, bool bEnd, const FString& Attr) { if (!bEnd) { LastFontSize = Attr; return ""; } else return ""; } FString FUBBParser::OnTag_ALIGN(const FString& TagName, bool bEnd, const FString& Attr) { if (!bEnd) return "

"; else return "

"; } ================================================ FILE: Source/FairyGUI/Private/Utils/XMLAttributes.cpp ================================================ #include "Utils/XMLAttributes.h" extern const FString FAIRYGUI_API G_EMPTY_STRING; const FString& FXMLAttributes::Get(const FString& AttrName, const FString& DefaultValue) { FString* Result = Find(AttrName); if (Result != nullptr) return *Result; else return DefaultValue; } int32 FXMLAttributes::GetInt(const FString& AttrName, int32 DefaultValue) { const FString& Value = Get(AttrName); if (Value.Len() == 0) return DefaultValue; return FCString::Atoi(*Value); } float FXMLAttributes::GetFloat(const FString& AttrName, float DefaultValue) { const FString& Value = Get(AttrName); if (Value.Len() == 0) return DefaultValue; return FCString::Atof(*Value); } bool FXMLAttributes::GetBool(const FString& AttrName, bool DefaultValue) { const FString& Value = Get(AttrName); if (Value.Len() == 0) return DefaultValue; return Value.ToBool(); } FColor FXMLAttributes::GetColor(const FString& AttrName, const FColor& DefaultValue) { const FString& Value = Get(AttrName); if (Value.Len() == 0) return DefaultValue; return FColor::FromHex(Value); } ================================================ FILE: Source/FairyGUI/Private/Utils/XMLIterator.cpp ================================================ #include "Utils/XMLIterator.h" extern const FString FAIRYGUI_API G_EMPTY_STRING; const TCHAR* CDATA_START = TEXT(""); const TCHAR* COMMENT_START = TEXT(""); const TCHAR* SYMBOL_LT = TEXT("<"); const TCHAR* SYMBOL_AMP = TEXT("&"); void FXMLIterator::Begin(const FString& InText, bool bInLowerCaseName) { Source = &InText; SourceLen = Source->Len(); bLowerCaseName = bInLowerCaseName; ParsePos = 0; LastTagEnd = 0; TagPos = 0; TagLength = 0; TagName.Reset(); } bool FXMLIterator::NextTag() { int32 pos; TCHAR c; TagType = EXMLTagType::Start; FString buffer; LastTagEnd = ParsePos; bAttrParsed = false; LastTagName = TagName; const FString& Text = *Source; while ((pos = Text.Find(SYMBOL_LT, ESearchCase::IgnoreCase, ESearchDir::FromStart, ParsePos)) != -1) { ParsePos = pos; pos++; if (pos == SourceLen) break; c = Text[pos]; if (c == '!') { if (SourceLen > pos + 7 && Text.Mid(pos - 1, 9) == CDATA_START) { pos = Text.Find(CDATA_END, ESearchCase::IgnoreCase, ESearchDir::FromStart, pos); TagType = EXMLTagType::CDATA; TagName.Reset(); TagPos = ParsePos; if (pos == -1) TagLength = SourceLen - ParsePos; else TagLength = pos + 3 - ParsePos; ParsePos += TagLength; return true; } else if (SourceLen > pos + 2 && Text.Mid(pos - 1, 4) == COMMENT_START) { pos = Text.Find(COMMENT_END, ESearchCase::IgnoreCase, ESearchDir::FromStart, pos); TagType = EXMLTagType::Comment; TagName.Reset(); TagPos = ParsePos; if (pos == -1) TagLength = SourceLen - ParsePos; else TagLength = pos + 3 - ParsePos; ParsePos += TagLength; return true; } else { pos++; TagType = EXMLTagType::Instruction; } } else if (c == '/') { pos++; TagType = EXMLTagType::End; } else if (c == '?') { pos++; TagType = EXMLTagType::Instruction; } for (; pos < SourceLen; pos++) { c = Text[pos]; if (FChar::IsWhitespace(c) || c == '>' || c == '/') break; } if (pos == SourceLen) break; buffer.Append(*Text + ParsePos + 1, pos - ParsePos - 1); if (buffer.Len() > 0 && buffer[0] == '/') buffer.RemoveAt(0, 1); bool singleQuoted = false, doubleQuoted = false; int32 possibleEnd = -1; for (; pos < SourceLen; pos++) { c = Text[pos]; if (c == '"') { if (!singleQuoted) doubleQuoted = !doubleQuoted; } else if (c == '\'') { if (!doubleQuoted) singleQuoted = !singleQuoted; } if (c == '>') { if (!(singleQuoted || doubleQuoted)) { possibleEnd = -1; break; } possibleEnd = pos; } else if (c == '<') break; } if (possibleEnd != -1) pos = possibleEnd; if (pos == SourceLen) break; if (Text[pos - 1] == '/') TagType = EXMLTagType::Void; TagName = buffer; if (bLowerCaseName) TagName = TagName.ToLower(); TagPos = ParsePos; TagLength = pos + 1 - ParsePos; ParsePos += TagLength; return true; } TagPos = SourceLen; TagLength = 0; TagName.Reset(); return false; } FString FXMLIterator::GetTagSource() const { return (*Source).Mid(TagPos, TagLength); } FString FXMLIterator::GetRawText(bool bTrim) const { if (LastTagEnd == TagPos) return G_EMPTY_STRING; if (bTrim) { int32 i = LastTagEnd; for (; i < TagPos; i++) { char c = (*Source)[i]; if (!FChar::IsWhitespace(c)) break; } if (i == TagPos) return G_EMPTY_STRING; else return (*Source).Mid(i, TagPos - i).TrimEnd(); } else return (*Source).Mid(LastTagEnd, TagPos - LastTagEnd); } FString FXMLIterator::GetText(bool bTrim) const { if (LastTagEnd == TagPos) return G_EMPTY_STRING; if (bTrim) { int32 i = LastTagEnd; for (; i < TagPos; i++) { char c = (*Source)[i]; if (!FChar::IsWhitespace(c)) break; } if (i == TagPos) return G_EMPTY_STRING; else return DecodeString((*Source).Mid(i, TagPos - i).TrimEnd()); } else return DecodeString((*Source).Mid(LastTagEnd, TagPos - LastTagEnd)); } void FXMLIterator::ParseAttributes() { if (bAttrParsed) return; bAttrParsed = true; FString attrName; int32 valueStart; int32 valueEnd; bool waitValue = false; int32 quoted; FString buffer; int32 i = TagPos; int32 attrEnd = TagPos + TagLength; if (i < attrEnd && (*Source)[i] == '<') { for (; i < attrEnd; i++) { TCHAR c = (*Source)[i]; if (FChar::IsWhitespace(c) || c == '>' || c == '/') break; } } for (; i < attrEnd; i++) { char c = (*Source)[i]; if (c == '=') { valueStart = -1; valueEnd = -1; quoted = 0; for (int32 j = i + 1; j < attrEnd; j++) { char c2 = (*Source)[j]; if (FChar::IsWhitespace(c2)) { if (valueStart != -1 && quoted == 0) { valueEnd = j - 1; break; } } else if (c2 == '>') { if (quoted == 0) { valueEnd = j - 1; break; } } else if (c2 == '"') { if (valueStart != -1) { if (quoted != 1) { valueEnd = j - 1; break; } } else { quoted = 2; valueStart = j + 1; } } else if (c2 == '\'') { if (valueStart != -1) { if (quoted != 2) { valueEnd = j - 1; break; } } else { quoted = 1; valueStart = j + 1; } } else if (valueStart == -1) { valueStart = j; } } if (valueStart != -1 && valueEnd != -1) { attrName = buffer; if (bLowerCaseName) attrName = attrName.ToLower(); buffer.Reset(); Attributes.Add(attrName, DecodeString((*Source).Mid(valueStart, valueEnd - valueStart + 1))); i = valueEnd + 1; } else break; } else if (!FChar::IsWhitespace(c)) { if (waitValue || c == '/' || c == '>') { if (buffer.Len() > 0) { attrName = buffer; if (bLowerCaseName) attrName = attrName.ToLower(); Attributes.Add(attrName, G_EMPTY_STRING); buffer.Reset(); } waitValue = false; } if (c != '/' && c != '>') buffer.AppendChar(c); } else { if (buffer.Len() > 0) waitValue = true; } } } FString FXMLIterator::DecodeString(const FString& InSource) { int32 len = InSource.Len(); int32 pos1 = 0, pos2 = 0; FString result; while (true) { pos2 = InSource.Find(SYMBOL_AMP, ESearchCase::IgnoreCase, ESearchDir::FromStart, pos1); if (pos2 == -1) { result.Append(InSource.Mid(pos1)); break; } result.Append(InSource.Mid(pos1, pos2 - pos1)); pos1 = pos2 + 1; pos2 = pos1; int32 end = FMath::Min(len, pos2 + 10); for (; pos2 < end; pos2++) { if (InSource[pos2] == ';') break; } if (pos2 < end && pos2 > pos1) { FString entity = InSource.Mid(pos1, pos2 - pos1); if (entity[0] == '#') { if (entity.Len() > 1) { uint32 u; if (entity[1] == 'x') u = FParse::HexNumber(*entity.Mid(2)); else u = FParse::HexNumber(*entity.Mid(1)); result.AppendChar((TCHAR)u); pos1 = pos2 + 1; } else result.AppendChar('&'); } else { static const TMap EscapeCharacters = { { "amp", '&' }, { "quot", '"'}, { "lt", '<' }, { "gt", '>'}, }; TCHAR c = EscapeCharacters.FindRef(entity); if (c != 0) { result.AppendChar(c); pos1 = pos2 + 1; } else result.AppendChar('&'); } } else { result.AppendChar('&'); } } return result; } ================================================ FILE: Source/FairyGUI/Private/Widgets/BitmapFont.cpp ================================================ #include "Widgets/BitmapFont.h" void FBitmapFont::AddReferencedObjects(FReferenceCollector& Collector) { if (Texture != nullptr) Collector.AddReferencedObject(Texture); } ================================================ FILE: Source/FairyGUI/Private/Widgets/BitmapFontRun.cpp ================================================ #include "Widgets/BitmapFontRun.h" #include "Styling/StyleDefaults.h" #include "Rendering/DrawElements.h" #include "Framework/Application/SlateApplication.h" #include "Framework/Text/DefaultLayoutBlock.h" #include "Framework/Text/RunUtils.h" TSharedRef< FBitmapFontRun > FBitmapFontRun::Create(const TSharedRef< const FString >& InText, const TSharedRef& InFont, const FTextRange& InRange) { return MakeShareable(new FBitmapFontRun(InText, InFont, InRange)); } FBitmapFontRun::FBitmapFontRun(const TSharedRef< const FString >& InText, const TSharedRef& InFont, const FTextRange& InRange) : Text(InText) , Range(InRange) , Font(InFont) { Glyph = Font->Glyphs.Find(Text.Get()[Range.BeginIndex]); if (Glyph != nullptr) { Brush.SetResourceObject(Font->Texture->NativeTexture); Brush.SetImageSize(Glyph->Size); Brush.SetUVRegion(Glyph->UVRect); } } FBitmapFontRun::~FBitmapFontRun() { } const TArray< TSharedRef >& FBitmapFontRun::GetChildren() { static TArray< TSharedRef > NoChildren; return NoChildren; } void FBitmapFontRun::ArrangeChildren(const TSharedRef< ILayoutBlock >& Block, const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const { // no widgets } int32 FBitmapFontRun::GetTextIndexAt(const TSharedRef< ILayoutBlock >& Block, const FVector2D& Location, float Scale, ETextHitPoint* const OutHitPoint) const { // An image should always contain a single character (a breaking space) check(Range.Len() == 1); const FVector2D& BlockOffset = Block->GetLocationOffset(); const FVector2D& BlockSize = Block->GetSize(); const float Left = BlockOffset.X; const float Top = BlockOffset.Y; const float Right = BlockOffset.X + BlockSize.X; const float Bottom = BlockOffset.Y + BlockSize.Y; const bool ContainsPoint = Location.X >= Left && Location.X < Right && Location.Y >= Top && Location.Y < Bottom; if (!ContainsPoint) { return INDEX_NONE; } const float ScaledImageSize = Glyph->XAdvance * Scale; const int32 Index = (Location.X <= (Left + (ScaledImageSize * 0.5f))) ? Range.BeginIndex : Range.EndIndex; if (OutHitPoint) { const FTextRange BlockRange = Block->GetTextRange(); const FLayoutBlockTextContext BlockTextContext = Block->GetTextContext(); // 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 *OutHitPoint = RunUtils::CalculateTextHitPoint(Index, BlockRange, BlockTextContext.BaseDirection); } return Index; } FVector2D FBitmapFontRun::GetLocationAt(const TSharedRef< ILayoutBlock >& Block, int32 Offset, float Scale) const { return Block->GetLocationOffset(); } int32 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 { if (Glyph == nullptr) return LayerId; // The block size and offset values are pre-scaled, so we need to account for that when converting the block offsets into paint geometry const float InverseScale = Inverse(AllottedGeometry.Scale); FLinearColor FinalColorAndOpacity; if (Font->bCanTint) FinalColorAndOpacity = InWidgetStyle.GetColorAndOpacityTint() * DefaultStyle.ColorAndOpacity.GetSpecifiedColor(); else FinalColorAndOpacity = InWidgetStyle.GetColorAndOpacityTint(); const ESlateDrawEffect DrawEffects = bParentEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect; FSlateDrawElement::MakeBox( OutDrawElements, ++LayerId, AllottedGeometry.ToPaintGeometry(Glyph->Size, FSlateLayoutTransform(TransformPoint(InverseScale, Block->GetLocationOffset()) + Glyph->Offset)), &Brush, DrawEffects, FinalColorAndOpacity ); return LayerId; } TSharedRef< ILayoutBlock > FBitmapFontRun::CreateBlock(int32 BeginIndex, int32 EndIndex, FVector2D Size, const FLayoutBlockTextContext& TextContext, const TSharedPtr< IRunRenderer >& Renderer) { return FDefaultLayoutBlock::Create(SharedThis(this), FTextRange(BeginIndex, EndIndex), Size, TextContext, Renderer); } int8 FBitmapFontRun::GetKerning(int32 CurrentIndex, float Scale, const FRunTextContext& TextContext) const { return 0; } FVector2D FBitmapFontRun::Measure(int32 BeginIndex, int32 EndIndex, float Scale, const FRunTextContext& TextContext) const { if (Glyph == nullptr || (EndIndex - BeginIndex == 0)) { return FVector2D(0, GetMaxHeight(Scale)); } return FVector2D(Glyph->XAdvance, Glyph->LineHeight) * Scale; } int16 FBitmapFontRun::GetMaxHeight(float Scale) const { if (Glyph == nullptr) return 0; else return Glyph->LineHeight * Scale; } int16 FBitmapFontRun::GetBaseLine(float Scale) const { return Scale; } FTextRange FBitmapFontRun::GetTextRange() const { return Range; } void FBitmapFontRun::SetTextRange(const FTextRange& Value) { Range = Value; } void FBitmapFontRun::Move(const TSharedRef& NewText, const FTextRange& NewRange) { Text = NewText; Range = NewRange; } TSharedRef FBitmapFontRun::Clone() const { TSharedRef NewRun = FBitmapFontRun::Create(Text, Font, Range); return NewRun; } void FBitmapFontRun::AppendTextTo(FString& AppendToText) const { AppendToText.Append(**Text + Range.BeginIndex, Range.Len()); } void FBitmapFontRun::AppendTextTo(FString& AppendToText, const FTextRange& PartialRange) const { check(Range.BeginIndex <= PartialRange.BeginIndex); check(Range.EndIndex >= PartialRange.EndIndex); AppendToText.Append(**Text + PartialRange.BeginIndex, PartialRange.Len()); } const FRunInfo& FBitmapFontRun::GetRunInfo() const { static FRunInfo RunInfo; return RunInfo; } ERunAttributes FBitmapFontRun::GetRunAttributes() const { return ERunAttributes::None; } ================================================ FILE: Source/FairyGUI/Private/Widgets/HitTest.cpp ================================================ #include "Widgets/HitTest.h" #include "Utils/ByteBuffer.h" #include "UI/GObject.h" void FPixelHitTestData::Load(FByteBuffer* Buffer) { Buffer->Skip(4); PixelWidth = Buffer->ReadInt(); Scale = 1.0f / Buffer->ReadByte(); int32 PixelsLength = Buffer->ReadInt(); Pixels.Append(Buffer->GetBuffer() + Buffer->GetPos(), PixelsLength); } FPixelHitTest::FPixelHitTest(const TSharedPtr& InData, int32 InOffsetX, int32 InOffsetY) : OffsetX(InOffsetX), OffsetY(InOffsetY), Data(InData) { } FPixelHitTest::~FPixelHitTest() { } bool FPixelHitTest::HitTest(const FBox2D& ContentRect, const FVector2D& LayoutScaleMultiplier, const FVector2D& LocalPoint) const { int32 x = FMath::FloorToInt((LocalPoint.X / LayoutScaleMultiplier.X - OffsetX) * Data->Scale); int32 y = FMath::FloorToInt((LocalPoint.Y / LayoutScaleMultiplier.Y - OffsetY) * Data->Scale); if (x < 0 || y < 0 || x >= Data->PixelWidth) return false; int32 pos = y * Data->PixelWidth + x; int32 pos2 = pos / 8; int32 pos3 = pos % 8; if (pos2 >= 0 && pos2 < Data->Pixels.Num()) return ((Data->Pixels[pos2] >> pos3) & 0x1) > 0; else return false; } FChildHitTest::FChildHitTest(UGObject* InObj) :Obj(InObj) { } FChildHitTest::~FChildHitTest() { } bool FChildHitTest::HitTest(const FBox2D& ContentRect, const FVector2D& LayoutScaleMultiplier, const FVector2D& LocalPoint) const { if (!Obj.IsValid() || Obj->GetParent() == nullptr) return false; IHitTest* HitArea = Obj->GetHitArea(); if (HitArea == nullptr) return false; FVector2D NewPoint = LocalPoint + Obj->GetPosition(); FBox2D NewRect = FBox2D(FVector2D::ZeroVector, Obj->GetSize()); if (!NewRect.IsInside(NewPoint)) return false; FVector2D NewMultiplier = Obj->GetSize() / Obj->SourceSize; if (NewMultiplier.ContainsNaN()) NewMultiplier.Set(1, 1); return HitArea->HitTest(NewRect, NewMultiplier, NewPoint); } ================================================ FILE: Source/FairyGUI/Private/Widgets/LoaderRun.cpp ================================================ #include "Widgets/LoaderRun.h" #include "Styling/StyleDefaults.h" #include "Rendering/DrawElements.h" #include "Framework/Application/SlateApplication.h" #include "Framework/Text/DefaultLayoutBlock.h" #include "Framework/Text/RunUtils.h" #include "FairyApplication.h" #include "UI/UIPackage.h" #include "UI/PackageItem.h" #include "UI/GLoader.h" TSharedRef< FLoaderRun > FLoaderRun::Create(UFairyApplication* App, const FHTMLElement& InHTMLElement, const TSharedRef< const FString >& InText, const FTextRange& InRange) { return MakeShareable(new FLoaderRun(App, InHTMLElement, InText, InRange)); } FLoaderRun::FLoaderRun(UFairyApplication* App, const FHTMLElement& InHTMLElement, const TSharedRef< const FString >& InText, const FTextRange& InRange) : Children() , HTMLElement(InHTMLElement) , Text(InText) , Range(InRange) { Loader = NewObject(App); Children.Add(Loader->GetDisplayObject()); FVector2D SourceSize(0, 0); const FString& Src = HTMLElement.Attributes.Get("src"); if (Src.Len() > 0) { TSharedPtr pii = UUIPackage::GetItemByURL(Src); if (pii.IsValid()) SourceSize = pii->Size; } Loader->SetURL(Src); SourceSize.X = HTMLElement.Attributes.GetInt("width", SourceSize.X); SourceSize.Y = HTMLElement.Attributes.GetInt("height", SourceSize.Y); if (SourceSize.X == 0) SourceSize.X = 5; if (SourceSize.Y == 0) SourceSize.Y = 5; Loader->SetSize(SourceSize); } FLoaderRun::~FLoaderRun() { } const TArray< TSharedRef >& FLoaderRun::GetChildren() { return Children; } void FLoaderRun::ArrangeChildren(const TSharedRef< ILayoutBlock >& Block, const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const { const float InverseScale = Inverse(AllottedGeometry.Scale); ArrangedChildren.AddWidget( AllottedGeometry.MakeChild(Children[0], TransformVector(InverseScale, Block->GetSize()), FSlateLayoutTransform(TransformPoint(InverseScale, Block->GetLocationOffset()))) ); } int32 FLoaderRun::GetTextIndexAt(const TSharedRef< ILayoutBlock >& Block, const FVector2D& Location, float Scale, ETextHitPoint* const OutHitPoint) const { // An image should always contain a single character (a breaking space) check(Range.Len() == 1); const FVector2D& BlockOffset = Block->GetLocationOffset(); const FVector2D& BlockSize = Block->GetSize(); const float Left = BlockOffset.X; const float Top = BlockOffset.Y; const float Right = BlockOffset.X + BlockSize.X; const float Bottom = BlockOffset.Y + BlockSize.Y; const bool ContainsPoint = Location.X >= Left && Location.X < Right && Location.Y >= Top && Location.Y < Bottom; if (!ContainsPoint) { return INDEX_NONE; } const FVector2D ScaledImageSize = Loader->GetSize() * Scale; const int32 Index = (Location.X <= (Left + (ScaledImageSize.X * 0.5f))) ? Range.BeginIndex : Range.EndIndex; if (OutHitPoint) { const FTextRange BlockRange = Block->GetTextRange(); const FLayoutBlockTextContext BlockTextContext = Block->GetTextContext(); // 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 *OutHitPoint = RunUtils::CalculateTextHitPoint(Index, BlockRange, BlockTextContext.BaseDirection); } return Index; } FVector2D FLoaderRun::GetLocationAt(const TSharedRef< ILayoutBlock >& Block, int32 Offset, float Scale) const { return Block->GetLocationOffset(); } int32 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 { const float InverseScale = Inverse(AllottedGeometry.Scale); const FGeometry WidgetGeometry = AllottedGeometry.MakeChild(TransformVector(InverseScale, Block->GetSize()), FSlateLayoutTransform(TransformPoint(InverseScale, Block->GetLocationOffset()))); return Children[0]->Paint(Args, WidgetGeometry, MyCullingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled); } TSharedRef< ILayoutBlock > FLoaderRun::CreateBlock(int32 BeginIndex, int32 EndIndex, FVector2D Size, const FLayoutBlockTextContext& TextContext, const TSharedPtr< IRunRenderer >& Renderer) { return FDefaultLayoutBlock::Create(SharedThis(this), FTextRange(BeginIndex, EndIndex), Size, TextContext, Renderer); } int8 FLoaderRun::GetKerning(int32 CurrentIndex, float Scale, const FRunTextContext& TextContext) const { return 0; } FVector2D FLoaderRun::Measure(int32 BeginIndex, int32 EndIndex, float Scale, const FRunTextContext& TextContext) const { if (EndIndex - BeginIndex == 0) { return FVector2D(0, GetMaxHeight(Scale)); } return (Loader->GetSize() + FVector2D(2, 0)) * Scale; } int16 FLoaderRun::GetMaxHeight(float Scale) const { return Loader->GetSize().Y * Scale; } int16 FLoaderRun::GetBaseLine(float Scale) const { return -Loader->GetSize().Y * 0.2f * Scale; } FTextRange FLoaderRun::GetTextRange() const { return Range; } void FLoaderRun::SetTextRange(const FTextRange& Value) { Range = Value; } void FLoaderRun::Move(const TSharedRef& NewText, const FTextRange& NewRange) { Text = NewText; Range = NewRange; } TSharedRef FLoaderRun::Clone() const { TSharedRef NewRun = FLoaderRun::Create(Loader->GetApp(), HTMLElement, Text, Range); return NewRun; } void FLoaderRun::AppendTextTo(FString& AppendToText) const { AppendToText.Append(**Text + Range.BeginIndex, Range.Len()); } void FLoaderRun::AppendTextTo(FString& AppendToText, const FTextRange& PartialRange) const { check(Range.BeginIndex <= PartialRange.BeginIndex); check(Range.EndIndex >= PartialRange.EndIndex); AppendToText.Append(**Text + PartialRange.BeginIndex, PartialRange.Len()); } const FRunInfo& FLoaderRun::GetRunInfo() const { static FRunInfo RunInfo; return RunInfo; } ERunAttributes FLoaderRun::GetRunAttributes() const { return ERunAttributes::None; } void FLoaderRun::AddReferencedObjects(FReferenceCollector& Collector) { Collector.AddReferencedObject(Loader); } ================================================ FILE: Source/FairyGUI/Private/Widgets/Mesh/EllipseMesh.cpp ================================================ #include "Widgets/Mesh/EllipseMesh.h" FEllipseMesh::FEllipseMesh() : LineWidth(0), LineColor(FColor::Black), StartDegree(0), EndDegreee(360) { } void FEllipseMesh::OnPopulateMesh(FVertexHelper& Helper) { static SlateIndex SECTOR_CENTER_TRIANGLES[] = { 0, 4, 1, 0, 3, 4, 0, 2, 3, 0, 8, 5, 0, 7, 8, 0, 6, 7, 6, 5, 2, 2, 1, 6 }; const FBox2D& rect = DrawRect.IsSet() ? DrawRect.GetValue() : Helper.ContentRect; const FColor& color = FillColor.IsSet() ? FillColor.GetValue() : Helper.VertexColor; float sectionStart = FMath::Clamp(StartDegree, 0, 360); float sectionEnd = FMath::Clamp(EndDegreee, 0, 360); bool clipped = sectionStart > 0 || sectionEnd < 360; sectionStart = FMath::DegreesToRadians(sectionStart); sectionEnd = FMath::DegreesToRadians(sectionEnd); const FColor& centerColor2 = CenterColor.IsSet() ? CenterColor.GetValue() : color; FVector2D radius = rect.GetSize() * 0.5f; int32 sides = FMath::CeilToInt(PI * (radius.X + radius.Y) / 4); sides = FMath::Clamp(sides, 40, 800); float angleDelta = 2 * PI / sides; float angle = 0; float lineAngle = 0; if (LineWidth > 0 && clipped) { lineAngle = LineWidth / radius.GetMax(); sectionStart += lineAngle; sectionEnd -= lineAngle; } int32 vpos = Helper.GetVertexCount(); FVector2D center = rect.Min + radius; Helper.AddVertex(center, centerColor2); for (int32 i = 0; i < sides; i++) { if (angle < sectionStart) angle = sectionStart; else if (angle > sectionEnd) angle = sectionEnd; FVector2D vec(FMath::Cos(angle) * (radius.X - LineWidth) + center.X, FMath::Sin(angle) * (radius.Y - LineWidth) + center.Y); Helper.AddVertex(vec, color); if (LineWidth > 0) { Helper.AddVertex(vec, LineColor); Helper.AddVertex(FVector2D(FMath::Cos(angle) * radius.X + center.X, FMath::Sin(angle) * radius.Y + center.Y), LineColor); } angle += angleDelta; } if (LineWidth > 0) { int32 cnt = sides * 3; for (int32 i = 0; i < cnt; i += 3) { if (i != cnt - 3) { Helper.AddTriangle(0, i + 1, i + 4); Helper.AddTriangle(i + 5, i + 2, i + 3); Helper.AddTriangle(i + 3, i + 6, i + 5); } else if (!clipped) { Helper.AddTriangle(0, i + 1, 1); Helper.AddTriangle(2, i + 2, i + 3); Helper.AddTriangle(i + 3, 3, 2); } else { Helper.AddTriangle(0, i + 1, i + 1); Helper.AddTriangle(i + 2, i + 2, i + 3); Helper.AddTriangle(i + 3, i + 3, i + 2); } } } else { for (int32 i = 0; i < sides; i++) { if (i != sides - 1) Helper.AddTriangle(0, i + 1, i + 2); else if (!clipped) Helper.AddTriangle(0, i + 1, 1); else Helper.AddTriangle(0, i + 1, i + 1); } } if (LineWidth > 0 && clipped) { Helper.AddVertex(FVector2D(radius.X, radius.Y), LineColor); float centerRadius = LineWidth * 0.5f; sectionStart -= lineAngle; angle = sectionStart + lineAngle * 0.5f + PI * 0.5f; Helper.AddVertex(FVector2D(FMath::Cos(angle) * centerRadius + radius.X, FMath::Sin(angle) * centerRadius + radius.Y), LineColor); angle -= PI; Helper.AddVertex(FVector2D(FMath::Cos(angle) * centerRadius + radius.X, FMath::Sin(angle) * centerRadius + radius.Y), LineColor); Helper.AddVertex(FVector2D(FMath::Cos(sectionStart) * radius.X + radius.X, FMath::Sin(sectionStart) * radius.Y + radius.Y), LineColor); Helper.AddVertex(Helper.GetPosition(vpos + 3), LineColor); sectionEnd += lineAngle; angle = sectionEnd - lineAngle * 0.5f + PI * 0.5f; Helper.AddVertex(FVector2D(FMath::Cos(angle) * centerRadius + radius.X, FMath::Sin(angle) * centerRadius + radius.Y), LineColor); angle -= PI; Helper.AddVertex(FVector2D(FMath::Cos(angle) * centerRadius + radius.X, FMath::Sin(angle) * centerRadius + radius.Y), LineColor); Helper.AddVertex(Helper.GetPosition(vpos + sides * 3), LineColor); Helper.AddVertex(FVector2D(FMath::Cos(sectionEnd) * radius.X + radius.X, FMath::Sin(sectionEnd) * radius.Y + radius.Y), LineColor); Helper.AddTriangles(SECTOR_CENTER_TRIANGLES, 24, sides * 3 + 1); } } bool FEllipseMesh::HitTest(const FBox2D& ContentRect, const FVector2D& LayoutScaleMultiplier, const FVector2D& LocalPoint) const { FVector2D Radius = ContentRect.GetSize() * 0.5f; FVector2D Pos = LocalPoint - Radius - ContentRect.Min; if (FMath::Pow(Pos.X / Radius.X, 2) + FMath::Pow(Pos.Y / Radius.Y, 2) < 1) { if (StartDegree != 0 || EndDegreee != 360) { float deg = FMath::RadiansToDegrees(FMath::Atan2(Pos.Y, Pos.X)); if (deg < 0) deg += 360; return deg >= StartDegree && deg <= EndDegreee; } else return true; } return false; } ================================================ FILE: Source/FairyGUI/Private/Widgets/Mesh/FillMesh.cpp ================================================ #include "Widgets/Mesh/FillMesh.h" static void FillHorizontal(FVertexHelper& Helper, FBox2D VertRect, int32 Origin, float Amount) { float a = VertRect.GetSize().X * Amount; if ((EOriginHorizontal)Origin == EOriginHorizontal::Right || (EOriginVertical)Origin == EOriginVertical::Bottom) VertRect.Min.X += (VertRect.GetSize().X - a); else VertRect.Max.X = VertRect.Min.X + a; Helper.AddQuad(VertRect); Helper.AddTriangles(); } static void FillVertical(FVertexHelper& Helper, FBox2D VertRect, int32 Origin, float Amount) { float a = VertRect.GetSize().Y * Amount; if ((EOriginHorizontal)Origin == EOriginHorizontal::Right || (EOriginVertical)Origin == EOriginVertical::Bottom) VertRect.Min.Y += (VertRect.GetSize().Y - a); else VertRect.Max.Y = VertRect.Min.Y + a; Helper.AddQuad(VertRect); Helper.AddTriangles(); } //4 vertex static void FillRadial90(FVertexHelper& Helper, FBox2D VertRect, EOrigin90 Origin, float Amount, bool bClockwise) { bool flipX = Origin == EOrigin90::TopRight || Origin == EOrigin90::BottomRight; bool flipY = Origin == EOrigin90::BottomLeft || Origin == EOrigin90::BottomRight; if (flipX != flipY) bClockwise = !bClockwise; float ratio = bClockwise ? Amount : (1 - Amount); float tan = FMath::Tan(PI * 0.5f * ratio); bool thresold = false; if (ratio != 1) thresold = (VertRect.GetSize().Y / VertRect.GetSize().X - tan) > 0; if (!bClockwise) thresold = !thresold; float x = VertRect.Min.X + (ratio == 0 ? FLT_MAX : (VertRect.GetSize().Y / tan)); float y = VertRect.Min.Y + (ratio == 1 ? FLT_MAX : (VertRect.GetSize().X * tan)); float x2 = x; float y2 = y; if (flipX) x2 = VertRect.GetSize().X - x; if (flipY) y2 = VertRect.GetSize().Y - y; float xMin = flipX ? (VertRect.GetSize().X - VertRect.Min.X) : VertRect.Min.X; float yMin = flipY ? (VertRect.GetSize().Y - VertRect.Min.Y) : VertRect.Min.Y; float xMax = flipX ? -VertRect.Min.X : VertRect.Max.X; float yMax = flipY ? -VertRect.Min.Y : VertRect.Max.Y; Helper.AddVertex(FVector2D(xMin, yMin)); if (bClockwise) Helper.AddVertex(FVector2D(xMax, yMin)); if (y > VertRect.Max.Y) { if (thresold) Helper.AddVertex(FVector2D(x2, yMax)); else Helper.AddVertex(FVector2D(xMax, yMax)); } else Helper.AddVertex(FVector2D(xMax, y2)); if (x > VertRect.Max.X) { if (thresold) Helper.AddVertex(FVector2D(xMax, y2)); else Helper.AddVertex(FVector2D(xMax, yMax)); } else Helper.AddVertex(FVector2D(x2, yMax)); if (!bClockwise) Helper.AddVertex(FVector2D(xMin, yMax)); if (flipX == flipY) { Helper.AddTriangle(0, 1, 2); Helper.AddTriangle(0, 2, 3); } else { Helper.AddTriangle(2, 1, 0); Helper.AddTriangle(3, 2, 0); } } #define LEFT_BOX(Rect) FBox2D(Rect.Min, Rect.Max - FVector2D(Rect.GetSize().X * 0.5f, 0)) #define RIGHT_BOX(Rect) FBox2D(Rect.Min + FVector2D(Rect.GetSize().X * 0.5f, 0), Rect.Max) #define TOP_BOX(Rect) FBox2D(Rect.Min, Rect.Max - FVector2D(0, Rect.GetSize().Y * 0.5f)) #define BOTTOM_BOX(Rect) FBox2D(Rect.Min + FVector2D(0, Rect.GetSize().Y * 0.5f), Rect.Max) #define LEFT_BOX_CW bClockwise?LEFT_BOX(VertRect):RIGHT_BOX(VertRect) #define RIGHT_BOX_CW bClockwise?RIGHT_BOX(VertRect):LEFT_BOX(VertRect) #define TOP_BOX_CW bClockwise?TOP_BOX(VertRect):BOTTOM_BOX(VertRect) #define BOTTOM_BOX_CW bClockwise?BOTTOM_BOX(VertRect):TOP_BOX(VertRect) //8 vertex static void FillRadial180(FVertexHelper& Helper, FBox2D VertRect, EOrigin180 Origin, float Amount, bool bClockwise) { switch (Origin) { case EOrigin180::Top: if (Amount <= 0.5f) { FillRadial90(Helper, RIGHT_BOX_CW, bClockwise ? EOrigin90::TopLeft : EOrigin90::TopRight, Amount / 0.5f, bClockwise); } else { FillRadial90(Helper, LEFT_BOX_CW, bClockwise ? EOrigin90::TopRight : EOrigin90::TopLeft, (Amount - 0.5f) / 0.5f, bClockwise); Helper.AddQuad(RIGHT_BOX_CW); Helper.AddTriangles(-4); } break; case EOrigin180::Bottom: if (Amount <= 0.5f) { FillRadial90(Helper, LEFT_BOX_CW, bClockwise ? EOrigin90::BottomRight : EOrigin90::BottomLeft, Amount / 0.5f, bClockwise); } else { FillRadial90(Helper, RIGHT_BOX_CW, bClockwise ? EOrigin90::BottomLeft : EOrigin90::BottomRight, (Amount - 0.5f) / 0.5f, bClockwise); Helper.AddQuad(LEFT_BOX_CW); Helper.AddTriangles(-4); } break; case EOrigin180::Left: if (Amount <= 0.5f) { FillRadial90(Helper, TOP_BOX_CW, bClockwise ? EOrigin90::BottomLeft : EOrigin90::TopLeft, Amount / 0.5f, bClockwise); } else { FillRadial90(Helper, BOTTOM_BOX_CW, bClockwise ? EOrigin90::TopLeft : EOrigin90::BottomLeft, (Amount - 0.5f) / 0.5f, bClockwise); Helper.AddQuad(TOP_BOX_CW); Helper.AddTriangles(-4); } break; case EOrigin180::Right: if (Amount <= 0.5f) { FillRadial90(Helper, BOTTOM_BOX_CW, bClockwise ? EOrigin90::TopRight : EOrigin90::BottomRight, Amount / 0.5f, bClockwise); } else { FillRadial90(Helper, TOP_BOX_CW, bClockwise ? EOrigin90::BottomRight : EOrigin90::TopRight, (Amount - 0.5f) / 0.5f, bClockwise); Helper.AddQuad(BOTTOM_BOX_CW); Helper.AddTriangles(-4); } break; } } //12 vertex static void FillRadial360(FVertexHelper& Helper, FBox2D VertRect, EOrigin360 Origin, float Amount, bool bClockwise) { switch (Origin) { case EOrigin360::Top: if (Amount < 0.5f) { FillRadial180(Helper, RIGHT_BOX_CW, bClockwise ? EOrigin180::Left : EOrigin180::Right, Amount / 0.5f, bClockwise); } else { FillRadial180(Helper, LEFT_BOX_CW, bClockwise ? EOrigin180::Right : EOrigin180::Left, (Amount - 0.5f) / 0.5f, bClockwise); Helper.AddQuad(RIGHT_BOX_CW); Helper.AddTriangles(-4); } break; case EOrigin360::Bottom: if (Amount < 0.5f) { FillRadial180(Helper, LEFT_BOX_CW, bClockwise ? EOrigin180::Right : EOrigin180::Left, Amount / 0.5f, bClockwise); } else { FillRadial180(Helper, RIGHT_BOX_CW, bClockwise ? EOrigin180::Left : EOrigin180::Right, (Amount - 0.5f) / 0.5f, bClockwise); Helper.AddQuad(LEFT_BOX_CW); Helper.AddTriangles(-4); } break; case EOrigin360::Left: if (Amount < 0.5f) { FillRadial180(Helper, TOP_BOX_CW, bClockwise ? EOrigin180::Bottom : EOrigin180::Top, Amount / 0.5f, bClockwise); } else { FillRadial180(Helper, BOTTOM_BOX_CW, bClockwise ? EOrigin180::Top : EOrigin180::Bottom, (Amount - 0.5f) / 0.5f, bClockwise); Helper.AddQuad(TOP_BOX_CW); Helper.AddTriangles(-4); } break; case EOrigin360::Right: if (Amount < 0.5f) { FillRadial180(Helper, BOTTOM_BOX_CW, bClockwise ? EOrigin180::Top : EOrigin180::Bottom, Amount / 0.5f, bClockwise); } else { FillRadial180(Helper, TOP_BOX_CW, bClockwise ? EOrigin180::Bottom : EOrigin180::Top, (Amount - 0.5f) / 0.5f, bClockwise); Helper.AddQuad(BOTTOM_BOX_CW); Helper.AddTriangles(-4); } break; } } FFillMesh::FFillMesh() : Method(EFillMethod::None), Origin(0), bClockwise(true), Amount(1) { } void FFillMesh::OnPopulateMesh(FVertexHelper& Helper) { const float clampedAmount = FMath::Clamp(Amount, 0, 1); switch (Method) { case EFillMethod::Horizontal: FillHorizontal(Helper, Helper.ContentRect, Origin, clampedAmount); break; case EFillMethod::Vertical: FillVertical(Helper, Helper.ContentRect, Origin, clampedAmount); break; case EFillMethod::Radial90: FillRadial90(Helper, Helper.ContentRect, (EOrigin90)Origin, clampedAmount, bClockwise); break; case EFillMethod::Radial180: FillRadial180(Helper, Helper.ContentRect, (EOrigin180)Origin, clampedAmount, bClockwise); break; case EFillMethod::Radial360: FillRadial360(Helper, Helper.ContentRect, (EOrigin360)Origin, clampedAmount, bClockwise); break; } } ================================================ FILE: Source/FairyGUI/Private/Widgets/Mesh/MeshFactory.cpp ================================================ #include "Widgets/Mesh/MeshFactory.h" ================================================ FILE: Source/FairyGUI/Private/Widgets/Mesh/PolygonMesh.cpp ================================================ #include "Widgets/Mesh/PolygonMesh.h" FPolygonMesh::FPolygonMesh() : LineWidth(0), LineColor(FColor::Black), bUsePercentPositions(false) { } void FPolygonMesh::OnPopulateMesh(FVertexHelper& Helper) { int32 numVertices = Points.Num(); if (numVertices < 3) return; const FColor& color = FillColor.IsSet() ? FillColor.GetValue() : Helper.VertexColor; FVector2D Size = Helper.ContentRect.GetSize(); bool useTexcoords = Texcoords.Num() >= numVertices; for (int32 i = 0; i < numVertices; i++) { FVector2D vec = Points[i]; if (bUsePercentPositions) vec *= Size; if (useTexcoords) { FVector2D uv = FMath::Lerp(Helper.UVRect.Min, Helper.UVRect.Max, Texcoords[i]); Helper.AddVertex(vec, color, uv); } else Helper.AddVertex(vec, color); } // Algorithm "Ear clipping method" described here: // -> https://en.wikipedia.org/wiki/Polygon_triangulation // // Implementation inspired by: // -> http://polyk.ivank.net // -> Starling TArray RestIndices; for (int32 i = 0; i < numVertices; ++i) RestIndices.Add(i); int32 restIndexPos = 0; int32 numRestIndices = numVertices; while (numRestIndices > 3) { bool earFound = false; int32 i0 = RestIndices[restIndexPos % numRestIndices]; int32 i1 = RestIndices[(restIndexPos + 1) % numRestIndices]; int32 i2 = RestIndices[(restIndexPos + 2) % numRestIndices]; const FVector2D& a = Points[i0]; const FVector2D& b = Points[i1]; const FVector2D& c = Points[i2]; if ((a.Y - b.Y) * (c.X - b.X) + (b.X - a.X) * (c.Y - b.Y) >= 0) { earFound = true; for (int32 i = 3; i < numRestIndices; ++i) { int32 otherIndex = RestIndices[(restIndexPos + i) % numRestIndices]; const FVector2D& p = Points[otherIndex]; if (IsPointInTriangle(p, a, b, c)) { earFound = false; break; } } } if (earFound) { Helper.AddTriangle(i0, i1, i2); RestIndices.RemoveAt((restIndexPos + 1) % numRestIndices); numRestIndices--; restIndexPos = 0; } else { restIndexPos++; if (restIndexPos == numRestIndices) break; // no more ears } } Helper.AddTriangle(RestIndices[0], RestIndices[1], RestIndices[2]); if (Colors.IsSet()) Helper.RepeatColors(Colors.GetValue().GetData(), Colors.GetValue().Num(), 0, Helper.GetVertexCount()); if (LineWidth > 0) DrawOutline(Helper); } void FPolygonMesh::DrawOutline(FVertexHelper& Helper) { int32 numVertices = Points.Num(); int32 k = Helper.GetVertexCount(); int32 start = k - numVertices; for (int32 i = 0; i < numVertices; i++) { const FVector2D& p0 = Helper.Vertices[start + i].Position; FVector2D p1; if (i < numVertices - 1) p1 = Helper.Vertices[start + i + 1].Position; else p1 = Helper.Vertices[start].Position; FVector2D widthVector(p1.Y - p0.Y, p0.X - p1.X); widthVector.Normalize(); Helper.AddVertex(p0 - widthVector * LineWidth * 0.5f, LineColor); Helper.AddVertex(p0 + widthVector * LineWidth * 0.5f, LineColor); Helper.AddVertex(p1 - widthVector * LineWidth * 0.5f, LineColor); Helper.AddVertex(p1 + widthVector * LineWidth * 0.5f, LineColor); k += 4; Helper.AddTriangle(k - 4, k - 3, k - 1); Helper.AddTriangle(k - 4, k - 1, k - 2); //joint if (i != 0) { Helper.AddTriangle(k - 6, k - 5, k - 3); Helper.AddTriangle(k - 6, k - 3, k - 4); } if (i == numVertices - 1) { start += numVertices; Helper.AddTriangle(k - 2, k - 1, start + 1); Helper.AddTriangle(k - 2, start + 1, start); } } } bool FPolygonMesh::IsPointInTriangle(const FVector2D& p, const FVector2D& a, const FVector2D& b, const FVector2D& c) { // From Starling // This algorithm is described well in this article: // http://www.blackpawn.com/texts/pointinpoly/default.html float v0x = c.X - a.X; float v0y = c.Y - a.Y; float v1x = b.X - a.X; float v1y = b.Y - a.Y; float v2x = p.X - a.X; float v2y = p.Y - a.Y; float dot00 = v0x * v0x + v0y * v0y; float dot01 = v0x * v1x + v0y * v1y; float dot02 = v0x * v2x + v0y * v2y; float dot11 = v1x * v1x + v1y * v1y; float dot12 = v1x * v2x + v1y * v2y; float invDen = 1.0f / (dot00 * dot11 - dot01 * dot01); float u = (dot11 * dot02 - dot01 * dot12) * invDen; float v = (dot00 * dot12 - dot01 * dot02) * invDen; return (u >= 0) && (v >= 0) && (u + v < 1); } bool FPolygonMesh::HitTest(const FBox2D& ContentRect, const FVector2D& LayoutScaleMultiplier, const FVector2D& LocalPoint) const { // Algorithm & implementation thankfully taken from: // -> http://alienryderflex.com/polygon/ // inspired by Starling int32 len = Points.Num(); int32 i; int32 j = len - 1; bool oddNodes = false; FVector2D ContentSize = ContentRect.GetSize(); for (i = 0; i < len; ++i) { FVector2D vi = Points[i]; FVector2D vj = Points[j]; if (bUsePercentPositions) { vi *= ContentSize; vj *= ContentSize; } 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)) { if (vi.X + (LocalPoint.Y - vi.Y) / (vj.Y - vi.Y) * (vj.X - vi.X) < LocalPoint.X) oddNodes = !oddNodes; } j = i; } return oddNodes; } ================================================ FILE: Source/FairyGUI/Private/Widgets/Mesh/RectMesh.cpp ================================================ #include "Widgets/Mesh/RectMesh.h" FRectMesh::FRectMesh() : LineWidth(0), LineColor(FColor::Black) { } void FRectMesh::OnPopulateMesh(FVertexHelper& Helper) { const FBox2D& rect = DrawRect.IsSet() ? DrawRect.GetValue() : Helper.ContentRect; const FColor& color = FillColor.IsSet() ? FillColor.GetValue() : Helper.VertexColor; if (LineWidth == 0) { if (color.A != 0)//optimized Helper.AddQuad(rect, color); } else { FBox2D part; FVector2D Position; //left,right part = FBox2D(rect.Min, rect.Min + FVector2D(LineWidth, rect.GetSize().Y)); Helper.AddQuad(part, LineColor); Position = FVector2D(rect.Max.X - LineWidth, rect.Min.Y); part = FBox2D(Position, Position + FVector2D(LineWidth, rect.GetSize().Y)); Helper.AddQuad(part, LineColor); //top, bottom Position = FVector2D(rect.Min.X + LineWidth, rect.Min.Y); part = FBox2D(Position, Position + FVector2D(rect.GetSize().X - LineWidth * 2, LineWidth)); Helper.AddQuad(part, LineColor); Position = FVector2D(rect.Min.X + LineWidth, rect.Max.Y - LineWidth); part = FBox2D(Position, Position + FVector2D(rect.GetSize().X - LineWidth * 2, LineWidth)); Helper.AddQuad(part, LineColor); //middle if (color.A != 0)//optimized { part = FBox2D(rect.Min + LineWidth, rect.Max - LineWidth); if (part.GetSize().GetMin() > 0) Helper.AddQuad(part, color); } } if (Colors.IsSet()) Helper.RepeatColors(Colors.GetValue().GetData(), Colors.GetValue().Num(), 0, Helper.GetVertexCount()); Helper.AddTriangles(); } ================================================ FILE: Source/FairyGUI/Private/Widgets/Mesh/RegularPolygonMesh.cpp ================================================ #include "Widgets/Mesh/RegularPolygonMesh.h" FRegularPolygonMesh::FRegularPolygonMesh() : Sides(3), LineWidth(0), LineColor(FColor::Black), Rotation(0) { } void FRegularPolygonMesh::OnPopulateMesh(FVertexHelper& Helper) { if (Distances.Num() > 0) verifyf(Distances.Num() >= Sides, TEXT("Distances.Length 0) r *= Distances[i]; FVector2D vec = center + FVector2D(FMath::Cos(angle) * (r - LineWidth), FMath::Sin(angle) * (r - LineWidth)); Helper.AddVertex(vec, color); if (LineWidth > 0) { Helper.AddVertex(vec, LineColor); vec = FVector2D(FMath::Cos(angle) * r + center.X, FMath::Sin(angle) * r + center.Y); Helper.AddVertex(vec, LineColor); } angle += angleDelta; } if (LineWidth > 0) { int32 tmp = Sides * 3; for (int32 i = 0; i < tmp; i += 3) { if (i != tmp - 3) { Helper.AddTriangle(0, i + 1, i + 4); Helper.AddTriangle(i + 5, i + 2, i + 3); Helper.AddTriangle(i + 3, i + 6, i + 5); } else { Helper.AddTriangle(0, i + 1, 1); Helper.AddTriangle(2, i + 2, i + 3); Helper.AddTriangle(i + 3, 3, 2); } } } else { for (int32 i = 0; i < Sides; i++) Helper.AddTriangle(0, i + 1, (i == Sides - 1) ? 1 : i + 2); } } ================================================ FILE: Source/FairyGUI/Private/Widgets/Mesh/RoundedMesh.cpp ================================================ #include "Widgets/Mesh/RoundedRectMesh.h" FRoundedRectMesh::FRoundedRectMesh() : LineWidth(0), LineColor(FColor::Black), TopLeftRadius(0), TopRightRadius(0), BottomLeftRadius(0), BottomRightRadius(0) { } void FRoundedRectMesh::OnPopulateMesh(FVertexHelper& Helper) { const FBox2D& rect = DrawRect.IsSet() ? DrawRect.GetValue() : Helper.ContentRect; const FColor& color = FillColor.IsSet() ? FillColor.GetValue() : Helper.VertexColor; FVector2D radius = rect.GetSize() * 0.5f; float cornerMaxRadius = radius.GetMin(); FVector2D center = radius + rect.Min; Helper.AddVertex(center, color); int32 cnt = Helper.GetVertexCount(); for (int32 i = 0; i < 4; i++) { float cornerRadius = 0; switch (i) { case 0: cornerRadius = BottomRightRadius; break; case 1: cornerRadius = BottomLeftRadius; break; case 2: cornerRadius = TopLeftRadius; break; case 3: cornerRadius = TopRightRadius; break; } cornerRadius = FMath::Min(cornerMaxRadius, cornerRadius); FVector2D offset = rect.Min; if (i == 0 || i == 3) offset.X = rect.Max.X - cornerRadius * 2; if (i == 0 || i == 1) offset.Y = rect.Max.Y - cornerRadius * 2; if (cornerRadius != 0) { int32 partNumSides = FMath::Max(1, FMath::CeilToInt(PI * cornerRadius / 8)) + 1; float angleDelta = PI / 2 / partNumSides; float angle = PI / 2 * i; float startAngle = angle; for (int32 j = 1; j <= partNumSides; j++) { if (j == partNumSides) angle = startAngle + PI / 2; FVector2D v1(offset.X + FMath::Cos(angle) * (cornerRadius - LineWidth) + cornerRadius, offset.Y + FMath::Sin(angle) * (cornerRadius - LineWidth) + cornerRadius); Helper.AddVertex(v1, color); if (LineWidth != 0) { Helper.AddVertex(v1, LineColor); Helper.AddVertex(FVector2D(offset.X + FMath::Cos(angle) * cornerRadius + cornerRadius, offset.Y + FMath::Sin(angle) * cornerRadius + cornerRadius), LineColor); } angle += angleDelta; } } else { FVector2D v1 = offset; if (LineWidth != 0) { if (i == 0 || i == 3) offset.X -= LineWidth; else offset.X += LineWidth; if (i == 0 || i == 1) offset.Y -= LineWidth; else offset.Y += LineWidth; Helper.AddVertex(offset, color); Helper.AddVertex(offset, LineColor); Helper.AddVertex(v1, LineColor); } else Helper.AddVertex(v1, color); } } cnt = Helper.GetVertexCount() - cnt; if (LineWidth > 0) { for (int32 i = 0; i < cnt; i += 3) { if (i != cnt - 3) { Helper.AddTriangle(0, i + 1, i + 4); Helper.AddTriangle(i + 5, i + 2, i + 3); Helper.AddTriangle(i + 3, i + 6, i + 5); } else { Helper.AddTriangle(0, i + 1, 1); Helper.AddTriangle(2, i + 2, i + 3); Helper.AddTriangle(i + 3, 3, 2); } } } else { for (int32 i = 0; i < cnt; i++) Helper.AddTriangle(0, i + 1, (i == cnt - 1) ? 1 : i + 2); } } ================================================ FILE: Source/FairyGUI/Private/Widgets/Mesh/VertexHelper.cpp ================================================ #include "Widgets/Mesh/VertexHelper.h" FVertexHelper::FVertexHelper() : ContentRect(ForceInit), UVRect(ForceInit), VertexColor(FColor::White) { } void FVertexHelper::Clear() { Vertices.Reset(); } int32 FVertexHelper::GetVertexCount() const { return Vertices.Num(); } void FVertexHelper::AddVertex(const FVector2D& Position) { AddVertex(Position, VertexColor); } void FVertexHelper::AddVertex(const FVector2D& Position, const FColor& Color) { AddVertex(Position, Color, FMath::Lerp(UVRect.Min, UVRect.Max, (Position - ContentRect.Min) / ContentRect.GetSize())); } void FVertexHelper::AddVertex(const FVector2D& Position, const FColor& Color, const FVector2D& TexCoords) { FSlateVertex Vertex; Vertex.Position = Position; Vertex.Color = Color; Vertex.TexCoords[0] = TexCoords.X; Vertex.TexCoords[1] = TexCoords.Y; Vertex.TexCoords[2] = 1; Vertex.TexCoords[3] = 1; Vertex.MaterialTexCoords[0] = TexCoords.X; Vertex.MaterialTexCoords[1] = TexCoords.Y; Vertices.Add(Vertex); } void FVertexHelper::AddQuad(const FBox2D& VertRect) { AddQuad(VertRect, VertexColor); } void FVertexHelper::AddQuad(const FBox2D& VertRect, const FColor& Color) { AddVertex(FVector2D(VertRect.Min.X, VertRect.Max.Y), Color); AddVertex(FVector2D(VertRect.Min.X, VertRect.Min.Y), Color); AddVertex(FVector2D(VertRect.Max.X, VertRect.Min.Y), Color); AddVertex(FVector2D(VertRect.Max.X, VertRect.Max.Y), Color); } void FVertexHelper::AddQuad(const FBox2D& VertRect, const FColor& Color, const FBox2D& InUVRect) { AddVertex(FVector2D(VertRect.Min.X, VertRect.Max.Y), Color, FVector2D(InUVRect.Min.X, InUVRect.Max.Y)); AddVertex(FVector2D(VertRect.Min.X, VertRect.Min.Y), Color, FVector2D(InUVRect.Min.X, InUVRect.Min.Y)); AddVertex(FVector2D(VertRect.Max.X, VertRect.Min.Y), Color, FVector2D(InUVRect.Max.X, InUVRect.Min.Y)); AddVertex(FVector2D(VertRect.Max.X, VertRect.Max.Y), Color, FVector2D(InUVRect.Max.X, InUVRect.Max.Y)); } void FVertexHelper::RepeatColors(FColor* Colors, int32 ColorCount, int32 StartIndex, int32 Count) { int32 len = FMath::Min(StartIndex + Count, Vertices.Num()); int32 k = 0; for (int32 i = StartIndex; i < len; i++) { Vertices[i].Color = Colors[(k++) % ColorCount]; } } void FVertexHelper::AddTriangle(SlateIndex idx0, SlateIndex idx1, SlateIndex idx2) { Triangles.Add(idx0); Triangles.Add(idx1); Triangles.Add(idx2); } void FVertexHelper::AddTriangles(const SlateIndex* Indice, int32 IndiceLength, int32 StartVertexIndex) { if (StartVertexIndex != 0) { if (StartVertexIndex < 0) StartVertexIndex = Vertices.Num() + StartVertexIndex; for (int32 i = 0; i < IndiceLength; i++) Triangles.Add(Indice[i] + StartVertexIndex); } else { Triangles.Append(Indice, IndiceLength); } } void FVertexHelper::AddTriangles(int32 StartVertexIndex) { int32 cnt = Vertices.Num(); if (StartVertexIndex < 0) StartVertexIndex = cnt + StartVertexIndex; for (int32 i = StartVertexIndex; i < cnt; i += 4) { Triangles.Add(i); Triangles.Add(i + 1); Triangles.Add(i + 2); Triangles.Add(i + 2); Triangles.Add(i + 3); Triangles.Add(i); } } const FVector2D& FVertexHelper::GetPosition(int32 Index) { if (Index < 0) Index = Vertices.Num() + Index; return Vertices[Index].Position; } FVector2D FVertexHelper::GetUVAtPosition(const FVector2D& Position, bool bUsePercent) { if (bUsePercent) return FMath::Lerp(UVRect.Min, UVRect.Max, Position); else return FMath::Lerp(UVRect.Min, UVRect.Max, (Position - ContentRect.Min) / ContentRect.GetSize()); } void FVertexHelper::Append(const FVertexHelper& VertexHelper) { Vertices += VertexHelper.Vertices; Triangles += VertexHelper.Triangles; } void FVertexHelper::Insert(const FVertexHelper& VertexHelper) { Vertices.Insert(VertexHelper.Vertices.GetData(), VertexHelper.Vertices.Num(), 0); Triangles.Insert(VertexHelper.Triangles.GetData(), VertexHelper.Triangles.Num(), 0); } ================================================ FILE: Source/FairyGUI/Private/Widgets/NGraphics.cpp ================================================ #include "Widgets/NGraphics.h" FNGraphics::FNGraphics() : Size(ForceInit), Color(FColor::White), Flip(EFlipType::None), Texture(nullptr), UsingAlpha(1), bMeshDirty(false) { } FNGraphics::~FNGraphics() { } void FNGraphics::SetColor(const FColor& InColor) { if (Color != InColor) { bMeshDirty = true; Color = InColor; } } void FNGraphics::SetFlip(EFlipType InFlip) { if (Flip != InFlip) { Flip = InFlip; bMeshDirty = true; } } void FNGraphics::SetMeshFactory(const TSharedPtr& InMeshFactory) { MeshFactory = InMeshFactory; bMeshDirty = true; } void FNGraphics::SetTexture(UNTexture* InTexture) { if (InTexture != Texture) { Texture = InTexture; if (InTexture != nullptr) { Brush.SetResourceObject(InTexture->NativeTexture); Brush.SetImageSize(InTexture->GetSize()); //static const FSlateBrush* WhiteBrush = FCoreStyle::Get().GetBrush("GenericWhiteBox"); ResourceHandle = FSlateApplication::Get().GetRenderer()->GetResourceHandle(Brush); } else { Brush.SetResourceObject(nullptr); ResourceHandle = FSlateResourceHandle(); } bMeshDirty = true; } } void FNGraphics::Paint(const FGeometry& AllottedGeometry, FSlateWindowElementList& OutDrawElements, int32 LayerId, float Alpha, bool bEnabled) { if (Size != AllottedGeometry.GetLocalSize()) { Size = AllottedGeometry.GetLocalSize(); bMeshDirty = true; } if (bMeshDirty) { UsingAlpha = Alpha; UpdateMeshNow(); } else if (Alpha != UsingAlpha) { UsingAlpha = Alpha; int32 cnt = Vertices.Num(); for (int32 i = 0; i < cnt; i++) { Vertices[i].Color.A = (uint8)FMath::Clamp(FMath::TruncToInt(AlphaBackup[i] * UsingAlpha), 0, 255); } } const ESlateDrawEffect DrawEffects = bEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect; int32 VerticeLength = Vertices.Num(); for (int32 i = 0; i < VerticeLength; i++) { Vertices[i].Position = AllottedGeometry.LocalToAbsolute(PositionsBackup[i]); } FSlateDrawElement::MakeCustomVerts(OutDrawElements, LayerId, ResourceHandle, Vertices, Triangles, nullptr, 0, 0, DrawEffects); } void FNGraphics::UpdateMeshNow() { bMeshDirty = false; Vertices.Reset(); Triangles.Reset(); if (Texture == nullptr || !MeshFactory.IsValid()) return; FVertexHelper Helper; Helper.ContentRect = FBox2D(FVector2D::ZeroVector, Size); Helper.UVRect = Texture->UVRect; Helper.TextureSize = Texture->GetSize(); if (Flip != EFlipType::None) { if (Flip == EFlipType::Horizontal || Flip == EFlipType::Both) { float tmp = Helper.UVRect.Min.X; Helper.UVRect.Min.X = Helper.UVRect.Max.X; Helper.UVRect.Max.X = tmp; } if (Flip == EFlipType::Vertical || Flip == EFlipType::Both) { float tmp = Helper.UVRect.Min.Y; Helper.UVRect.Min.Y = Helper.UVRect.Max.Y; Helper.UVRect.Max.Y = tmp; } } Helper.VertexColor = Color; MeshFactory->OnPopulateMesh(Helper); int32 vertCount = Helper.GetVertexCount(); if (vertCount == 0) return; if (Texture->bRotated) { float xMin = Texture->UVRect.Min.X; float yMin = Texture->UVRect.Min.Y; float xMax = Texture->UVRect.Max.X; float yMax = Texture->UVRect.Max.Y; for (int32 i = 0; i < vertCount; i++) { auto& vec = Helper.Vertices[i].TexCoords; float tmp = vec[1]; vec[1] = yMin + xMax - vec[0]; vec[0] = xMin + tmp - yMin; } } AlphaBackup.SetNum(vertCount, false); PositionsBackup.SetNum(vertCount, false); for (int32 i = 0; i < vertCount; i++) { FSlateVertex& Vertex = Helper.Vertices[i]; AlphaBackup[i] = Vertex.Color.A; Vertex.Color.A = (uint8)FMath::Clamp(FMath::TruncToInt(Vertex.Color.A * UsingAlpha), 0, 255), PositionsBackup[i] = Vertex.Position; } Vertices += Helper.Vertices; Triangles += Helper.Triangles; } void FNGraphics::PopulateDefaultMesh(FVertexHelper& Helper) { FBox2D rect = Texture->GetDrawRect(Helper.ContentRect); Helper.AddQuad(rect, Helper.VertexColor, Helper.UVRect); Helper.AddTriangles(); } void FNGraphics::AddReferencedObjects(FReferenceCollector& Collector) { if (Texture != nullptr) Collector.AddReferencedObject(Texture); } ================================================ FILE: Source/FairyGUI/Private/Widgets/NTextFormat.cpp ================================================ #include "Widgets/NTextFormat.h" #include "UI/UIConfig.h" #include "UI/UIPackage.h" FNTextFormat::FNTextFormat() : Size(12), Color(FColor::White), bBold(false), bItalic(false), bUnderline(false), LineSpacing(3), LetterSpacing(0), Align(EAlignType::Left), VerticalAlign(EVerticalAlignType::Top), OutlineColor(FColor::Black), OutlineSize(0), ShadowColor(FColor::Black), ShadowOffset(0, 0) { } bool FNTextFormat::EqualStyle(const FNTextFormat& AnotherFormat) const { return Size == AnotherFormat.Size && Color == AnotherFormat.Color && bBold == AnotherFormat.bBold && bUnderline == AnotherFormat.bUnderline && bItalic == AnotherFormat.bItalic && Align == AnotherFormat.Align; } FTextBlockStyle FNTextFormat::GetStyle() const { FTextBlockStyle Style; const FString& FontFace = Face.IsEmpty() ? FUIConfig::Config.DefaultFont : Face; if (!FontFace.StartsWith("ui://")) { const UObject* Font = UUIPackageStatic::Get().Fonts.FindRef(FontFace); if (Font != nullptr) { FSlateFontInfo SlateFont(Font, Size * 0.75f); SlateFont.OutlineSettings.OutlineSize = OutlineSize; SlateFont.OutlineSettings.OutlineColor = OutlineColor; Style.SetFont(SlateFont); } else { FSlateFontInfo SlateFont = FCoreStyle::GetDefaultFontStyle(*FontFace, Size * 0.75f); SlateFont.OutlineSettings.OutlineSize = OutlineSize; SlateFont.OutlineSettings.OutlineColor = OutlineColor; Style.SetFont(SlateFont); } } Style.SetColorAndOpacity(FSlateColor(FLinearColor(Color))); Style.SetShadowOffset(ShadowOffset); Style.SetShadowColorAndOpacity(ShadowColor); return MoveTemp(Style); } ================================================ FILE: Source/FairyGUI/Private/Widgets/NTexture.cpp ================================================ #include "Widgets/NTexture.h" #include "FairyApplication.h" UNTexture* UNTexture::WhiteTexture = nullptr; UNTexture* UNTexture::GetWhiteTexture() { if (WhiteTexture == nullptr) { UTexture2D* NativeTexture = UTexture2D::CreateTransient(2, 2); uint8* MipData = (uint8*)NativeTexture->PlatformData->Mips[0].BulkData.Lock(LOCK_READ_WRITE); for (int32 i = 0; i < 16; i++) *(MipData + i) = 255; NativeTexture->PlatformData->Mips[0].BulkData.Unlock(); #if WITH_EDITORONLY_DATA NativeTexture->CompressionNone = true; NativeTexture->MipGenSettings = TMGS_NoMipmaps; #endif // WITH_EDITORONLY_DATA NativeTexture->CompressionSettings = TC_Default; NativeTexture->UpdateResource(); WhiteTexture = NewObject(); WhiteTexture->AddToRoot(); WhiteTexture->Init(NativeTexture); } return WhiteTexture; } void UNTexture::DestroyWhiteTexture() { if (WhiteTexture != nullptr) { WhiteTexture->RemoveFromRoot(); WhiteTexture = nullptr; } } UNTexture::UNTexture() : UVRect(ForceInit), Region(ForceInit), Offset(ForceInit), OriginalSize(ForceInit) { } void UNTexture::Init(UTexture2D* InNativeTexture) { Init(InNativeTexture, 1, 1); } void UNTexture::Init(UTexture2D* InNativeTexture, float ScaleX, float ScaleY) { NativeTexture = InNativeTexture; UVRect = FBox2D(FVector2D::ZeroVector, FVector2D(ScaleX, ScaleY)); if (ScaleY < 0) { UVRect.Min.Y = -ScaleY; UVRect.Max.Y = 0; } if (ScaleX < 0) { UVRect.Min.X = -ScaleX; UVRect.Max.X = 0; } if (NativeTexture != nullptr) OriginalSize.Set(NativeTexture->GetSurfaceWidth(), NativeTexture->GetSurfaceHeight()); Region = FBox2D(FVector2D::ZeroVector, FVector2D(OriginalSize.X, OriginalSize.Y)); } void UNTexture::Init(UTexture2D* InNativeTexture, const FBox2D& InRegion) { NativeTexture = InNativeTexture; Region = InRegion; Region.bIsValid = true; OriginalSize = Region.GetSize(); if (NativeTexture != nullptr) { UVRect = FBox2D(FVector2D(Region.Min.X / NativeTexture->GetSurfaceWidth(), Region.Min.Y / NativeTexture->GetSurfaceHeight()), FVector2D(Region.Max.X / NativeTexture->GetSurfaceWidth(), Region.Max.Y / NativeTexture->GetSurfaceHeight())); } else UVRect = FBox2D(FVector2D::ZeroVector, FVector2D(1, 1)); } void UNTexture::Init(UNTexture* InRoot, const FBox2D& InRegion, bool bInRotated) { Root = InRoot; NativeTexture = Root->NativeTexture; bRotated = bInRotated; Region = InRegion; Region.bIsValid = true; Region.Min.X += Root->Region.Min.X; Region.Min.Y += Root->Region.Min.Y; FVector2D RootSize = Root->GetSize(); UVRect = FBox2D(FVector2D(Region.Min.X * Root->UVRect.GetSize().X / RootSize.X, Region.Min.Y * Root->UVRect.GetSize().Y / RootSize.Y), FVector2D(Region.Max.X * Root->UVRect.GetSize().X / RootSize.X, Region.Max.Y * Root->UVRect.GetSize().Y / RootSize.Y)); if (bRotated) { FVector2D TmpSize = Region.GetSize(); Region.Max.X = Region.Min.X + TmpSize.Y; Region.Max.Y = Region.Min.Y + TmpSize.X; TmpSize = UVRect.GetSize(); UVRect.Max.X = UVRect.Min.X + TmpSize.Y; UVRect.Max.Y = UVRect.Min.Y + TmpSize.X; } OriginalSize = Region.GetSize(); } void UNTexture::Init(UNTexture* InRoot, const FBox2D& InRegion, bool bInRotated, const FVector2D& InOriginalSize, const FVector2D& InOffset) { Init(InRoot, InRegion, bInRotated); OriginalSize = InOriginalSize; Offset = InOffset; } FVector2D UNTexture::GetSize() const { return Region.GetSize(); } FBox2D UNTexture::GetDrawRect(FBox2D& InDrawRect) const { if (OriginalSize == Region.GetSize()) return InDrawRect; FVector2D Scale = InDrawRect.GetSize() / OriginalSize; return FBox2D(Offset * Scale, (Region.GetSize() + Offset)*Scale); } ================================================ FILE: Source/FairyGUI/Private/Widgets/SContainer.cpp ================================================ #include "Widgets/SContainer.h" #include "FairyApplication.h" #include "UI/GObject.h" SContainer::SContainer() : Children(this) { bCanSupportFocus = false; } void SContainer::Construct(const SContainer::FArguments& InArgs) { SDisplayObject::Construct(SDisplayObject::FArguments().GObject(InArgs._GObject)); } void SContainer::AddChild(const TSharedRef& SlotWidget) { AddChildAt(SlotWidget, Children.Num()); } void SContainer::AddChildAt(const TSharedRef& SlotWidget, int32 Index) { int32 Count = Children.Num(); verifyf(Index >= 0 && Index <= Count, TEXT("Invalid child index")); if (SlotWidget->GetParentWidget().Get() == this) SetChildIndex(SlotWidget, Index); else { verifyf(!SlotWidget->GetParentWidget().IsValid(), TEXT("Cant add a child has parent")); FSlotBase& NewSlot = *new FSlotBase(); if (Index == Count) Children.Add(&NewSlot); else Children.Insert(&NewSlot, Index); NewSlot.AttachWidget(SlotWidget); UGObject* OnStageObj = SDisplayObject::GetWidgetGObjectIfOnStage(AsShared()); if (OnStageObj != nullptr) { OnStageObj->GetApp()->BroadcastEvent(FUIEvents::AddedToStage, SlotWidget); } } } void SContainer::SetChildIndex(const TSharedRef& SlotWidget, int32 Index) { if (Index >= Children.Num()) Index = Children.Num() - 1; int32 OldIndex = GetChildIndex(SlotWidget); verifyf(OldIndex != -1, TEXT("Not a child of this container")); if (OldIndex == Index) return; Children.Move(OldIndex, Index); } void SContainer::RemoveChild(const TSharedRef& SlotWidget) { int32 Index = GetChildIndex(SlotWidget); RemoveChildAt(Index); } void SContainer::RemoveChildAt(int32 Index) { verifyf(Index >= 0 && Index < Children.Num(), TEXT("Invalid child index")); TSharedRef SlotWidget = Children[Index].GetWidget(); UGObject* OnStageObj = SDisplayObject::GetWidgetGObjectIfOnStage(AsShared()); if (OnStageObj != nullptr) { OnStageObj->GetApp()->BroadcastEvent(FUIEvents::RemovedFromStage, SlotWidget); } Children.RemoveAt(Index); } int32 SContainer::GetChildIndex(const TSharedRef& SlotWidget) const { for (int32 SlotIdx = 0; SlotIdx < Children.Num(); ++SlotIdx) { if (SlotWidget == Children[SlotIdx].GetWidget()) { return SlotIdx; } } return -1; } void SContainer::RemoveChildren(int32 BeginIndex, int32 EndIndex) { if (EndIndex < 0 || EndIndex >= Children.Num()) EndIndex = Children.Num() - 1; UGObject* OnStageObj = SDisplayObject::GetWidgetGObjectIfOnStage(AsShared()); UFairyApplication* Dispatcher = OnStageObj != nullptr ? OnStageObj->GetApp() : nullptr; if (Dispatcher != nullptr || BeginIndex > 0 || EndIndex < Children.Num() - 1) { for (int32 i = BeginIndex; i <= EndIndex; ++i) { if (Dispatcher != nullptr) { TSharedRef SlotWidget = Children[BeginIndex].GetWidget(); Dispatcher->BroadcastEvent(FUIEvents::RemovedFromStage, SlotWidget); } Children.RemoveAt(BeginIndex); } } else Children.Empty(); } int32 SContainer::NumChildren() const { return Children.Num(); } void SContainer::OnArrangeChildren(const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const { if (Children.Num() > 0) { SDisplayObject::bMindVisibleOnly = true; for (int32 ChildIndex = 0; ChildIndex < Children.Num(); ++ChildIndex) { const FSlotBase& CurChild = Children[ChildIndex]; const TSharedRef& CurWidget = CurChild.GetWidget(); if (ArrangedChildren.Accepts(CurWidget->GetVisibility())) ArrangedChildren.AddWidget(AllottedGeometry.MakeChild( CurWidget, FVector2D::ZeroVector, CurWidget.Get().GetDesiredSize() )); } SDisplayObject::bMindVisibleOnly = false; } } int32 SContainer::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const { FArrangedChildren ArrangedChildren(EVisibility::Visible); ArrangeChildren(AllottedGeometry, ArrangedChildren); // Because we paint multiple children, we must track the maximum layer id that they produced in case one of our parents // wants to an overlay for all of its contents. int32 MaxLayerId = LayerId; const bool bForwardedEnabled = ShouldBeEnabled(bParentEnabled); const FPaintArgs NewArgs = Args.WithNewParent(this); for (int32 ChildIndex = 0; ChildIndex < ArrangedChildren.Num(); ++ChildIndex) { FArrangedWidget& CurWidget = ArrangedChildren[ChildIndex]; //if (!IsChildWidgetCulled(MyCullingRect, CurWidget)) { const int32 CurWidgetsMaxLayerId = CurWidget.Widget->Paint(NewArgs, CurWidget.Geometry, MyCullingRect, OutDrawElements, MaxLayerId + 1, InWidgetStyle, bForwardedEnabled); MaxLayerId = FMath::Max(MaxLayerId, CurWidgetsMaxLayerId); } //else { } } return MaxLayerId; } FChildren* SContainer::GetChildren() { return &Children; } ================================================ FILE: Source/FairyGUI/Private/Widgets/SDisplayObject.cpp ================================================ #include "Widgets/SDisplayObject.h" #include "FairyApplication.h" #include "Engine/GameViewportClient.h" #include "UI/GObject.h" bool SDisplayObject::bMindVisibleOnly = false; FNoChildren SDisplayObject::NoChildrenInstance; FName SDisplayObject::SDisplayObjectTag("SDisplayObjectTag"); SDisplayObject::SDisplayObject() : bVisible(true), bInteractable(true), bTouchable(true), bOpaque(true), Size(ForceInit) { SetCanTick(false); bCanSupportFocus = false; } void SDisplayObject::Construct(const SDisplayObject::FArguments& InArgs) { GObject = InArgs._GObject; SetTag(InArgs._Tag); } const FVector2D& SDisplayObject::GetPosition() const { if (!GetRenderTransform().IsSet()) return FVector2D::ZeroVector; else return GetRenderTransform()->GetTranslation(); } void SDisplayObject::SetPosition(const FVector2D& InPosition) { if (!GetRenderTransform().IsSet()) SetRenderTransform(FSlateRenderTransform(InPosition)); else SetRenderTransform( FSlateRenderTransform(GetRenderTransform()->GetMatrix(), InPosition)); } void SDisplayObject::SetX(float InX) { if (!GetRenderTransform().IsSet()) SetRenderTransform(FSlateRenderTransform(FVector2D(InX, 0))); else SetRenderTransform( FSlateRenderTransform(GetRenderTransform()->GetMatrix(), FVector2D(InX, GetRenderTransform()->GetTranslation().Y))); } void SDisplayObject::SetY(float InY) { if (!GetRenderTransform().IsSet()) SetRenderTransform(FSlateRenderTransform(FVector2D(0, InY))); else SetRenderTransform( FSlateRenderTransform(GetRenderTransform()->GetMatrix(), FVector2D(GetRenderTransform()->GetTranslation().X, InY))); } void SDisplayObject::SetSize(const FVector2D& InSize) { if (Size != InSize) { Size = InSize; Invalidate(EInvalidateWidget::LayoutAndVolatility); } } void SDisplayObject::SetVisible(bool bInVisible) { if (bVisible != bInVisible) { bVisible = bInVisible; UpdateVisibilityFlags(); } } void SDisplayObject::SetTouchable(bool bInTouchable) { if (bTouchable != bInTouchable) { bTouchable = bInTouchable; UpdateVisibilityFlags(); } } void SDisplayObject::SetOpaque(bool bInOpaque) { if (bOpaque != bInOpaque) { bOpaque = bInOpaque; UpdateVisibilityFlags(); } } void SDisplayObject::SetInteractable(bool bInInteractable) { if (bInteractable != bInInteractable) { bInteractable = bInInteractable; UpdateVisibilityFlags(); } } void SDisplayObject::UpdateVisibilityFlags() { bool HitTestFlag = bInteractable && bTouchable; if (!bVisible) SetVisibility(EVisibility::Collapsed); else if (!HitTestFlag) SetVisibility(EVisibility::HitTestInvisible); else if (GObject.IsValid() && GObject->GetHitArea() != nullptr) Visibility.BindRaw(this, &SDisplayObject::GetVisibilityFlags); else if (!bOpaque) SetVisibility(EVisibility::SelfHitTestInvisible); else SetVisibility(EVisibility::All); } EVisibility SDisplayObject::GetVisibilityFlags() const { if (!bMindVisibleOnly && GObject.IsValid() && GObject->GetHitArea() != nullptr) { FVector2D Pos = GObject->GetApp()->GetTouchPosition(); Pos = GObject->GlobalToLocal(Pos); FBox2D ContentRect(FVector2D::ZeroVector, GObject->GetSize()); if (!ContentRect.IsInside(Pos)) return EVisibility::HitTestInvisible; FVector2D LayoutScaleMultiplier = GObject->GetSize() / GObject->SourceSize; if (LayoutScaleMultiplier.ContainsNaN()) LayoutScaleMultiplier.Set(1, 1); if (!GObject->GetHitArea()->HitTest(ContentRect, LayoutScaleMultiplier, Pos)) return EVisibility::HitTestInvisible; else return EVisibility::All; } else { if (!bOpaque) return EVisibility::SelfHitTestInvisible; else return EVisibility::All; } } FVector2D SDisplayObject::ComputeDesiredSize(float) const { return Size; } FChildren* SDisplayObject::GetChildren() { return &NoChildrenInstance; } void SDisplayObject::OnArrangeChildren(const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const { } int32 SDisplayObject::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const { return LayerId; } FReply SDisplayObject::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { UGObject* Obj = GetWidgetGObject(AsShared()); if (Obj != nullptr) return Obj->GetApp()->OnWidgetMouseButtonDown(AsShared(), MyGeometry, MouseEvent); else return FReply::Unhandled(); } FReply SDisplayObject::OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { UGObject* Obj = GetWidgetGObject(AsShared()); if (Obj != nullptr) return Obj->GetApp()->OnWidgetMouseButtonUp(AsShared(), MyGeometry, MouseEvent); else return FReply::Unhandled(); } FReply SDisplayObject::OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { UGObject* Obj = GetWidgetGObject(AsShared()); if (Obj != nullptr) return Obj->GetApp()->OnWidgetMouseMove(AsShared(), MyGeometry, MouseEvent); else return FReply::Unhandled(); } FReply SDisplayObject::OnMouseButtonDoubleClick(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { UGObject* Obj = GetWidgetGObject(AsShared()); if (Obj != nullptr) return Obj->GetApp()->OnWidgetMouseButtonDoubleClick(AsShared(), MyGeometry, MouseEvent); else return FReply::Unhandled(); } void SDisplayObject::OnMouseEnter(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { UGObject* Obj = GetWidgetGObject(AsShared()); if (Obj != nullptr) Obj->GetApp()->OnWidgetMouseEnter(AsShared(), MyGeometry, MouseEvent); } void SDisplayObject::OnMouseLeave(const FPointerEvent& MouseEvent) { UGObject* Obj = GetWidgetGObject(AsShared()); if (Obj != nullptr) Obj->GetApp()->OnWidgetMouseLeave(AsShared(), MouseEvent); } FReply SDisplayObject::OnMouseWheel(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { UGObject* Obj = GetWidgetGObject(AsShared()); if (Obj != nullptr) return Obj->GetApp()->OnWidgetMouseWheel(AsShared(), MyGeometry, MouseEvent); else return FReply::Unhandled(); } bool SDisplayObject::IsWidgetOnStage(const TSharedPtr& InWidget) { TSharedPtr Ptr = InWidget; while (Ptr.IsValid()) { if (Ptr->Advanced_IsWindow()) return true; Ptr = Ptr->GetParentWidget(); } return false; } UGObject* SDisplayObject::GetWidgetGObject(const TSharedPtr& InWidget) { TSharedPtr Ptr = InWidget; while (Ptr.IsValid() && !Ptr->Advanced_IsWindow()) { if (Ptr->GetTag() == SDisplayObject::SDisplayObjectTag) { const TWeakObjectPtr& ObjPtr = StaticCastSharedPtr(Ptr)->GObject; if (ObjPtr.IsValid()) return ObjPtr.Get(); } Ptr = Ptr->GetParentWidget(); } return nullptr; } UGObject* SDisplayObject::GetWidgetGObjectIfOnStage(const TSharedPtr& InWidget) { TSharedPtr Ptr = InWidget; UGObject* Result = nullptr; while (Ptr.IsValid()) { if (Ptr->Advanced_IsWindow()) return Result; if (Result == nullptr && Ptr->GetTag() == SDisplayObject::SDisplayObjectTag) Result = StaticCastSharedPtr(Ptr)->GObject.Get(); Ptr = Ptr->GetParentWidget(); } return nullptr; } void SDisplayObject::GetWidgetPathToRoot(const TSharedRef& InWidget, TArray& OutArray) { TSharedPtr Ptr = InWidget; while (Ptr.IsValid() && !Ptr->Advanced_IsWindow()) { if (Ptr->GetTag() == SDisplayObject::SDisplayObjectTag) { const TWeakObjectPtr& ObjPtr = StaticCastSharedPtr(Ptr)->GObject; if (ObjPtr.IsValid()) OutArray.Add(ObjPtr.Get()); } Ptr = Ptr->GetParentWidget(); } } void SDisplayObject::GetWidgetDescendants(const TSharedRef& InWidget, TArray& OutArray) { if (InWidget->GetTag() == SDisplayObject::SDisplayObjectTag) { const TSharedRef& DisplayObject = StaticCastSharedRef(InWidget); if (DisplayObject->GObject.IsValid()) OutArray.Add(DisplayObject->GObject.Get()); } FChildren* Children = InWidget->GetChildren(); for (int32 SlotIdx = 0; SlotIdx < Children->Num(); ++SlotIdx) { GetWidgetDescendants(Children->GetChildAt(SlotIdx), OutArray); } } ================================================ FILE: Source/FairyGUI/Private/Widgets/SFImage.cpp ================================================ #include "Widgets/SFImage.h" #include "Widgets/NTexture.h" #include "Widgets/Mesh/VertexHelper.h" #include "UI/FieldTypes.h" SFImage::SFImage() : bScaleByTile(false), TextureScale(1, 1), TileGridIndice(0) { Graphics.SetMeshFactory(MakeShared(this)); } void SFImage::Construct(const FArguments& InArgs) { SDisplayObject::Construct(SDisplayObject::FArguments().GObject(InArgs._GObject)); } void SFImage::SetTexture(UNTexture* InTexture) { Graphics.SetTexture(InTexture); if (InTexture != nullptr && Size.IsZero()) { SetSize(InTexture->GetSize()); Invalidate(EInvalidateWidget::LayoutAndVolatility); } } void SFImage::SetNativeSize() { if (Graphics.GetTexture() != nullptr) SetSize(Graphics.GetTexture()->GetSize()); } void SFImage::SetScale9Grid(const TOptional& InGridRect) { Scale9Grid = InGridRect; } void SFImage::SetScaleByTile(bool bInScaleByTile) { if (bScaleByTile != bInScaleByTile) { bScaleByTile = bInScaleByTile; Graphics.SetMeshDirty(); } } void SFImage::SetTileGridIndice(int32 InTileGridIndex) { if (TileGridIndice != InTileGridIndex) { TileGridIndice = InTileGridIndex; Graphics.SetMeshDirty(); } } EFillMethod SFImage::GetFillMethod() const { return FillMesh.IsValid() ? FillMesh->Method : EFillMethod::None; } void SFImage::SetFillMethod(EFillMethod InMethod) { if (!FillMesh.IsValid()) { if (InMethod == EFillMethod::None) return; FillMesh = MakeUnique(); } if (FillMesh->Method != InMethod) { FillMesh->Method = InMethod; Graphics.SetMeshDirty(); } } int32 SFImage::GetFillOrigin() const { return FillMesh.IsValid() ? FillMesh->Origin : 0; } void SFImage::SetFillOrigin(int32 InOrigin) { if (!FillMesh.IsValid()) FillMesh = MakeUnique(); if (FillMesh->Origin != InOrigin) { FillMesh->Origin = InOrigin; Graphics.SetMeshDirty(); } } bool SFImage::IsFillClockwise() const { return FillMesh.IsValid() ? FillMesh->bClockwise : true; } void SFImage::SetFillClockwise(bool bInClockwise) { if (!FillMesh.IsValid()) FillMesh = MakeUnique(); if (FillMesh->bClockwise != bInClockwise) { FillMesh->bClockwise = bInClockwise; Graphics.SetMeshDirty(); } } float SFImage::GetFillAmount() const { return FillMesh.IsValid() ? FillMesh->Amount : 0; } void SFImage::SetFillAmount(float InAmount) { if (!FillMesh.IsValid()) FillMesh = MakeUnique(); if (FillMesh->Amount != InAmount) { FillMesh->Amount = InAmount; Graphics.SetMeshDirty(); } } int32 SFImage::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const { const bool bIsEnabled = ShouldBeEnabled(bParentEnabled); const_cast(this)->Graphics.Paint(AllottedGeometry, OutDrawElements, LayerId, InWidgetStyle.GetColorAndOpacityTint().A, bIsEnabled); return LayerId; } void SFImage::OnPopulateMesh(FVertexHelper& Helper) { if (FillMesh.IsValid() && FillMesh->Method != EFillMethod::None) { FillMesh->OnPopulateMesh(Helper); } else if (bScaleByTile) { UNTexture* Texture = Graphics.GetTexture(); if (Texture->Root == Texture && Texture->NativeTexture != nullptr && Texture->NativeTexture->AddressX == TextureAddress::TA_Mirror && Texture->NativeTexture->AddressY == TextureAddress::TA_Mirror) { FBox2D UVRect = Helper.UVRect; UVRect.Max = UVRect.Min + UVRect.GetSize() * Helper.ContentRect.GetSize() / Texture->GetSize() * TextureScale; Helper.AddQuad(Helper.ContentRect, Helper.VertexColor, UVRect); Helper.AddTriangles(); } else { FBox2D ContentRect = Helper.ContentRect; ContentRect.Max = ContentRect.Min + ContentRect.GetSize() * TextureScale; TileFill(Helper, ContentRect, Helper.UVRect, Graphics.GetTexture()->GetSize()); Helper.AddTriangles(); } } else if (Scale9Grid.IsSet()) { SliceFill(Helper); } else Graphics.PopulateDefaultMesh(Helper); } void SFImage::SliceFill(FVertexHelper& Helper) { const SlateIndex TRIANGLES_9_GRID[] = { 4, 0, 1, 1, 5, 4, 5, 1, 2, 2, 6, 5, 6, 2, 3, 3, 7, 6, 8, 4, 5, 5, 9, 8, 9, 5, 6, 6, 10, 9, 10, 6, 7, 7, 11, 10, 12, 8, 9, 9, 13, 12, 13, 9, 10, 10, 14, 13, 14, 10, 11, 11, 15, 14 }; const int32 gridTileIndice[] = { -1, 0, -1, 2, 4, 3, -1, 1, -1 }; static float gridX[4]; static float gridY[4]; static float gridTexX[4]; static float gridTexY[4]; UNTexture* Texture = Graphics.GetTexture(); FBox2D GridRect = Scale9Grid.GetValue(); FBox2D ContentRect = Helper.ContentRect; ContentRect.Max = ContentRect.Min + ContentRect.GetSize() * TextureScale; FBox2D UVRect = Helper.UVRect; FVector2D TextureSize = Texture->GetSize(); EFlipType FlipType = Graphics.GetFlip(); if (FlipType != EFlipType::None) { if (FlipType == EFlipType::Horizontal || FlipType == EFlipType::Both) { GridRect.Min.X = TextureSize.X - GridRect.Max.X; GridRect.Max.X = GridRect.Min.X + GridRect.GetSize().X; } if (FlipType == EFlipType::Vertical || FlipType == EFlipType::Both) { GridRect.Min.Y = TextureSize.Y - GridRect.Max.Y; GridRect.Max.Y = GridRect.Min.Y + GridRect.GetSize().Y; } } FVector2D Scale = UVRect.GetSize() / TextureSize; gridTexX[0] = UVRect.Min.X; gridTexX[1] = UVRect.Min.X + GridRect.Min.X * Scale.X; gridTexX[2] = UVRect.Min.X + GridRect.Max.X * Scale.X; gridTexX[3] = UVRect.Max.X; gridTexY[0] = UVRect.Min.Y; gridTexY[1] = UVRect.Min.Y + GridRect.Min.Y * Scale.Y; gridTexY[2] = UVRect.Min.Y + GridRect.Max.Y * Scale.Y; gridTexY[3] = UVRect.Max.Y; if (ContentRect.GetSize().X >= (Scale.X - GridRect.GetSize().X)) { gridX[1] = GridRect.Min.X; gridX[2] = ContentRect.GetSize().X - (TextureSize.X - GridRect.Max.X); gridX[3] = ContentRect.GetSize().X; } else { float tmp = GridRect.Min.X / (TextureSize.X - GridRect.Max.X); tmp = ContentRect.GetSize().X * tmp / (1 + tmp); gridX[1] = tmp; gridX[2] = tmp; gridX[3] = ContentRect.GetSize().X; } if (ContentRect.GetSize().Y >= (TextureSize.Y - GridRect.GetSize().Y)) { gridY[1] = GridRect.Min.Y; gridY[2] = ContentRect.GetSize().Y - (TextureSize.Y - GridRect.Max.Y); gridY[3] = ContentRect.GetSize().Y; } else { float tmp = GridRect.Min.Y / (TextureSize.Y - GridRect.Max.Y); tmp = ContentRect.GetSize().Y * tmp / (1 + tmp); gridY[1] = tmp; gridY[2] = tmp; gridY[3] = ContentRect.GetSize().Y; } if (TileGridIndice == 0) { for (int32 cy = 0; cy < 4; cy++) { for (int32 cx = 0; cx < 4; cx++) Helper.AddVertex(FVector2D(gridX[cx] / TextureScale.X, gridY[cy] / TextureScale.Y), Helper.VertexColor, FVector2D(gridTexX[cx], gridTexY[cy])); } Helper.AddTriangles(TRIANGLES_9_GRID, sizeof(TRIANGLES_9_GRID) / sizeof(SlateIndex)); } else { FBox2D drawRect; FBox2D texRect; int32 row, col; int32 part; for (int32 pii = 0; pii < 9; pii++) { col = pii % 3; row = pii / 3; part = gridTileIndice[pii]; drawRect = FBox2D(FVector2D(gridX[col], gridY[row]), FVector2D(gridX[col + 1], gridY[row + 1])); texRect = FBox2D(FVector2D(gridTexX[col], gridTexY[row]), FVector2D(gridTexX[col + 1], gridTexY[row + 1])); if (part != -1 && (TileGridIndice & (1 << part)) != 0) { TileFill(Helper, drawRect, texRect, (part == 0 || part == 1 || part == 4) ? GridRect.GetSize() : drawRect.GetSize()); } else { drawRect.Min /= TextureScale; drawRect.Max = drawRect.Min + drawRect.GetSize() * TextureScale; Helper.AddQuad(drawRect, Helper.VertexColor, texRect); } } Helper.AddTriangles(); } } void SFImage::TileFill(FVertexHelper& Helper, const FBox2D& ContentRect, const FBox2D& UVRect, const FVector2D& TextureSize) { FVector2D cnt = ContentRect.GetSize() / TextureSize; cnt.Set(FMath::CeilToInt(cnt.X), FMath::CeilToInt(cnt.Y)); FVector2D tailSize = ContentRect.GetSize() - (cnt - FVector2D(1, 1)) * TextureSize; for (int32 i = 0; i < cnt.X; i++) { for (int32 j = 0; j < cnt.Y; j++) { FBox2D UVTmp = UVRect; if (i == cnt.X - 1) UVTmp.Max.X = FMath::Lerp(UVRect.Min.X, UVRect.Max.X, tailSize.X / TextureSize.X); if (j == cnt.Y - 1) UVTmp.Max.Y = FMath::Lerp(UVRect.Min.Y, UVRect.Max.Y, tailSize.Y / TextureSize.Y); FVector2D Min = ContentRect.Min + FVector2D(i, j) * TextureSize; FBox2D drawRect = FBox2D(Min, Min + FVector2D(i == (cnt.X - 1) ? tailSize.X : TextureSize.X, j == (cnt.Y - 1) ? tailSize.Y : TextureSize.Y)); drawRect.Min /= TextureScale; drawRect.Max = drawRect.Min + drawRect.GetSize() / TextureScale; Helper.AddQuad(drawRect, Helper.VertexColor, UVTmp); } } } ================================================ FILE: Source/FairyGUI/Private/Widgets/SMovieClip.cpp ================================================ #include "Widgets/SMovieClip.h" FMovieClipData::FMovieClipData() : Interval(0), RepeatDelay(0), bSwing(false) { } void FMovieClipData::AddReferencedObjects(FReferenceCollector& Collector) { for (auto& Frame : Frames) { if (Frame.Texture != nullptr) Collector.AddReferencedObject(Frame.Texture); } } SMovieClip::SMovieClip() : Frame(0), bPlaying(true), TimeScale(1), Start(0), End(0), Times(0), EndAt(0), Status(0), FrameElapsed(0), bReversed(false), RepeatedCount(0) { } void SMovieClip::Construct(const FArguments& InArgs) { SDisplayObject::Construct(SDisplayObject::FArguments().GObject(InArgs._GObject)); } void SMovieClip::SetClipData(TSharedPtr InData) { Data = InData; SetScale9Grid(TOptional()); SetScaleByTile(false); if (!Data.IsValid()) { SetCanTick(false); Graphics.SetTexture(nullptr); return; } SetCanTick(bPlaying); int32 frameCount = Data->Frames.Num(); if (End == -1 || End > frameCount - 1) End = frameCount - 1; if (EndAt == -1 || EndAt > frameCount - 1) EndAt = frameCount - 1; if (Frame < 0 || Frame > frameCount - 1) Frame = frameCount - 1; FrameElapsed = 0; RepeatedCount = 0; bReversed = false; DrawFrame(); } void SMovieClip::SetPlaying(bool InPlaying) { bPlaying = InPlaying; SetCanTick(bPlaying && Data.IsValid()); } void SMovieClip::SetTimeScale(float InTimeScale) { TimeScale = InTimeScale; } void SMovieClip::SetFrame(int32 InFrame) { if (!Data.IsValid()) { Frame = InFrame; return; } int32 frameCount = Data->Frames.Num(); if (InFrame >= frameCount) InFrame = frameCount - 1; Frame = InFrame; FrameElapsed = 0; DrawFrame(); } void SMovieClip::Advance(float Time) { if (!Data.IsValid()) return; int32 frameCount = Data->Frames.Num(); if (frameCount == 0) return; int32 beginFrame = Frame; bool beginReversed = bReversed; float backupTime = Time; while (true) { float tt = Data->Interval + Data->Frames[Frame].AddDelay; if (Frame == 0 && RepeatedCount > 0) tt += Data->RepeatDelay; if (Time < tt) { FrameElapsed = 0; break; } Time -= tt; if (Data->bSwing) { if (bReversed) { Frame--; if (Frame <= 0) { Frame = 0; RepeatedCount++; bReversed = !bReversed; } } else { Frame++; if (Frame > frameCount - 1) { Frame = FMath::Max(0, frameCount - 2); RepeatedCount++; bReversed = !bReversed; } } } else { Frame++; if (Frame > frameCount - 1) { Frame = 0; RepeatedCount++; } } if (Frame == beginFrame && bReversed == beginReversed) { float roundTime = backupTime - Time; Time -= FMath::FloorToInt(Time / roundTime) * roundTime; } } } void SMovieClip::SetPlaySettings(int32 InStart, int32 InEnd, int32 InTimes, int32 InEndAt, const FSimpleDelegate& InCompleteCallback) { int32 frameCount = Data.IsValid() ? Data->Frames.Num() : 0; Start = InStart; End = InEnd; if (End == -1 || End > frameCount - 1) End = frameCount - 1; Times = InTimes; EndAt = InEndAt; if (EndAt == -1) EndAt = End; Status = 0; CompleteCallback = InCompleteCallback; SetFrame(InStart); } void SMovieClip::DrawFrame() { if (Data.IsValid() && Frame < Data->Frames.Num()) Graphics.SetTexture(Data->Frames[Frame].Texture); } void SMovieClip::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) { SFImage::Tick(AllottedGeometry, InCurrentTime, InDeltaTime); if (!Data.IsValid() || !bPlaying) return; int32 frameCount = Data->Frames.Num(); if (frameCount == 0 || Status == 3) return; float dt = InDeltaTime; if (TimeScale != 1) dt *= TimeScale; FrameElapsed += dt; float tt = Data->Interval + Data->Frames[Frame].AddDelay; if (Frame == 0 && RepeatedCount > 0) tt += Data->RepeatDelay; if (FrameElapsed < tt) return; FrameElapsed -= tt; if (FrameElapsed > Data->Interval) FrameElapsed = Data->Interval; if (Data->bSwing) { if (bReversed) { Frame--; if (Frame <= 0) { Frame = 0; RepeatedCount++; bReversed = !bReversed; } } else { Frame++; if (Frame > frameCount - 1) { Frame = FMath::Max(0, frameCount - 2); RepeatedCount++; bReversed = !bReversed; } } } else { Frame++; if (Frame > frameCount - 1) { Frame = 0; RepeatedCount++; } } if (Status == 1) //new loop { Frame = Start; FrameElapsed = 0; Status = 0; } else if (Status == 2) //ending { Frame = EndAt; FrameElapsed = 0; Status = 3; //ended CompleteCallback.Execute(); } else { if (Frame == End) { if (Times > 0) { Times--; if (Times == 0) Status = 2; //ending else Status = 1; //new loop } else if (Start != 0) Status = 1; //new loop } } DrawFrame(); } ================================================ FILE: Source/FairyGUI/Private/Widgets/SShape.cpp ================================================ #include "Widgets/SShape.h" #include "Widgets/NTexture.h" #include "Widgets/Mesh/VertexHelper.h" SShape::SShape() { } void SShape::Construct(const FArguments& InArgs) { SDisplayObject::Construct(SDisplayObject::FArguments().GObject(InArgs._GObject)); Graphics.SetTexture(UNTexture::GetWhiteTexture()); } int32 SShape::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const { const bool bIsEnabled = ShouldBeEnabled(bParentEnabled); const_cast(this)->Graphics.Paint(AllottedGeometry, OutDrawElements, LayerId, InWidgetStyle.GetColorAndOpacityTint().A, bIsEnabled); return LayerId; } ================================================ FILE: Source/FairyGUI/Private/Widgets/STextField.cpp ================================================ #include "Widgets/STextField.h" #include "Internationalization/BreakIterator.h" #include "Utils/HTMLParser.h" #include "Widgets/LoaderRun.h" #include "Widgets/BitmapFontRun.h" #include "UI/GObject.h" #include "UI/UIPackage.h" STextField::STextField() : bHTML(false), AutoSize(EAutoSizeType::None), bSingleLine(false), MaxWidth(0), TextLayout(FSlateTextLayout::Create(this, FTextBlockStyle::GetDefault())) { TextLayout->SetLineBreakIterator(FBreakIterator::CreateCharacterBoundaryIterator()); } void STextField::Construct(const FArguments& InArgs) { SDisplayObject::Construct(SDisplayObject::FArguments().GObject(InArgs._GObject)); } void STextField::SetText(const FString& InText, bool bInHTML) { const int32 OldLength = Text.Len(); // Only compare reasonably sized strings, it's not worth checking this // for large blocks of text. if (bHTML == bInHTML && OldLength <= 20) { if (InText.Compare(Text, ESearchCase::CaseSensitive) == 0) { return; } } Text = InText; bHTML = bInHTML; TextLayout->DirtyLayout(); Invalidate(EInvalidateWidget::LayoutAndVolatility); } void STextField::SetAutoSize(EAutoSizeType InAutoSize) { if (AutoSize != InAutoSize) { AutoSize = InAutoSize; if (AutoSize == EAutoSizeType::Both) { TextLayout->SetWrappingWidth(0); } else { TextLayout->SetWrappingWidth(Size.X); } } } void STextField::SetSingleLine(bool bInSingleLine) { if (bSingleLine != bInSingleLine) { bSingleLine = bInSingleLine; TextLayout->DirtyLayout(); } } void STextField::SetMaxWidth(float InMaxWidth) { if (MaxWidth != InMaxWidth) { MaxWidth = InMaxWidth; TextLayout->DirtyLayout(); } } FVector2D STextField::GetTextSize() { if(TextLayout->IsLayoutDirty()) UpdateTextLayout(); return TextLayout->GetSize(); } void STextField::SetTextFormat(const FNTextFormat& InFormat) { if (&InFormat != &TextFormat) TextFormat = InFormat; TextLayout->DirtyLayout(); } FVector2D STextField::ComputeDesiredSize(float LayoutScaleMultiplier) const { TextLayout->SetScale(LayoutScaleMultiplier); if (TextLayout->IsLayoutDirty()) const_cast(this)->UpdateTextLayout(); return Size; } FChildren* STextField::GetChildren() { return TextLayout->GetChildren(); } void STextField::OnArrangeChildren(const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const { TextLayout->ArrangeChildren(AllottedGeometry, ArrangedChildren); } int32 STextField::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const { FVector2D AutoScrollValue = FVector2D::ZeroVector; // Scroll to the left if (TextFormat.Align != EAlignType::Left) { const float ActualWidth = TextLayout->GetSize().X; const float VisibleWidth = Size.X; if (VisibleWidth < ActualWidth) { switch (TextFormat.Align) { case EAlignType::Center: AutoScrollValue.X = (ActualWidth - VisibleWidth) * 0.5f; // Scroll to the center break; case EAlignType::Right: AutoScrollValue.X = (ActualWidth - VisibleWidth); // Scroll to the right break; default: break; } } } if (TextFormat.VerticalAlign != EVerticalAlignType::Top) { const float ActualHeight = TextLayout->GetSize().Y; const float VisibleHeight = Size.Y; switch (TextFormat.VerticalAlign) { case EVerticalAlignType::Middle: AutoScrollValue.Y = FMath::CeilToFloat((ActualHeight - VisibleHeight) * .5f); break; case EVerticalAlignType::Bottom: AutoScrollValue.Y = FMath::CeilToFloat(ActualHeight - VisibleHeight); break; } if (AutoScrollValue.Y > 0) AutoScrollValue.Y = 0; } TextLayout->SetVisibleRegion(Size, AutoScrollValue * TextLayout->GetScale()); TextLayout->UpdateIfNeeded(); LayerId = TextLayout->OnPaint(Args, AllottedGeometry, MyCullingRect, OutDrawElements, LayerId, InWidgetStyle, ShouldBeEnabled(bParentEnabled)); return LayerId; } void STextField::UpdateTextLayout() { TextLayout->ClearLines(); TextLayout->ClearLineHighlights(); TextLayout->ClearRunRenderers(); TextLayout->SetDefaultTextStyle(TextFormat.GetStyle()); TextLayout->SetJustification((ETextJustify::Type)TextFormat.Align); TextLayout->SetWrappingPolicy(ETextWrappingPolicy::AllowPerCharacterWrapping); if (AutoSize == EAutoSizeType::Both) TextLayout->SetWrappingWidth(MaxWidth); else TextLayout->SetWrappingWidth(MaxWidth != 0 ? FMath::Min(MaxWidth, Size.X) : Size.X); TextLayout->SetMargin(FMargin(2, 2)); TextLayout->SetLineHeightPercentage(1 + (TextFormat.LineSpacing - 3) / TextFormat.Size); HTMLElements.Reset(); if (bHTML) { FHTMLParser::DefaultParser.Parse(Text, TextFormat, HTMLElements, FHTMLParser::DefaultParseOptions); } else { FHTMLElement TextElement; TextElement.Type = EHTMLElementType::Text; TextElement.Format = TextFormat; TextElement.Text = Text; HTMLElements.Add(MoveTemp(TextElement)); } BuildLines(); TextLayout->UpdateIfNeeded(); if (AutoSize == EAutoSizeType::Both) { GObject->SetSize(TextLayout->GetSize()); } else if (AutoSize == EAutoSizeType::Height) { GObject->SetSize(FVector2D(Size.X, TextLayout->GetSize().Y)); } } void STextField::BuildLines() { class FLineHelper { public: TArray Lines; FTextLayout::FNewLineData* LastLineData; bool bNewLine; FLineHelper() { NewLine(); } TSharedRef& GetTextRef() { if (bNewLine) NewLine(); return LastLineData->Text; } FString& GetText() { if (bNewLine) NewLine(); return LastLineData->Text.Get(); } TArray>& GetRuns() { if (bNewLine) NewLine(); return LastLineData->Runs; } private: void NewLine() { Lines.Emplace(MakeShareable(new FString()), TArray>()); LastLineData = &Lines.Last(); bNewLine = false; } } LineHelper; TSharedPtr BitmapFont; if (TextFormat.Face.StartsWith("ui://")) { TSharedPtr FontItem = UUIPackage::GetItemByURL(TextFormat.Face); if (FontItem.IsValid()) { FontItem->Load(); BitmapFont = FontItem->BitmapFont; } } TArray LineRangesBuffer; for (int32 ElementIndex = 0; ElementIndex < HTMLElements.Num(); ++ElementIndex) { const FHTMLElement& Element = HTMLElements[ElementIndex]; if (Element.Type == EHTMLElementType::Text) { LineRangesBuffer.Reset(); FTextBlockStyle TextStyle = Element.Format.GetStyle(); FTextRange::CalculateLineRangesFromString(Element.Text, LineRangesBuffer); for (int32 LineIndex = 0; LineIndex < LineRangesBuffer.Num(); ++LineIndex) { const FTextRange& LineRange = LineRangesBuffer[LineIndex]; FString TextBlock = Element.Text.Mid(LineRange.BeginIndex, LineRange.Len()); if (BitmapFont.IsValid()) { int32 len = TextBlock.Len(); for (int32 CharIndex = 0; CharIndex < len; CharIndex++) { FTextRange ModelRange; ModelRange.BeginIndex = LineHelper.GetText().Len(); LineHelper.GetText().AppendChar(TextBlock[CharIndex]); ModelRange.EndIndex = LineHelper.GetText().Len(); LineHelper.GetRuns().Add(FBitmapFontRun::Create(LineHelper.GetTextRef(), BitmapFont.ToSharedRef(), ModelRange)); } } else { FTextRange ModelRange; ModelRange.BeginIndex = LineHelper.GetText().Len(); LineHelper.GetText().Append(TextBlock); ModelRange.EndIndex = LineHelper.GetText().Len(); LineHelper.GetRuns().Add(FSlateTextRun::Create(FRunInfo(), LineHelper.GetTextRef(), TextStyle, ModelRange)); } if (LineIndex != LineRangesBuffer.Num() - 1) LineHelper.bNewLine = true; } } else if (Element.Type == EHTMLElementType::Image) { FTextRange ModelRange; ModelRange.BeginIndex = LineHelper.GetText().Len(); LineHelper.GetText().Append(TEXT("\x200B")); // Zero-Width Breaking Space ModelRange.EndIndex = LineHelper.GetText().Len(); LineHelper.GetRuns().Add(FLoaderRun::Create(GObject->GetApp(), Element, LineHelper.GetTextRef(), ModelRange)); } } TextLayout->AddLines(LineHelper.Lines); } ================================================ FILE: Source/FairyGUI/Private/Widgets/STextInput.cpp ================================================ #include "Widgets/STextInput.h" #include "Widgets/Text/SlateEditableTextLayout.h" class SMyTextInput : public SMultiLineEditableText { public: SMyTextInput() :bPassword(false) { } void SetTextFormat(const FNTextFormat& InTextFormat) { EditableTextLayout->SetTextStyle(InTextFormat.GetStyle()); EditableTextLayout->SetJustification((ETextJustify::Type)InTextFormat.Align); } void SetOnTextChanged(FOnTextChanged Callback) { OnTextChangedCallback = Callback; } void SetOnTextCommitted(FOnTextCommitted Callback) { OnTextCommittedCallback = Callback; } void SetAllowMultiLine(bool bInAllowMultiLine) { bAllowMultiLine = bInAllowMultiLine; } virtual bool IsTextPassword() const override { return bPassword; } bool bPassword; }; STextInput::STextInput() : Widget(SNew(SMyTextInput)), ChildSlot(this) { } void STextInput::Construct(const FArguments& InArgs) { SDisplayObject::Construct(SDisplayObject::FArguments().GObject(InArgs._GObject)); ChildSlot.AttachWidget(Widget); } void STextInput::SetTextFormat(const FNTextFormat& InTextFormat) { StaticCastSharedRef(Widget)->SetTextFormat(InTextFormat); } void STextInput::SetPassword(bool bInPassword) { StaticCastSharedRef(Widget)->bPassword = bInPassword; } void STextInput::SetSingleLine(bool bInSingleLine) { StaticCastSharedRef(Widget)->SetAllowMultiLine(!bInSingleLine); } void STextInput::SetOnTextChanged(FOnTextChanged Callback) { StaticCastSharedRef(Widget)->SetOnTextChanged(Callback); } void STextInput::SetOnTextCommitted(FOnTextCommitted Callback) { StaticCastSharedRef(Widget)->SetOnTextCommitted(Callback); } FChildren* STextInput::GetChildren() { return &ChildSlot; } void STextInput::OnArrangeChildren(const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const { if (ArrangedChildren.Accepts(Widget->GetVisibility())) ArrangedChildren.AddWidget(AllottedGeometry.MakeChild( Widget, FVector2D::ZeroVector, Size )); } int32 STextInput::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const { FArrangedChildren ArrangedChildren(EVisibility::Visible); ArrangeChildren(AllottedGeometry, ArrangedChildren); FArrangedWidget& TheChild = ArrangedChildren[0]; return TheChild.Widget->Paint(Args.WithNewParent(this), TheChild.Geometry, MyCullingRect, OutDrawElements, LayerId, InWidgetStyle, ShouldBeEnabled(bParentEnabled)); } ================================================ FILE: Source/FairyGUI/Public/Event/EventContext.h ================================================ #pragma once #include "CoreMinimal.h" #include "UObject/NoExportTypes.h" #include "Input/Events.h" #include "EventTypes.h" #include "Utils/NVariant.h" #include "EventContext.generated.h" class UGObject; class SDisplayObject; UCLASS(BlueprintType) class FAIRYGUI_API UEventContext : public UObject { GENERATED_BODY() public: UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGObject* GetSender() const { return Sender; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGObject* GetInitiator() const { return Initiator; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") const FName& GetType() const { return Type; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") const FVector2D& GetPointerPosition() const { return PointerEvent->GetScreenSpacePosition(); } UFUNCTION(BlueprintCallable, Category = "FairyGUI") int32 GetPointerIndex() const { return (int32)PointerEvent->GetPointerIndex(); } UFUNCTION(BlueprintCallable, Category = "FairyGUI") int32 GetUserIndex() const { return PointerEvent->GetUserIndex(); } UFUNCTION(BlueprintCallable, Category = "FairyGUI") float GetWheelDelta() const { return PointerEvent->GetWheelDelta(); } UFUNCTION(BlueprintCallable, Category = "FairyGUI") FKey GetMouseButton() const { if (PointerEvent->IsTouchEvent()) return EKeys::LeftMouseButton; else return PointerEvent->GetEffectingButton(); } UFUNCTION(BlueprintCallable, Category = "FairyGUI") FPointerEvent& GetPointerEvent() const { return *PointerEvent; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") FKeyEvent& GetKeyEvent() const { return *KeyEvent; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") int32 GetClickCount() const { return ClickCount; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool IsDoubleClick() const { return ClickCount == 2; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") const FNVariant& GetData() const { return Data; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void StopPropagation() { bStopped = true; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool IsPropagationStopped() const { return bStopped; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void PreventDefault() { bDefaultPrevented = true; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool IsDefaultPrevented() const { return bDefaultPrevented; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void CaptureTouch() { bIsMouseCaptor = true; } private: UGObject* Sender; UGObject* Initiator; FName Type; bool bStopped; bool bDefaultPrevented; bool bIsMouseCaptor; FPointerEvent* PointerEvent; FKeyEvent* KeyEvent; int32 ClickCount; FNVariant Data; friend class UFairyApplication; }; DECLARE_DELEGATE_OneParam(FGUIEventDelegate, UEventContext*); DECLARE_MULTICAST_DELEGATE_OneParam(FGUIEventMDelegate, UEventContext*); DECLARE_DYNAMIC_DELEGATE_OneParam(FGUIEventDynDelegate, UEventContext*, EventContext); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FGUIEventDynMDelegate, UEventContext*, EventContext); DECLARE_DYNAMIC_DELEGATE(FSimpleDynDelegate); ================================================ FILE: Source/FairyGUI/Public/Event/EventTypes.h ================================================ #pragma once #include "CoreMinimal.h" #include "UObject/NoExportTypes.h" struct FAIRYGUI_API FUIEvents { static const FName Click; static const FName TouchBegin; static const FName TouchMove; static const FName TouchEnd; static const FName RollOver; static const FName RollOut; static const FName MouseWheel; static const FName DragStart; static const FName DragMove; static const FName DragEnd; static const FName Drop; static const FName AddedToStage; static const FName RemovedFromStage; static const FName Changed; static const FName ClickItem; static const FName ClickLink; static const FName GearStop; static const FName Scroll; static const FName ScrollEnd; static const FName PullDownRelease; static const FName PullUpRelease; static const FName Submit; }; ================================================ FILE: Source/FairyGUI/Public/FairyApplication.h ================================================ #pragma once #include "CoreMinimal.h" #include "UObject/NoExportTypes.h" #include "Engine/GameViewportClient.h" #include "Engine.h" #include "Framework/Application/IInputProcessor.h" #include "FairyCommons.h" #include "Event/EventContext.h" #include "Tween/TweenManager.h" #include "UI/UIConfig.h" #include "FairyApplication.generated.h" class UUIPackage; class UNTexture; class UGObject; class UGRoot; class UDragDropManager; UCLASS(BlueprintType) class FAIRYGUI_API UFairyApplication : public UObject { GENERATED_BODY() private: struct FTouchInfo { int32 UserIndex; int32 PointerIndex; bool bDown; bool bToClearCaptors; FVector2D DownPosition; bool bClickCancelled; int32 ClickCount; TArray> DownPath; TArray> MouseCaptors; FPointerEvent Event; FTouchInfo(); }; class FInputProcessor : public IInputProcessor { public: FInputProcessor(UFairyApplication* InApplication); virtual void Tick(const float DeltaTime, FSlateApplication& SlateApp, TSharedRef Cursor) override; virtual bool HandleMouseButtonDownEvent(FSlateApplication& SlateApp, const FPointerEvent& MouseEvent) override; virtual bool HandleMouseButtonUpEvent(FSlateApplication& SlateApp, const FPointerEvent& MouseEvent) override; virtual bool HandleMouseMoveEvent(FSlateApplication& SlateApp, const FPointerEvent& MouseEvent) override; UFairyApplication* Application; }; public: UFUNCTION(BlueprintPure, Category = "FairyGUI", meta = (DisplayName = "Get Application", WorldContext = "WorldContextObject")) static UFairyApplication* Get(UObject* WorldContextObject); static void Destroy(); UFairyApplication(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGRoot* GetUIRoot() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") UDragDropManager* GetDragDropManager() const { return DragDropManager; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") FVector2D GetTouchPosition(int32 InUserIndex = -1, int32 InPointerIndex = -1); UFUNCTION(BlueprintCallable, Category = "FairyGUI") int32 GetTouchCount() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGObject* GetObjectUnderPoint(const FVector2D& ScreenspacePosition); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void CancelClick(int32 InUserIndex = -1, int32 InPointerIndex = -1); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void PlaySound(const FString& URL, float VolumeScale = 1); UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool IsSoundEnabled() const { return bSoundEnabled; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetSoundEnabled(bool InEnabled); UFUNCTION(BlueprintCallable, Category = "FairyGUI") float GetSoundVolumeScale() const { return SoundVolumeScale; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetSoundVolumeScale(float InVolumeScale); public: virtual UWorld* GetWorld() const override { return GameInstance->GetWorld(); } bool DispatchEvent(const FName& EventType, const TSharedRef& Initiator, const FNVariant& Data = FNVariant::Null); void BubbleEvent(const FName& EventType, const TSharedRef& Initiator, const FNVariant& Data = FNVariant::Null); void BroadcastEvent(const FName& EventType, const TSharedRef& Initiator, const FNVariant& Data = FNVariant::Null); void AddMouseCaptor(int32 InUserIndex, int32 InPointerIndex, UGObject* InTarget); void RemoveMouseCaptor(int32 InUserIndex, int32 InPointerIndex, UGObject* InTarget); bool HasMouseCaptor(int32 InUserIndex, int32 InPointerIndex); FReply OnWidgetMouseButtonDown(const TSharedRef& Widget, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent); FReply OnWidgetMouseButtonUp(const TSharedRef& Widget, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent); FReply OnWidgetMouseMove(const TSharedRef& Widget, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent); FReply OnWidgetMouseButtonDoubleClick(const TSharedRef& Widget, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent); void OnWidgetMouseEnter(const TSharedRef& Widget, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent); void OnWidgetMouseLeave(const TSharedRef& Widget, const FPointerEvent& MouseEvent); FReply OnWidgetMouseWheel(const TSharedRef& Widget, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent); UGameViewportClient* GetViewportClient() const { return ViewportClient; } const TSharedPtr& GetViewportWidget() const { return ViewportWidget; } void CallAfterSlateTick(FSimpleDelegate Callback); template< class UserClass, typename... VarTypes > void DelayCall(FTimerHandle& InOutHandle, UserClass* InUserObject, typename TMemFunPtrType::Type inTimerMethod, VarTypes...); void CancelDelayCall(FTimerHandle& InHandle); private: void OnCreate(); void OnDestroy(); void PreviewDownEvent(const FPointerEvent& MouseEvent); void PreviewUpEvent(const FPointerEvent& MouseEvent); void PreviewMoveEvent(const FPointerEvent& MouseEvent); UEventContext* BorrowEventContext(); void ReturnEventContext(UEventContext* Context); void InternalBubbleEvent(const FName& EventType, const TArray& CallChain, const FNVariant& Data); FTouchInfo* GetTouchInfo(const FPointerEvent& MouseEvent); FTouchInfo* GetTouchInfo(int32 InUserIndex, int32 InPointerIndex); void OnSlatePostTick(float DeltaTime); private: UPROPERTY(Transient) UGRoot* UIRoot; UPROPERTY(Transient) UDragDropManager* DragDropManager; UPROPERTY(Transient) TArray EventContextPool; TSharedPtr InputProcessor; UGameViewportClient* ViewportClient; TSharedPtr ViewportWidget; TIndirectArray Touches; FTouchInfo* LastTouch; bool bNeedCheckPopups; FDelegateHandle PostTickDelegateHandle; FSimpleMulticastDelegate PostTickMulticastDelegate; bool bSoundEnabled; float SoundVolumeScale; UGameInstance* GameInstance; static TMap Instances; }; template< class UserClass, typename... VarTypes > void UFairyApplication::DelayCall(FTimerHandle& InOutHandle, UserClass* InUserObject, typename TMemFunPtrType::Type inTimerMethod, VarTypes... Vars) { if (!GameInstance->GetWorld()->GetTimerManager().TimerExists(InOutHandle)) InOutHandle = GameInstance->GetWorld()->GetWorld()->GetTimerManager().SetTimerForNextTick(FTimerDelegate::CreateUObject(InUserObject, inTimerMethod, Vars...)); } inline void UFairyApplication::CancelDelayCall(FTimerHandle& InHandle) { GameInstance->GetWorld()->GetTimerManager().ClearTimer(InHandle); } ================================================ FILE: Source/FairyGUI/Public/FairyBlueprintLibrary.h ================================================ #pragma once #include "CoreMinimal.h" #include "UObject/NoExportTypes.h" #include "Kismet/BlueprintFunctionLibrary.h" #include "Utils/NVariant.h" #include "Tween/TweenValue.h" #include "Tween/EaseType.h" #include "Tween/TweenerHandle.h" #include "Event/EventContext.h" #include "FairyBlueprintLibrary.generated.h" DECLARE_DYNAMIC_DELEGATE_TwoParams(FTweenUpdateDynDelegate, const FTweenValue&, Value, const FTweenValue&, DeltaValue); UCLASS() class FAIRYGUI_API UFairyBlueprintLibrary : public UBlueprintFunctionLibrary { GENERATED_BODY() public: UFUNCTION(BlueprintPure, Category = "FairyGUI") static const FUIConfig& GetUIConfig(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") static void SetUIConfig(const FUIConfig& InConfig); UFUNCTION(BlueprintPure, Category = "FairyGUI|Variant") static bool GetVariantAsBool(UPARAM(ref) FNVariant& InVariant); UFUNCTION(BlueprintPure, Category = "FairyGUI|Variant") static int32 GetVariantAsInt(UPARAM(ref) FNVariant& InVariant); UFUNCTION(BlueprintPure, Category = "FairyGUI|Variant") static float GetVariantAsFloat(UPARAM(ref) FNVariant& InVariant); UFUNCTION(BlueprintPure, Category = "FairyGUI|Variant") static FString GetVariantAsString(UPARAM(ref) FNVariant& InVariant); UFUNCTION(BlueprintPure, Category = "FairyGUI|Variant") static FColor GetVariantAsColor(UPARAM(ref) FNVariant& InVariant); UFUNCTION(BlueprintPure, Category = "FairyGUI|Variant", meta = (DeterminesOutputType = "ClassType")) static UObject* GetVariantAsUObject(UPARAM(ref) FNVariant& InVariant, TSubclassOf ClassType); UFUNCTION(BlueprintCallable, Category = "FairyGUI|Variant") static FNVariant& SetVariantBool(UPARAM(ref) FNVariant& InVariant, bool bInValue); UFUNCTION(BlueprintCallable, Category = "FairyGUI|Variant") static FNVariant& SetVariantInt(UPARAM(ref) FNVariant& InVariant, int32 InValue); UFUNCTION(BlueprintCallable, Category = "FairyGUI|Variant") static FNVariant& SetVariantFloat(UPARAM(ref) FNVariant& InVariant, float InValue); UFUNCTION(BlueprintCallable, Category = "FairyGUI|Variant") static FNVariant& SetVariantString(UPARAM(ref) FNVariant& InVariant, const FString& InValue); UFUNCTION(BlueprintCallable, Category = "FairyGUI|Variant") static FNVariant& SetVariantColor(UPARAM(ref) FNVariant& InVariant, const FColor& InValue); UFUNCTION(BlueprintCallable, Category = "FairyGUI|Variant") static FNVariant& SetVariantUObject(UPARAM(ref) FNVariant& InVariant, UObject* InValue); UFUNCTION(BlueprintCallable, Category = "FairyGUI|Tween", meta = (AutoCreateRefTerm = "OnUpdate,OnComplete")) static FTweenerHandle TweenFloat(float StartValue, float EndValue, EEaseType EaseType, float Duration, int32 Repeat, const FTweenUpdateDynDelegate& OnUpdate, const FSimpleDynDelegate& OnComplete); UFUNCTION(BlueprintCallable, Category = "FairyGUI|Tween", meta = (AutoCreateRefTerm = "OnUpdate,OnComplete")) static FTweenerHandle TweenVector2(const FVector2D& StartValue, const FVector2D& EndValue, EEaseType EaseType, float Duration, int32 Repeat, const FTweenUpdateDynDelegate& OnUpdate, const FSimpleDynDelegate& OnComplete); UFUNCTION(BlueprintCallable, Category = "FairyGUI|Tween") static void KillTween(UPARAM(ref) FTweenerHandle& Handle, bool bSetComplete = false); UFUNCTION(BlueprintCallable, Category = "FairyGUI") static void SetPackageItemExtension(const FString& URL, TSubclassOf ClassType); }; ================================================ FILE: Source/FairyGUI/Public/FairyCommons.h ================================================ #pragma once #include "CoreMinimal.h" FAIRYGUI_API DECLARE_LOG_CATEGORY_EXTERN(LogFairyGUI, Log, All) extern const FString FAIRYGUI_API G_EMPTY_STRING; DECLARE_DELEGATE_RetVal_OneParam(class UGComponent*, FGComponentCreator, UObject*); ================================================ FILE: Source/FairyGUI/Public/FairyGUI.h ================================================ #pragma once #include "UI/UIObjectFactory.h" #include "UI/UIPackage.h" #include "UI/PackageItem.h" #include "UI/GComponent.h" #include "UI/GImage.h" #include "UI/GMovieClip.h" #include "UI/GTextField.h" #include "UI/GRichTextField.h" #include "UI/GTextInput.h" #include "UI/GGraph.h" #include "UI/GLoader.h" #include "UI/GLoader3D.h" #include "UI/GGroup.h" #include "UI/GLabel.h" #include "UI/GButton.h" #include "UI/GComboBox.h" #include "UI/GProgressBar.h" #include "UI/GSlider.h" #include "UI/GScrollBar.h" #include "UI/GList.h" #include "UI/GTree.h" #include "UI/PopupMenu.h" #include "UI/GWindow.h" #include "UI/GRoot.h" #include "UI/GController.h" #include "UI/Transition.h" #include "UI/ScrollPane.h" #include "UI/TranslationHelper.h" #include "Tween/GTween.h" #include "Utils/NVariant.h" #include "Utils/ByteBuffer.h" #include "Widgets/NTexture.h" #include "Widgets/Mesh/EllipseMesh.h" #include "Widgets/Mesh/PolygonMesh.h" #include "Widgets/Mesh/RectMesh.h" #include "Widgets/Mesh/RegularPolygonMesh.h" #include "Widgets/Mesh/RoundedRectMesh.h" #include "UIPackageAsset.h" #include "FairyApplication.h" ================================================ FILE: Source/FairyGUI/Public/FairyGUIModule.h ================================================ // Copyright 1998-2019 Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "Modules/ModuleManager.h" class FFairyGUIModule : public IModuleInterface { public: /** IModuleInterface implementation */ virtual void StartupModule() override; virtual void ShutdownModule() override; FDelegateHandle EndPieDelegateHandle; }; ================================================ FILE: Source/FairyGUI/Public/Tween/EaseManager.h ================================================ #pragma once #include "CoreMinimal.h" #include "EaseType.h" class FAIRYGUI_API EaseManager { public: static float Evaluate(EEaseType EaseType, float Time, float Duration, float OvershootOrAmplitude, float Period); }; ================================================ FILE: Source/FairyGUI/Public/Tween/EaseType.h ================================================ #pragma once #include "EaseType.generated.h" UENUM() enum class EEaseType : uint8 { Linear, SineIn, SineOut, SineInOut, QuadIn, QuadOut, QuadInOut, CubicIn, CubicOut, CubicInOut, QuartIn, QuartOut, QuartInOut, QuintIn, QuintOut, QuintInOut, ExpoIn, ExpoOut, ExpoInOut, CircIn, CircOut, CircInOut, ElasticIn, ElasticOut, ElasticInOut, BackIn, BackOut, BackInOut, BounceIn, BounceOut, BounceInOut, Custom }; ================================================ FILE: Source/FairyGUI/Public/Tween/GPath.h ================================================ #pragma once #include "CoreMinimal.h" struct FAIRYGUI_API FGPathPoint { enum class ECurveType { CRSpline, Bezier, CubicBezier, Straight }; FVector Pos; FVector Control1; FVector Control2; ECurveType CurveType; FGPathPoint(const FVector& InPos); FGPathPoint(const FVector& InPos, const FVector& InControl); FGPathPoint(const FVector& InPos, const FVector& InControl1, const FVector& InControl2); FGPathPoint(const FVector& InPos, ECurveType InCurveType); }; class FAIRYGUI_API FGPath { public: FGPath(); void Create(const FGPathPoint* InPoints, int32 Count); void Clear(); FVector GetPointAt(float Time); float GetLength() { return FullLength; } int32 GetSegmentCount() { return Segments.Num(); } float GetSegmentLength(int32 SegmentIndex); void GetPointsInSegment(int32 SegmentIndex, float t0, float t1, TArray& OutPoints, TArray* OutTimeArray = nullptr, float PointDensity = 0.1f); void GetAllPoints(TArray& OutPoints, float PointDensity = 0.1f); struct FSegment { FGPathPoint::ECurveType Type; float Length; int32 PointStart; int32 PointCount; }; private: void CreateSplineSegment(TArray& InOutSplinePoints); FVector OnCRSplineCurve(int32 PointStart, int32 PointCount, float Time); FVector OnBezierCurve(int32 PointStart, int32 PointCount, float Time); TArray Segments; TArray Points; float FullLength; }; ================================================ FILE: Source/FairyGUI/Public/Tween/GTween.h ================================================ #pragma once #include "CoreMinimal.h" #include "GTweener.h" #include "EaseType.h" #include "TweenValue.h" class FAIRYGUI_API FGTween { public: static FGTweener* To(float StartValue, float EndValue, float Duration); static FGTweener* To(const FVector2D& StartValue, const FVector2D& EndValue, float Duration); static FGTweener* To(const FVector& StartValue, const FVector& EndValue, float Duration); static FGTweener* To(const FVector4& StartValue, const FVector4& EndValue, float Duration); static FGTweener* To(const FColor& StartValue, const FColor& EndValue, float Duration); static FGTweener* ToDouble(double StartValue, double EndValue, float Duration); static FGTweener* DelayedCall(float Delay); static FGTweener* Shake(const FVector2D& StartValue, float Amplitude, float Duration); static bool IsTweening(const FTweenerHandle& Handle); static bool IsTweening(UObject* Target); static FGTweener* GetTween(const FTweenerHandle& Handle); static FGTweener* GetTween(UObject* Target); static void Kill(FTweenerHandle& Handle, bool bSetComplete = false); static void Kill(UObject* Target, bool bSetComplete = false); }; class FAIRYGUI_API FGTweenAction { public: static void MoveX(FGTweener* Tweener); static void MoveY(FGTweener* Tweener); static void Move(FGTweener* Tweener); static void SetWidth(FGTweener* Tweener); static void SetHeight(FGTweener* Tweener); static void SetSize(FGTweener* Tweener); static void ScaleX(FGTweener* Tweener); static void ScaleY(FGTweener* Tweener); static void ScaleXY(FGTweener* Tweener); static void Rotate(FGTweener* Tweener); static void SetAlpha(FGTweener* Tweener); static void SetProgress(FGTweener* Tweener); }; ================================================ FILE: Source/FairyGUI/Public/Tween/GTweener.h ================================================ #pragma once #include "CoreMinimal.h" #include "EaseType.h" #include "TweenValue.h" #include "TweenerHandle.h" #include "Utils/NVariant.h" class FGPath; class FGTweener; DECLARE_DELEGATE_OneParam(FTweenDelegate, FGTweener*); class FAIRYGUI_API FGTweener { public: FGTweener(); ~FGTweener(); const FTweenerHandle& GetHandle() { return Handle; } FGTweener* SetDelay(float InValue); float GetDelay() const { return Delay; } FGTweener* SetDuration(float InValue); float GetDuration() const { return Duration; } FGTweener* SetBreakpoint(float InValue); FGTweener* SetEase(EEaseType InValue); FGTweener* SetEasePeriod(float InValue); FGTweener* SetEaseOvershootOrAmplitude(float InValue); FGTweener* SetRepeat(int32 InRepeat, bool bInYoyo = false); int32 GetRepeat() const { return Repeat; } FGTweener* SetTimeScale(float InValue); FGTweener* SetSnapping(bool InValue); FGTweener* SetTarget(UObject* InTarget); UObject* GetTarget() const { return Target.Get(); } const FNVariant& GetUserData() const { return UserData; } FGTweener* SetUserData(const FNVariant& InData); FGTweener* SetPath(TSharedPtr InPath); FGTweener* OnUpdate(FTweenDelegate Callback); FGTweener* OnStart(FTweenDelegate Callback); FGTweener* OnComplete(FTweenDelegate Callback); FGTweener* OnUpdate(FSimpleDelegate Callback); FGTweener* OnStart(FSimpleDelegate Callback); FGTweener* OnComplete(FSimpleDelegate Callback); float GetNormalizedTime() const { return NormalizedTime; } bool IsCompleted() const { return Ended != 0; } bool AllCompleted() const { return Ended == 1; } FGTweener* SetPaused(bool bInPaused); void Seek(float Time); void Kill(bool bSetComplete = false); FTweenValue StartValue; FTweenValue EndValue; FTweenValue Value; FTweenValue DeltaValue; private: FGTweener* To(float InStart, float InEnd, float InDuration); FGTweener* To(const FVector2D& InStart, const FVector2D& InEnd, float InDuration); FGTweener* To(const FVector& InStart, const FVector& InEnd, float InDuration); FGTweener* To(const FVector4& InStart, const FVector4& InEnd, float InDuration); FGTweener* To(const FColor& InStart, const FColor& InEnd, float InDuration); FGTweener* To(double InStart, double InEnd, float InDuration); FGTweener* Shake(const FVector2D& InStart, float InAmplitude, float InDuration); void Init(); void Reset(); void Update(float DeltaTime); void Update(); private: TWeakObjectPtr Target; bool bKilled; bool bPaused; float Delay; float Duration; float Breakpoint; EEaseType EaseType; float EaseOvershootOrAmplitude; float EasePeriod; int32 Repeat; bool bYoyo; float TimeScale; bool bSnapping; FNVariant UserData; int32 ValueSize; TSharedPtr Path; FTweenerHandle Handle; FTweenDelegate OnUpdateCallback; FTweenDelegate OnStartCallback; FTweenDelegate OnCompleteCallback; bool bStarted; int32 Ended; float ElapsedTime; float NormalizedTime; friend class FGTween; friend class FTweenManager; }; ================================================ FILE: Source/FairyGUI/Public/Tween/TweenManager.h ================================================ #pragma once #include "CoreMinimal.h" #include "Engine/Engine.h" #include "Tickable.h" #include "GTweener.h" class UGObject; class FAIRYGUI_API FTweenManager : public FTickableGameObject { public: static FTweenManager Singleton; FTweenManager(); virtual ~FTweenManager(); void Reset(); FGTweener* CreateTween(); bool IsTweening(FTweenerHandle const& Handle) { return GetTween(Handle) != nullptr; } bool IsTweening(UObject* Target) { return GetTween(Target) != nullptr; } bool KillTween(FTweenerHandle & Handle, bool bCompleted); bool KillTweens(UObject* Target, bool bCompleted); FGTweener* GetTween(FTweenerHandle const& Handle); FGTweener* GetTween(UObject* Target); void Tick(float DeltaTime); TStatId GetStatId() const { return TStatId(); } private: FGTweener** ActiveTweens; TArray TweenerPool; int32 TotalActiveTweens; int32 ArrayLength; uint32 TweenerInstanceCount; }; ================================================ FILE: Source/FairyGUI/Public/Tween/TweenValue.h ================================================ #pragma once #include "CoreMinimal.h" #include "TweenValue.generated.h" USTRUCT(BlueprintType) struct FAIRYGUI_API FTweenValue { GENERATED_USTRUCT_BODY() public: UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") float X; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") float Y; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") float Z; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") float W; double D; FTweenValue(); FVector2D GetVec2() const; void SetVec2(const FVector2D& Value); FVector GetVec3() const; void SetVec3(const FVector& Value); FVector4 GetVec4() const; void SetVec4(const FVector4& Value); FColor GetColor() const; void SetColor(const FColor& Color); float operator[] (int32 Index) const; float& operator[] (int32 Index); void Reset(); }; ================================================ FILE: Source/FairyGUI/Public/Tween/TweenerHandle.h ================================================ #pragma once #include "CoreMinimal.h" #include "TweenerHandle.generated.h" USTRUCT(BlueprintType) struct FAIRYGUI_API FTweenerHandle { GENERATED_USTRUCT_BODY() public: FTweenerHandle() : Handle(0) { } bool IsValid() const { return Handle != 0; } void Invalidate() { Handle = 0; } bool operator==(const FTweenerHandle& Other) const { return Handle == Other.Handle; } bool operator!=(const FTweenerHandle& Other) const { return Handle != Other.Handle; } FString ToString() const { return FString::Printf(TEXT("%ull"), Handle); } private: FORCEINLINE int32 GetIndex() const { return (int32)(Handle & (uint64)(MaxIndex - 1)); } FORCEINLINE uint64 GetSerialNumber() const { return Handle >> IndexBits; } static const uint32 IndexBits = 24; static const uint32 SerialNumberBits = 40; static const int32 MaxIndex = (int32)1 << IndexBits; static const uint64 MaxSerialNumber = (uint64)1 << SerialNumberBits; void SetIndex(int32 Index) { Handle = (uint64)(uint32)Index; } void IncreaseSerialNumber() { int32 Index = (int32)(Handle & (uint64)(MaxIndex - 1)); uint64 SerialNumber = Handle >> IndexBits; SerialNumber++; if (!ensureMsgf(SerialNumber != FTweenerHandle::MaxSerialNumber, TEXT("Tweener serial number has wrapped around!"))) { SerialNumber = 0; } Handle = (SerialNumber << IndexBits) | (uint64)(uint32)Index; } uint64 Handle; friend class FTweenManager; }; ================================================ FILE: Source/FairyGUI/Public/UI/ControllerAction/ChangePageAction.h ================================================ #pragma once #include "ControllerAction.h" class FChangePageAction : public FControllerAction { public: virtual void Setup(FByteBuffer * Buffer) override; FString ObjectID; FString ControllerName; FString TargetPage; protected: virtual void Enter(UGController* Controller) override; virtual void Leave(UGController* Controller) override; }; ================================================ FILE: Source/FairyGUI/Public/UI/ControllerAction/ControllerAction.h ================================================ #pragma once #include "CoreMinimal.h" class UGController; class FByteBuffer; class FControllerAction { public: static FControllerAction* CreateAction(int32 ActionType); FControllerAction(); virtual ~FControllerAction(); void Run(UGController* Controller, const FString& PreviousPage, const FString& CurrentPage); virtual void Setup(FByteBuffer * Buffer); TArray FromPage; TArray ToPage; protected: virtual void Enter(UGController* Controller) = 0; virtual void Leave(UGController* Controller) = 0; }; ================================================ FILE: Source/FairyGUI/Public/UI/ControllerAction/PlayTransitionAction.h ================================================ #pragma once #include "ControllerAction.h" class UTransition; class FPlayTransitionAction : public FControllerAction { public: FPlayTransitionAction(); virtual void Setup(FByteBuffer * Buffer) override; FString TransitionName; int32 PlayTimes; float Delay; bool bStopOnExit; protected: virtual void Enter(UGController* Controller) override; virtual void Leave(UGController* Controller) override; UTransition* CurrentTransition; }; ================================================ FILE: Source/FairyGUI/Public/UI/DragDropManager.h ================================================ #pragma once #include "CoreMinimal.h" #include "UObject/NoExportTypes.h" #include "Event/EventContext.h" #include "UI/GLoader.h" #include "DragDropManager.generated.h" UCLASS(BlueprintType) class UDragDropManager : public UObject { GENERATED_BODY() public: UDragDropManager(); virtual ~UDragDropManager(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGLoader* GetAgent() const { return Agent; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool IsDragging() const { return Agent->GetParent() != nullptr; } UFUNCTION(BlueprintCallable, Category = "FairyGUI", meta = (AutoCreateRefTerm="InSourceData")) void StartDrag(const FString& InIcon, const FNVariant& InUserData, int32 InUserIndex = -1, int32 InPointerIndex = -1); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void Cancel(); void CreateAgent(); private: void DelayStartDrag(int32 InUserIndex, int32 InPointerIndex); void OnDragEnd(UEventContext* Context); UPROPERTY(Transient) UGLoader* Agent; FNVariant UserData; }; ================================================ FILE: Source/FairyGUI/Public/UI/FieldTypes.h ================================================ #pragma once #include "CoreMinimal.h" #include "UObject/NoExportTypes.h" #include "FieldTypes.generated.h" UENUM() enum class EPackageItemType { Image, MovieClip, Sound, Component, Atlas, Font, Swf, Misc, Unknown, Spine, DragonBones }; UENUM() enum class EObjectType { Image, MovieClip, Swf, Graph, Loader, Group, Text, RichText, InputText, Component, List, Label, Button, ComboBox, ProgressBar, Slider, ScrollBar, Tree, Loader3D }; UENUM() enum class EButtonMode : uint8 { Common, Check, Radio }; UENUM() enum class EChildrenRenderOrder : uint8 { Ascent, Descent, Arch, }; UENUM() enum class EOverflowType : uint8 { Visible, Hidden, Scroll }; UENUM() enum class EScrollType : uint8 { Horizontal, Vertical, Both }; UENUM() enum class EScrollBarDisplayType : uint8 { Default, Visible, Auto, Hidden }; UENUM() enum class ELoaderFillType : uint8 { None, Scale, ScaleMatchHeight, ScaleMatchWidth, ScaleFree, ScaleNoBorder }; UENUM() enum class EProgressTitleType : uint8 { Percent, ValueMax, Value, Max }; UENUM() enum class EListLayoutType : uint8 { SingleColumn, SingleRow, FlowHorizontal, FlowVertical, Pagination }; UENUM() enum class EListSelectionMode : uint8 { Single, Multiple, MultipleSingleclick, None }; UENUM() enum class EGroupLayoutType : uint8 { None, Horizontal, Vertical }; UENUM() enum class EPopupDirection : uint8 { Auto, Up, Down }; UENUM() enum class EAutoSizeType : uint8 { None, Both, Height, Shrink }; UENUM() enum class EFlipType : uint8 { None, Horizontal, Vertical, Both }; UENUM() enum class ETransitionActionType { XY, Size, Scale, Pivot, Alpha, Rotation, Color, Animation, Visible, Sound, Transition, Shake, ColorFilter, Skew, Text, Icon, Unknown }; UENUM() enum class EFillMethod : uint8 { None, Horizontal, Vertical, Radial90, Radial180, Radial360, }; UENUM() enum class EOriginHorizontal : uint8 { Left, Right, }; UENUM() enum class EOriginVertical : uint8 { Top, Bottom }; UENUM() enum class EOrigin90 : uint8 { TopLeft, TopRight, BottomLeft, BottomRight }; UENUM() enum class EOrigin180 : uint8 { Top, Bottom, Left, Right }; UENUM() enum class EOrigin360 : uint8 { Top, Bottom, Left, Right }; UENUM() enum class EObjectPropID { Text, Icon, Color, OutlineColor, Playing, Frame, DeltaTime, TimeScale, FontSize, Selected }; UENUM() enum class EAlignType : uint8 { Left, Center, Right }; UENUM() enum class EVerticalAlignType : uint8 { Top, Middle, Bottom }; UENUM() enum class ERelationType : uint8 { Left_Left, Left_Center, Left_Right, Center_Center, Right_Left, Right_Center, Right_Right, Top_Top, Top_Middle, Top_Bottom, Middle_Middle, Bottom_Top, Bottom_Middle, Bottom_Bottom, Width, Height, LeftExt_Left, LeftExt_Right, RightExt_Left, RightExt_Right, TopExt_Top, TopExt_Bottom, BottomExt_Top, BottomExt_Bottom, Size }; ================================================ FILE: Source/FairyGUI/Public/UI/GButton.h ================================================ #pragma once #include "GComponent.h" #include "GButton.generated.h" class UGController; class UGTextField; UCLASS(BlueprintType, Blueprintable) class FAIRYGUI_API UGButton : public UGComponent { GENERATED_BODY() public: UGButton(); virtual ~UGButton(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") const FString& GetTitle() const { return Title; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetTitle(const FString& InTitle) { SetText(InTitle); }; virtual const FString& GetText() const override { return Title; } virtual void SetText(const FString& InText) override; virtual const FString& GetIcon() const override; virtual void SetIcon(const FString& InIcon) override; UFUNCTION(BlueprintCallable, Category = "FairyGUI") const FString& GetSelectedTitle() const { return SelectedTitle; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetSelectedTitle(const FString& InTitle); UFUNCTION(BlueprintCallable, Category = "FairyGUI") const FString& GetSelectedIcon() const { return SelectedIcon; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetSelectedIcon(const FString& InIcon); UFUNCTION(BlueprintCallable, Category = "FairyGUI") FColor GetTitleColor() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetTitleColor(const FColor& InColor); UFUNCTION(BlueprintCallable, Category = "FairyGUI") int32 GetTitleFontSize() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetTitleFontSize(int32 InFontSize); UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool IsSelected() const { return bSelected; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetSelected(bool bInSelected); UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGController* GetRelatedController() const { return RelatedController; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetRelatedController(UGController* InController); UGTextField* GetTextField() const; virtual FNVariant GetProp(EObjectPropID PropID) const override; virtual void SetProp(EObjectPropID PropID, const FNVariant& InValue) override; UPROPERTY(BlueprintAssignable, Category = "FairyGUI|Event") FGUIEventDynMDelegate OnChanged; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") bool bChangeStateOnClick; static const FString UP; static const FString DOWN; static const FString OVER; static const FString SELECTED_OVER; static const FString DISABLED; static const FString SELECTED_DISABLED; protected: virtual void ConstructExtension(FByteBuffer* Buffer); virtual void SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos) override; virtual void HandleControllerChanged(UGController* Controller) override; void SetState(const FString& InState); void SetCurrentState(); private: void OnRollOverHandler(UEventContext* Context); void OnRollOutHandler(UEventContext* Context); void OnTouchBeginHandler(UEventContext* Context); void OnTouchEndHandler(UEventContext* Context); void OnClickHandler(UEventContext* Context); void OnRemovedFromStageHandler(UEventContext* Context); EButtonMode Mode; UGObject* TitleObject; UGObject* IconObject; UGController* ButtonController; UGController* RelatedController; FString RelatedPageID; FString Title; FString SelectedTitle; FString Icon; FString SelectedIcon; FString Sound; float SoundVolumeScale; bool bSelected; bool bOver; bool bDown; int32 DownEffect; bool bDownScaled; float DownEffectValue; }; ================================================ FILE: Source/FairyGUI/Public/UI/GComboBox.h ================================================ #pragma once #include "GComponent.h" #include "GComboBox.generated.h" class UGController; class UGTextField; class UGList; UCLASS(BlueprintType, Blueprintable) class FAIRYGUI_API UGComboBox : public UGComponent { GENERATED_BODY() public: UGComboBox(); virtual ~UGComboBox(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") const FString& GetTitle() const { return GetText(); } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetTitle(const FString& InTitle) { SetText(InTitle); }; virtual const FString& GetText() const override; virtual void SetText(const FString& InText) override; virtual const FString& GetIcon() const override; virtual void SetIcon(const FString& InIcon) override; UFUNCTION(BlueprintCallable, Category = "FairyGUI") FColor GetTitleColor() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetTitleColor(const FColor& InColor); UFUNCTION(BlueprintCallable, Category = "FairyGUI") int32 GetTitleFontSize() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetTitleFontSize(int32 InFontSize); UFUNCTION(BlueprintCallable, Category = "FairyGUI") const FString& GetValue() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetValue(const FString& InValue); UFUNCTION(BlueprintCallable, Category = "FairyGUI") int32 GetSelectedIndex() const { return SelectedIndex; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetSelectedIndex(int32 InIndex); UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGController* GetSelectionController() const { return SelectionController; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetSelectionController(UGController* InController) { SelectionController = InController; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGObject* GetDropdown() const { return DropdownObject; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void Refresh(); UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") int32 VisibleItemCount; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") EPopupDirection PopupDirection; UGTextField* GetTextField() const; virtual FNVariant GetProp(EObjectPropID PropID) const override; virtual void SetProp(EObjectPropID PropID, const FNVariant& InValue) override; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") TArray Items; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") TArray Icons; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") TArray Values; UPROPERTY(BlueprintAssignable, Category = "FairyGUI|Event") FGUIEventDynMDelegate OnChanged; protected: virtual void ConstructExtension(FByteBuffer* Buffer); virtual void SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos) override; virtual void HandleControllerChanged(UGController* Controller) override; virtual void HandleGrayedChanged() override; void SetState(const FString& InState); void SetCurrentState(); void UpdateSelectionController(); void UpdateDropdownList(); void ShowDropdown(); void RenderDropdownList(); UPROPERTY(Transient) UGComponent* DropdownObject; UGObject* TitleObject; UGObject* IconObject; UGList* ListObject; UGController* SelectionController; private: void OnClickItem(UEventContext* Context); void OnRollOverHandler(UEventContext* Context); void OnRollOutHandler(UEventContext* Context); void OnTouchBeginHandler(UEventContext* Context); void OnTouchEndHandler(UEventContext* Context); void OnPopupWinClosed(UEventContext* Context); bool bItemsUpdated; int32 SelectedIndex; UGController* ButtonController; bool bDown; bool bOver; }; ================================================ FILE: Source/FairyGUI/Public/UI/GComponent.h ================================================ #pragma once #include "GObject.h" #include "ScrollPane.h" #include "GComponent.generated.h" class UGController; class UTransition; class SContainer; UCLASS(BlueprintType, Blueprintable) class FAIRYGUI_API UGComponent : public UGObject { GENERATED_BODY() public: UGComponent(); virtual ~UGComponent(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGObject* AddChild(UGObject* Child); UFUNCTION(BlueprintCallable, Category = "FairyGUI") virtual UGObject* AddChildAt(UGObject* Child, int32 Index); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void RemoveChild(UGObject* Child); UFUNCTION(BlueprintCallable, Category = "FairyGUI") virtual void RemoveChildAt(int32 Index); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void RemoveChildren(int32 BeginIndex = 0, int32 EndIndex = -1); UFUNCTION(BlueprintCallable, Category = "FairyGUI", meta = (DeterminesOutputType = "ClassType")) UGObject* GetChildAt(int32 Index, TSubclassOf ClassType = nullptr) const; UFUNCTION(BlueprintCallable, Category = "FairyGUI", meta = (DeterminesOutputType = "ClassType")) UGObject* GetChild(const FString& ChildName, TSubclassOf ClassType = nullptr) const; UFUNCTION(BlueprintCallable, Category = "FairyGUI", meta = (DeterminesOutputType = "ClassType")) UGObject* GetChildByPath(const FString& Path, TSubclassOf ClassType = nullptr) const; UFUNCTION(BlueprintCallable, Category = "FairyGUI", meta = (DeterminesOutputType = "ClassType")) UGObject* GetChildInGroup(const UGGroup* Group, const FString& ChildName, TSubclassOf ClassType = nullptr) const; UGObject* GetChildByID(const FString& ChildID) const; const TArray& GetChildren() const { return Children; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") int32 GetChildIndex(const UGObject* Child) const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetChildIndex(UGObject* Child, int32 Index); UFUNCTION(BlueprintCallable, Category = "FairyGUI") int32 SetChildIndexBefore(UGObject* Child, int32 Index); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SwapChildren(UGObject* Child1, UGObject* Child2); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SwapChildrenAt(int32 Index1, int32 Index2); UFUNCTION(BlueprintCallable, Category = "FairyGUI") int32 NumChildren() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool IsAncestorOf(const UGObject* Obj) const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") virtual bool IsChildInView(UGObject* Child) const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") virtual int32 GetFirstChildInView() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGController* GetControllerAt(int32 Index) const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGController* GetController(const FString& ControllerName) const; const TArray& GetControllers() const { return Controllers; } void AddController(UGController* Controller); void RemoveController(UGController* Controller); void ApplyController(UGController* Controller); void ApplyAllControllers(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") UTransition* GetTransition(const FString& TransitionName) const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") UTransition* GetTransitionAt(int32 Index) const; const TArray& GetTransitions() const { return Transitions; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool IsOpaque() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetOpaque(bool bInOpaque); UFUNCTION(BlueprintCallable, Category = "FairyGUI") const FMargin& GetMargin() { return Margin; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetMargin(const FMargin& InMargin); UFUNCTION(BlueprintCallable, Category = "FairyGUI") EChildrenRenderOrder GetChildrenRenderOrder() const { return ChildrenRenderOrder; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetChildrenRenderOrder(EChildrenRenderOrder InChildrenRenderOrder); UFUNCTION(BlueprintCallable, Category = "FairyGUI") int32 GetApexIndex() const { return ApexIndex; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetApexIndex(int32 InApedIndex); //UGObject* getMask() const; //void setMask(UGObject* value, bool inverted = false); virtual IHitTest* GetHitArea() const override { return HitArea.Get(); } void SetHitArea(const TSharedPtr& InHitArea); UFUNCTION(BlueprintCallable, Category = "FairyGUI") UScrollPane* GetScrollPane() const { return ScrollPane; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") float GetViewWidth() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetViewWidth(float InViewWidth); UFUNCTION(BlueprintCallable, Category = "FairyGUI") float GetViewHeight() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetViewHeight(float InViewHeight); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetBoundsChangedFlag(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void EnsureBoundsCorrect(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void OnClickChild(const FString& ChildName, const FGUIEventDynDelegate& Delegate) { GetChild(ChildName)->OnClick.AddUnique(Delegate); } UPROPERTY(BlueprintAssignable, Category = "FairyGUI|Event") FGUIEventDynMDelegate OnDrop; UPROPERTY(BlueprintAssignable, Category = "FairyGUI|Event") FGUIEventDynMDelegate OnScroll; UPROPERTY(BlueprintAssignable, Category = "FairyGUI|Event") FGUIEventDynMDelegate OnScrollEnd; UPROPERTY(BlueprintAssignable, Category = "FairyGUI|Event") FGUIEventDynMDelegate OnPullUpRelease; UPROPERTY(BlueprintAssignable, Category = "FairyGUI|Event") FGUIEventDynMDelegate OnPullDownRelease; virtual FVector2D GetSnappingPosition(const FVector2D& InPoint); //internal use void ChildSortingOrderChanged(UGObject* Child, int32 OldValue, int32 NewValue); void ChildStateChanged(UGObject* Child); void AdjustRadioGroupDepth(UGObject* Child, UGController* Controller); virtual void ConstructFromResource() override; void ConstructFromResource(TArray* ObjectPool, int32 PoolIndex); bool bBuildingDisplayList; protected: virtual void ConstructExtension(FByteBuffer* Buffer); virtual void OnConstruct(); UFUNCTION(BlueprintImplementableEvent, Category = "FairyGUI", meta = ( DisplayName = "OnConstruct")) void K2_OnConstruct(); virtual void SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos) override; virtual void HandleSizeChanged() override; virtual void HandleGrayedChanged() override; virtual void HandleControllerChanged(UGController* Controller) override; virtual void UpdateBounds(); void SetBounds(float ax, float ay, float aw, float ah); void SetupOverflow(EOverflowType InOverflow); void SetupScroll(FByteBuffer* Buffer); UPROPERTY(Transient) TArray Children; UPROPERTY(Transient) TArray Controllers; UPROPERTY(Transient) TArray Transitions; UPROPERTY(Transient) UScrollPane* ScrollPane; TSharedPtr RootContainer; TSharedPtr Container; FMargin Margin; FVector2D AlignOffset; EChildrenRenderOrder ChildrenRenderOrder; int32 ApexIndex; uint8 bBoundsChanged : 1; uint8 bTrackBounds : 1; TSharedPtr HitArea; private: int32 GetInsertPosForSortingChild(UGObject* Child); int32 MoveChild(UGObject* Child, int32 OldIndex, int32 NewIndex); void BuildNativeDisplayList(bool bImmediatelly = false); void OnAddedToStageHandler(UEventContext* Context); void OnRemovedFromStageHandler(UEventContext* Context); int32 SortingChildCount; UGController* ApplyingController; FTimerHandle UpdateBoundsTimerHandle; FTimerHandle BuildDisplayListTimerHandle; friend class UScrollPane; }; ================================================ FILE: Source/FairyGUI/Public/UI/GController.h ================================================ #pragma once #include "CoreMinimal.h" #include "UObject/NoExportTypes.h" #include "ControllerAction/ControllerAction.h" #include "GController.generated.h" class UGComponent; class FByteBuffer; UCLASS(BlueprintType) class FAIRYGUI_API UGController : public UObject { GENERATED_BODY() public: UGController(); virtual ~UGController(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") int32 GetSelectedIndex() const { return SelectedIndex; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetSelectedIndex(int32 Index); void SetSelectedIndex(int32 Index, bool bTriggerEvent); UFUNCTION(BlueprintCallable, Category = "FairyGUI") const FString& GetSelectedPage() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetSelectedPage(const FString& PageName); void SetSelectedPage(const FString& PageName, bool bTriggerEvent); const FString& GetSelectedPageID() const; void SetSelectedPageID(const FString& PageID, bool bTriggerEvent = true); int32 GetPrevisousIndex() const { return PreviousIndex; } const FString& GetPreviousPage() const; const FString& GetPreviousPageID() const; int32 GetPageCount() const; bool HasPage(const FString& PageName) const; int32 GetPageIndexByID(const FString& PageID) const; const FString& GetPageNameByID(const FString& PageID) const; const FString& GetPageID(int32 Index) const; void SetOppositePageID(const FString& PageID); void RunActions(); void Setup(FByteBuffer* Buffer); FString Name; bool bChanging; bool bAutoRadioGroupDepth; DECLARE_EVENT_OneParam(UGController, FOnChanged, UGController*); FOnChanged& OnChanged() { return OnChangedEvent; } private: int32 SelectedIndex; int32 PreviousIndex; TArray PageIDs; TArray PageNames; TIndirectArray Actions; FOnChanged OnChangedEvent; }; ================================================ FILE: Source/FairyGUI/Public/UI/GGraph.h ================================================ #pragma once #include "GObject.h" #include "GGraph.generated.h" UCLASS(BlueprintType) class FAIRYGUI_API UGGraph : public UGObject { GENERATED_BODY() public: UGGraph(); virtual ~UGGraph(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") FColor GetColor() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetColor(const FColor& InColor); UFUNCTION(BlueprintCallable, Category = "FairyGUI", meta = (AutoCreateRefTerm = "LineColor,FillColor")) void DrawRect(float LineWidth, const FColor& LineColor, const FColor& FillColor); UFUNCTION(BlueprintCallable, Category = "FairyGUI", meta = (AutoCreateRefTerm = "LineColor,FillColor")) void DrawRoundRect(float LineWidth, const FColor& LineColor, const FColor& FillColor, float TopLeftRadius, float TopRightRadius, float BottomLeftRadius, float BottomRightRadius); UFUNCTION(BlueprintCallable, Category = "FairyGUI", meta = (AutoCreateRefTerm = "LineColor,FillColor")) void DrawEllipse(float LineWidth, const FColor& LineColor, const FColor& FillColor, float StartDegree = 0, float EndDegree = 360); UFUNCTION(BlueprintCallable, Category = "FairyGUI", meta = (AutoCreateRefTerm = "LineColor,FillColor,Points")) void DrawPolygon(float LineWidth, const FColor& LineColor, const FColor& FillColor, const TArray& Points); UFUNCTION(BlueprintCallable, Category = "FairyGUI", meta = (AutoCreateRefTerm = "LineColor,FillColor,Distances")) void DrawRegularPolygon(int32 Sides, float LineWidth, const FColor& LineColor, const FColor& FillColor, float Rotation, const TArray& Distances); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void Clear(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool IsEmpty() const; virtual IHitTest* GetHitArea() const override; virtual FNVariant GetProp(EObjectPropID PropID) const override; virtual void SetProp(EObjectPropID PropID, const FNVariant& InValue) override; protected: virtual void SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos) override; private: TSharedPtr Content; }; ================================================ FILE: Source/FairyGUI/Public/UI/GGroup.h ================================================ #pragma once #include "GObject.h" #include "GGroup.generated.h" UCLASS(BlueprintType) class FAIRYGUI_API UGGroup : public UGObject { GENERATED_BODY() public: UGGroup(); virtual ~UGGroup(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") EGroupLayoutType GetLayout() { return Layout; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetLayout(EGroupLayoutType InLayout); UFUNCTION(BlueprintCallable, Category = "FairyGUI") int32 GetColumnGap() { return ColumnGap; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetColumnGap(int32 InColumnGap); UFUNCTION(BlueprintCallable, Category = "FairyGUI") int32 GetLineGap() { return LineGap; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetLineGap(int32 InLineGap); UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool IsExcludeInvisibles() { return bExcludeInvisibles; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetExcludeInvisibles(bool bInFlag); UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool IsAutoSizeDisabled() { return bAutoSizeDisabled; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetAutoSizeDisabled(bool bInFlag); UFUNCTION(BlueprintCallable, Category = "FairyGUI") int32 GetMainGridIndex() { return MainGridIndex; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetMainGridIndex(int32 InIndex); UFUNCTION(BlueprintCallable, Category = "FairyGUI") int32 GetMainGridMinSize() { return MainGridMinSize; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetMainGridMinSize(int32 InSize); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetBoundsChangedFlag(bool bPositionChangedOnly = false); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void EnsureBoundsCorrect(); void MoveChildren(const FVector2D& Delta); void ResizeChildren(const FVector2D& Delta); uint8 Updating; protected: virtual void SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos) override; virtual void SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos) override; virtual void HandleAlphaChanged() override; virtual void HandleVisibleChanged() override; private: void UpdateBounds(); void HandleLayout(); EGroupLayoutType Layout; int32 LineGap; int32 ColumnGap; bool bExcludeInvisibles; bool bAutoSizeDisabled; int32 MainGridIndex; int32 MainGridMinSize; bool bPercentReady; bool bBoundsChanged; int32 MainChildIndex; float TotalSize; int32 NumChildren; FTimerHandle UpdateBoundsTimerHandle; }; ================================================ FILE: Source/FairyGUI/Public/UI/GImage.h ================================================ #pragma once #include "GObject.h" #include "GImage.generated.h" UCLASS(BlueprintType) class FAIRYGUI_API UGImage : public UGObject { GENERATED_BODY() public: UGImage(); virtual ~UGImage(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") EFlipType GetFlip() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetFlip(EFlipType InFlip); UFUNCTION(BlueprintCallable, Category = "FairyGUI") FColor GetColor() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetColor(const FColor& InColor); UFUNCTION(BlueprintCallable, Category = "FairyGUI") EFillMethod GetFillMethod() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetFillMethod(EFillMethod Method); UFUNCTION(BlueprintCallable, Category = "FairyGUI") int32 GetFillOrigin() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetFillOrigin(int32 Origin); UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool IsFillClockwise() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetFillClockwise(bool bClockwise); UFUNCTION(BlueprintCallable, Category = "FairyGUI") float GetFillAmount() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetFillAmount(float Amount); virtual void ConstructFromResource() override; virtual FNVariant GetProp(EObjectPropID PropID) const override; virtual void SetProp(EObjectPropID PropID, const FNVariant& InValue) override; protected: virtual void SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos) override; private: TSharedPtr Content; }; ================================================ FILE: Source/FairyGUI/Public/UI/GLabel.h ================================================ #pragma once #include "GComponent.h" #include "GLabel.generated.h" class UGTextField; UCLASS(BlueprintType, Blueprintable) class FAIRYGUI_API UGLabel : public UGComponent { GENERATED_BODY() public: UGLabel(); virtual ~UGLabel(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") const FString& GetTitle() const { return GetText(); } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetTitle(const FString& InTitle) { SetText(InTitle); }; virtual const FString& GetText() const override; virtual void SetText(const FString& InText) override; virtual const FString& GetIcon() const override; virtual void SetIcon(const FString& InIcon) override; UFUNCTION(BlueprintCallable, Category = "FairyGUI") FColor GetTitleColor() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetTitleColor(const FColor& InColor); UFUNCTION(BlueprintCallable, Category = "FairyGUI") int32 GetTitleFontSize() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetTitleFontSize(int32 value); UGTextField* GetTextField() const; virtual FNVariant GetProp(EObjectPropID PropID) const override; virtual void SetProp(EObjectPropID PropID, const FNVariant& InValue) override; protected: virtual void ConstructExtension(FByteBuffer* Buffer); virtual void SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos) override; UGObject* TitleObject; UGObject* IconObject; }; ================================================ FILE: Source/FairyGUI/Public/UI/GList.h ================================================ #pragma once #include "GComponent.h" #include "GList.generated.h" class FGObjectPool; DECLARE_DELEGATE_TwoParams(FListItemRenderer, int32, UGObject*); DECLARE_DELEGATE_RetVal_OneParam(FString, FListItemProvider, int32); DECLARE_DYNAMIC_DELEGATE_TwoParams(FDynListItemRenderer, int32, Index, UGObject*, Obj); DECLARE_DYNAMIC_DELEGATE_RetVal_OneParam(FString, FDynListItemProvider, int32, Index); UCLASS(BlueprintType, NotBlueprintable) class FAIRYGUI_API UGList : public UGComponent { GENERATED_BODY() public: UGList(); virtual ~UGList(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") const FString& GetDefaultItem() const { return DefaultItem; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetDefaultItem(const FString& InDefaultItem); UFUNCTION(BlueprintCallable, Category = "FairyGUI") EListLayoutType GetLayout() const { return Layout; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetLayout(EListLayoutType InLayout); UFUNCTION(BlueprintCallable, Category = "FairyGUI") int32 GetLineCount() const { return LineCount; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetLineCount(int32 InLineCount); UFUNCTION(BlueprintCallable, Category = "FairyGUI") int32 GetColumnCount() { return ColumnCount; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetColumnCount(int32 InColumnCount); UFUNCTION(BlueprintCallable, Category = "FairyGUI") int32 GetColumnGap() const { return ColumnGap; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetColumnGap(int32 InColumnGap); UFUNCTION(BlueprintCallable, Category = "FairyGUI") int32 GetLineGap() const { return LineGap; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetLineGap(int32 InLineGap); UFUNCTION(BlueprintCallable, Category = "FairyGUI") EAlignType GetAlign() const { return Align; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetAlign(EAlignType InAlign); UFUNCTION(BlueprintCallable, Category = "FairyGUI") EVerticalAlignType GetVerticalAlign() const { return VerticalAlign; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetVerticalAlign(EVerticalAlignType InVerticalAlign); UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool GetAutoResizeItem() const { return bAutoResizeItem; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetAutoResizeItem(bool bFlag); UFUNCTION(BlueprintCallable, Category = "FairyGUI") EListSelectionMode GetSelectionMode() const { return SelectionMode; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetSelectionMode(EListSelectionMode InMode) { SelectionMode = InMode; } FGObjectPool* GetItemPool() const { return Pool; } UGObject* GetFromPool(); UGObject* GetFromPool(const FString& URL); void ReturnToPool(UGObject* Obj); UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGObject* AddItemFromPool(const FString& URL = ""); virtual UGObject* AddChildAt(UGObject* Child, int32 Index) override; virtual void RemoveChildAt(int32 Index) override; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void RemoveChildToPoolAt(int32 Index); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void RemoveChildToPool(UGObject* Child); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void RemoveChildrenToPool(int32 BeginIndex = 0, int32 EndIndex = -1); UFUNCTION(BlueprintCallable, Category = "FairyGUI") int32 GetSelectedIndex() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetSelectedIndex(int32 Index); void GetSelection(TArray& OutIndice) const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void AddSelection(int32 Index, bool bScrollItToView); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void RemoveSelection(int32 Index); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void ClearSelection(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SelectAll(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SelectReverse(); void HandleArrowKey(int32 Direction); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void ResizeToFit(int32 ItemCount, int32 InMinSize = 0); virtual int32 GetFirstChildInView() const override; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void ScrollToView(int32 Index, bool bAnimation = false, bool bSetFirst = false); UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGController* GetSelectionController() const { return SelectionController; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetSelectionController(UGController* InController); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetVirtual(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetVirtualAndLoop(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool IsVirtual() const { return bVirtual; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void RefreshVirtualList(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") int32 GetNumItems() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetNumItems(int32 InNumItems); UFUNCTION(BlueprintCallable, Category = "FairyGUI") int32 ChildIndexToItemIndex(int32 Index) const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") int32 ItemIndexToChildIndex(int32 Index) const; virtual FVector2D GetSnappingPosition(const FVector2D& InPoint) override; void SetItemRenderer(const FListItemRenderer& InItemRenderer) { ItemRenderer = InItemRenderer; } void SetItemProvider(const FListItemProvider& InItemProvider) { ItemProvider = InItemProvider; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetItemRenderer(const FDynListItemRenderer& InItemRenderer) { if (InItemRenderer.IsBound()) ItemRenderer = FListItemRenderer::CreateUFunction(const_cast(InItemRenderer.GetUObject()), InItemRenderer.GetFunctionName()); else ItemRenderer.Unbind(); } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetItemProvider(const FDynListItemProvider& InItemProvider) { if (InItemProvider.IsBound()) ItemProvider = FListItemProvider::CreateUFunction(const_cast(InItemProvider.GetUObject()), InItemProvider.GetFunctionName()); else ItemProvider.Unbind(); } UPROPERTY(BlueprintAssignable, Category = "FairyGUI|Event") FGUIEventDynMDelegate OnClickItem; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") bool bScrollItemToViewOnClick; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") bool bFoldInvisibleItems; protected: virtual void HandleControllerChanged(UGController* Controller) override; virtual void HandleSizeChanged() override; virtual void UpdateBounds() override; virtual void SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos) override; virtual void SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos) override; virtual void DispatchItemEvent(UGObject* Obj, UEventContext* Context); virtual void ReadItems(FByteBuffer* Buffer); virtual void SetupItem(FByteBuffer* Buffer, UGObject* Obj); private: void ClearSelectionExcept(UGObject* Obj); void SetSelectionOnEvent(UGObject* Obj, UEventContext* Context); UFUNCTION() void OnClickItemHandler(UEventContext* Context); void UpdateSelectionController(int32 Index); void SetVirtual(bool bLoop); void CheckVirtualList(); void SetVirtualListChangedFlag(bool bLayoutChanged); void DoRefreshVirtualList(); void OnScrollHandler(UEventContext* Context); int32 GetIndexOnPos1(float& pos, bool forceUpdate); int32 GetIndexOnPos2(float& pos, bool forceUpdate); int32 GetIndexOnPos3(float& pos, bool forceUpdate); void HandleScroll(bool forceUpdate); bool HandleScroll1(bool forceUpdate); bool HandleScroll2(bool forceUpdate); void HandleScroll3(bool forceUpdate); void HandleArchOrder1(); void HandleArchOrder2(); void HandleAlign(float InContentWidth, float InContentHeight); FString DefaultItem; EListLayoutType Layout; int32 LineCount; int32 ColumnCount; int32 LineGap; int32 ColumnGap; EAlignType Align; EVerticalAlignType VerticalAlign; bool bAutoResizeItem; EListSelectionMode SelectionMode; UGController* SelectionController; FListItemRenderer ItemRenderer; FListItemProvider ItemProvider; FGObjectPool* Pool; int32 LastSelectedIndex; //Virtual List support bool bVirtual; bool bLoop; int32 NumItems; int32 RealNumItems; int32 FirstIndex; //the top left index int32 CurLineItemCount; //item count in one line int32 CurLineItemCount2; //item count in vertical direction,only pagination layout FVector2D ItemSize; int32 VirtualListChanged; //1-content changed, 2-size changed bool bEventLocked; uint32 ItemInfoVer; FTimerHandle RefreshTimerHandle; struct FItemInfo { FVector2D Size; UGObject* Obj; uint32 UpdateFlag; bool bSelected; FItemInfo(); }; TArray VirtualItems; }; ================================================ FILE: Source/FairyGUI/Public/UI/GLoader.h ================================================ #pragma once #include "GObject.h" #include "GLoader.generated.h" UCLASS(BlueprintType, Blueprintable) class FAIRYGUI_API UGLoader : public UGObject { GENERATED_BODY() public: UGLoader(); virtual ~UGLoader(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") const FString& GetURL() const { return URL; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetURL(const FString& InURL); virtual const FString& GetIcon() const override { return URL; } virtual void SetIcon(const FString& InIcon) override { SetURL(InIcon); } UFUNCTION(BlueprintCallable, Category = "FairyGUI") EAlignType GetAlign() const { return Align; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetAlign(EAlignType InAlign); UFUNCTION(BlueprintCallable, Category = "FairyGUI") EVerticalAlignType GetVerticalAlign() const { return VerticalAlign; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetVerticalAlign(EVerticalAlignType InVerticalAlign); UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool GetAutoSize() const { return bAutoSize; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetAutoSize(bool bInAutoSize); UFUNCTION(BlueprintCallable, Category = "FairyGUI") ELoaderFillType GetFill() const { return Fill; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetFill(ELoaderFillType InFillType); UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool IsShrinkOnly() const { return bShrinkOnly; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetShrinkOnly(bool bInShrinkOnly); UFUNCTION(BlueprintCallable, Category = "FairyGUI") EFlipType GetFlip() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetFlip(EFlipType InFlip); UFUNCTION(BlueprintCallable, Category = "FairyGUI") FColor GetColor() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetColor(const FColor& InColor); UFUNCTION(BlueprintCallable, Category = "FairyGUI") EFillMethod GetFillMethod() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetFillMethod(EFillMethod Method); UFUNCTION(BlueprintCallable, Category = "FairyGUI") int32 GetFillOrigin() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetFillOrigin(int32 Origin); UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool IsFillClockwise() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetFillClockwise(bool bClockwise); UFUNCTION(BlueprintCallable, Category = "FairyGUI") float GetFillAmount() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetFillAmount(float Amount); UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool IsPlaying() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetPlaying(bool bInPlaying); UFUNCTION(BlueprintCallable, Category = "FairyGUI") int32 GetFrame() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetFrame(int32 InFrame); virtual FNVariant GetProp(EObjectPropID PropID) const; virtual void SetProp(EObjectPropID PropID, const FNVariant& InValue); protected: virtual void HandleSizeChanged() override; virtual void SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos) override; void LoadContent(); void ClearContent(); void LoadFromPackage(const FString& ItemURL); void LoadExternal(); void OnExternalLoaded(FString LoadingURL); void UpdateLayout(); void SetErrorState(); TSharedPtr SoftObjectPath; private: TSharedPtr Container; TSharedPtr Content; UPROPERTY(Transient) UGObject* Content2; TSharedPtr ContentItem; FString URL; ELoaderFillType Fill; EAlignType Align; EVerticalAlignType VerticalAlign; uint8 bShowErrorSign : 1; uint8 bShrinkOnly : 1; uint8 bAutoSize : 1; uint8 bUpdatingLayout : 1; }; ================================================ FILE: Source/FairyGUI/Public/UI/GLoader3D.h ================================================ #pragma once #include "GObject.h" #include "GLoader3D.generated.h" UCLASS(BlueprintType, Blueprintable) class FAIRYGUI_API UGLoader3D : public UGObject { GENERATED_BODY() public: UGLoader3D(); virtual ~UGLoader3D(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") const FString& GetURL() const { return URL; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetURL(const FString& InURL); virtual const FString& GetIcon() const override { return URL; } virtual void SetIcon(const FString& InIcon) override { SetURL(InIcon); } UFUNCTION(BlueprintCallable, Category = "FairyGUI") FColor GetColor() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetColor(const FColor& InColor); virtual FNVariant GetProp(EObjectPropID PropID) const; virtual void SetProp(EObjectPropID PropID, const FNVariant& InValue); protected: virtual void HandleSizeChanged() override; virtual void SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos) override; void LoadContent(); void ClearContent(); void LoadFromPackage(const FString& ItemURL); void LoadExternal(); void UpdateLayout(); void SetErrorState(); private: TSharedPtr Content; TSharedPtr ContentItem; FString URL; ELoaderFillType Fill; EAlignType Align; EVerticalAlignType VerticalAlign; bool bShowErrorSign; bool bShrinkOnly; bool bAutoSize; bool bUpdatingLayout; }; ================================================ FILE: Source/FairyGUI/Public/UI/GMovieClip.h ================================================ #pragma once #include "GObject.h" #include "Event/EventContext.h" #include "GMovieClip.generated.h" UCLASS(BlueprintType) class FAIRYGUI_API UGMovieClip : public UGObject { GENERATED_BODY() public: UGMovieClip(); virtual ~UGMovieClip(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool IsPlaying() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetPlaying(bool bInPlaying); UFUNCTION(BlueprintCallable, Category = "FairyGUI") int32 GetFrame() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetFrame(int32 InFrame); UFUNCTION(BlueprintCallable, Category = "FairyGUI") float GetTimeScale() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetTimeScale(float InTimeScale); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void Advance(float Time); UFUNCTION(BlueprintCallable, Category = "FairyGUI") EFlipType GetFlip() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetFlip(EFlipType InFlip); UFUNCTION(BlueprintCallable, Category = "FairyGUI") FColor GetColor() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetColor(const FColor& InColor); //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) void SetPlaySettings(int32 InStart = 0, int32 InEnd = -1, int32 InTimes = 0, int32 InEndAt = -1, const FSimpleDelegate& InCompleteCallback = FSimpleDelegate()); UFUNCTION(BlueprintCallable, Category = "FairyGUI", meta = (AutoCreateRefTerm = "InCompleteCallback")) void SetPlaySettings(const FSimpleDynDelegate& InCompleteCallback, int32 InStart = 0, int32 InEnd = -1, int32 InTimes = 0, int32 InEndAt = -1) { SetPlaySettings(InStart, InEnd, InTimes, InEndAt, InCompleteCallback.IsBound() ? FSimpleDelegate::CreateUFunction(const_cast(InCompleteCallback.GetUObject()), InCompleteCallback.GetFunctionName()) : FSimpleDelegate()); } virtual void ConstructFromResource() override; virtual FNVariant GetProp(EObjectPropID PropID) const override; virtual void SetProp(EObjectPropID PropID, const FNVariant& InValue) override; protected: virtual void SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos) override; private: TSharedPtr Content; }; ================================================ FILE: Source/FairyGUI/Public/UI/GObject.h ================================================ #pragma once #include "Relations.h" #include "PackageItem.h" #include "UIConfig.h" #include "FairyCommons.h" #include "Widgets/SDisplayObject.h" #include "Widgets/HitTest.h" #include "Event/EventContext.h" #include "Utils/NVariant.h" #include "GObject.generated.h" class FByteBuffer; class FRelations; class FGearBase; class UGGroup; class UGComponent; class UGTreeNode; class UGController; class UGRoot; UCLASS(BlueprintType) class FAIRYGUI_API UGObject : public UObject { GENERATED_BODY() public: UGObject(); virtual ~UGObject(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") float GetX() const { return Position.X; }; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetX(float InX); UFUNCTION(BlueprintCallable, Category = "FairyGUI") float GetY() const { return Position.Y; }; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetY(float InY); UFUNCTION(BlueprintCallable, Category = "FairyGUI") const FVector2D& GetPosition() const { return Position; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetPosition(const FVector2D& InPosition); UFUNCTION(BlueprintCallable, Category = "FairyGUI") float GetXMin() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetXMin(float InXMin); UFUNCTION(BlueprintCallable, Category = "FairyGUI") float GetYMin() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetYMin(float InYMin); UFUNCTION(BlueprintCallable, Category = "FairyGUI") float GetWidth() const { return Size.X; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetWidth(float InWidth) { SetSize(FVector2D(InWidth, RawSize.Y)); } UFUNCTION(BlueprintCallable, Category = "FairyGUI") float GetHeight() const { return Size.Y; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetHeight(float InHeight) { SetSize(FVector2D(RawSize.X, InHeight)); } UFUNCTION(BlueprintCallable, Category = "FairyGUI") const FVector2D& GetSize() const { return Size; } UFUNCTION(BlueprintCallable, Category = "FairyGUI", meta = (AdvancedDisplay="bIgnorePivot")) void SetSize(const FVector2D& InSize, bool bIgnorePivot = false); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void Center(bool bRestraint = false); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void MakeFullScreen(bool bRestraint = false); UFUNCTION(BlueprintCallable, Category = "FairyGUI") const FVector2D& GetPivot() const { return Pivot; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetPivot(const FVector2D& InPivot, bool bAsAnchor = false); UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool IsPivotAsAnchor() const { return bPivotAsAnchor; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") float GetScaleX() const { return Scale.X; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetScaleX(float InScaleX) { SetScale(FVector2D(InScaleX, Scale.Y)); } UFUNCTION(BlueprintCallable, Category = "FairyGUI") float GetScaleY() const { return Scale.Y; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetScaleY(float InScaleY) { SetScale(FVector2D(Scale.X, InScaleY)); } UFUNCTION(BlueprintCallable, Category = "FairyGUI") const FVector2D& GetScale() const { return Scale; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetScale(const FVector2D& InScale); UFUNCTION(BlueprintCallable, Category = "FairyGUI") const FVector2D& GetSkew() const { return Skew; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetSkew(const FVector2D& InSkew); UFUNCTION(BlueprintCallable, Category = "FairyGUI") float GetRotation() const { return Rotation; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetRotation(float InRotation); UFUNCTION(BlueprintCallable, Category = "FairyGUI") float GetAlpha() const { return Alpha; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetAlpha(float InAlpha); UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool IsGrayed() const { return bGrayed; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetGrayed(bool bInGrayed); UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool IsVisible() const { return bVisible; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetVisible(bool bInVisible); UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool IsTouchable() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetTouchable(bool bInTouchable); UFUNCTION(BlueprintCallable, Category = "FairyGUI") int32 GetSortingOrder() const { return SortingOrder; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetSortingOrder(int32 InSortingOrder); UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGGroup* GetGroup() const { return Group.Get(); } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetGroup(UGGroup* InGroup); UFUNCTION(BlueprintCallable, Category = "FairyGUI") virtual const FString& GetText() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") virtual void SetText(const FString& InText); UFUNCTION(BlueprintCallable, Category = "FairyGUI") virtual const FString& GetIcon() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") virtual void SetIcon(const FString& InIcon); UFUNCTION(BlueprintCallable, Category = "FairyGUI") const FString& GetTooltips() const { return Tooltips; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetTooltips(const FString& InTooltips); UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool IsDraggable() const { return bDraggable; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetDraggable(bool bInDraggable); UFUNCTION(BlueprintCallable, Category = "FairyGUI") FBox2D GetDragBounds() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetDragBounds(const FBox2D& InBounds); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void StartDrag(int32 UserIndex, int32 PointerIndex); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void StopDrag(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") FString GetResourceURL() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") FString GetResourceName() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") FString GetPackageName() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") FVector2D GlobalToLocal(const FVector2D& InPoint); UFUNCTION(BlueprintCallable, Category = "FairyGUI") FBox2D GlobalToLocalRect(const FBox2D& InRect); UFUNCTION(BlueprintCallable, Category = "FairyGUI") FVector2D RootToLocal(const FVector2D& InPoint); UFUNCTION(BlueprintCallable, Category = "FairyGUI") FBox2D RootToLocalRect(const FBox2D& InRect); UFUNCTION(BlueprintCallable, Category = "FairyGUI") FVector2D LocalToGlobal(const FVector2D& InPoint); UFUNCTION(BlueprintCallable, Category = "FairyGUI") FBox2D LocalToGlobalRect(const FBox2D& InRect); UFUNCTION(BlueprintCallable, Category = "FairyGUI") FVector2D LocalToRoot(const FVector2D& InPoint); UFUNCTION(BlueprintCallable, Category = "FairyGUI") FBox2D LocalToRootRect(const FBox2D& InRect); const TSharedPtr& GetRelations() { return Relations; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void AddRelation(UGObject* Obj, ERelationType RelationType, bool bUsePercent = false); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void RemoveRelation(UGObject* Obj, ERelationType RelationType); const TSharedPtr& GetGear(int32 Index); bool CheckGearController(int32 Index, UGController* Controller); uint32 AddDisplayLock(); void ReleaseDisplayLock(uint32 Token); UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGComponent* GetParent() const { return Parent.Get(); } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetParent(UGObject* InParent); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetParentToRoot(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGRoot* GetUIRoot() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") UFairyApplication* GetApp() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool OnStage() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void RemoveFromParent(); UFUNCTION(BlueprintCallable, Category = "FairyGUI", meta = (DeterminesOutputType = "ClassType")) UGObject* CastTo(TSubclassOf ClassType) const; template T* As() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGTreeNode* GetTreeNode() const { return TreeNode; } TSharedPtr GetPackageItem() const { return PackageItem; } TSharedRef GetDisplayObject() const { return DisplayObject.ToSharedRef(); } virtual IHitTest* GetHitArea() const { return nullptr; } template T GetProp(EObjectPropID PropID) const; virtual FNVariant GetProp(EObjectPropID PropID) const; virtual void SetProp(EObjectPropID PropID, const FNVariant& InValue); virtual void ConstructFromResource(); public: bool DispatchEvent(const FName& EventType, const FNVariant& Data = FNVariant::Null); bool HasEventListener(const FName& EventType) const; void InvokeEventDelegate(UEventContext* Context); FGUIEventMDelegate& On(const FName& EventType); FSimpleMulticastDelegate& OnPositionChanged() { return OnPositionChangedEvent; } FSimpleMulticastDelegate& OnSizeChanged() { return OnSizeChangedEvent; } UPROPERTY(BlueprintAssignable, Category = "FairyGUI|Event") FGUIEventDynMDelegate OnClick; UPROPERTY(BlueprintAssignable, Category = "FairyGUI|Event") FGUIEventDynMDelegate OnTouchBegin; UPROPERTY(BlueprintAssignable, Category = "FairyGUI|Event") FGUIEventDynMDelegate OnTouchMove; UPROPERTY(BlueprintAssignable, Category = "FairyGUI|Event") FGUIEventDynMDelegate OnTouchEnd; UPROPERTY(BlueprintAssignable, Category = "FairyGUI|Event") FGUIEventDynMDelegate OnRollOver; UPROPERTY(BlueprintAssignable, Category = "FairyGUI|Event") FGUIEventDynMDelegate OnRollOut; UPROPERTY(BlueprintAssignable, Category = "FairyGUI|Event") FGUIEventDynMDelegate OnDragStart; UPROPERTY(BlueprintAssignable, Category = "FairyGUI|Event") FGUIEventDynMDelegate OnDragMove; UPROPERTY(BlueprintAssignable, Category = "FairyGUI|Event") FGUIEventDynMDelegate OnDragEnd; UPROPERTY(BlueprintAssignable, Category = "FairyGUI|Event") FGUIEventDynMDelegate OnGearStop; UPROPERTY(BlueprintAssignable, Category = "FairyGUI|Event") FGUIEventDynMDelegate OnAddedToStage; UPROPERTY(BlueprintAssignable, Category = "FairyGUI|Event") FGUIEventDynMDelegate OnRemovedFromStage; public: UPROPERTY(Transient, BlueprintReadOnly, Category = "FairyGUI") FString ID; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") FString Name; UPROPERTY(Transient, BlueprintReadOnly, Category = "FairyGUI") FVector2D SourceSize; UPROPERTY(Transient, BlueprintReadOnly, Category = "FairyGUI") FVector2D InitSize; UPROPERTY(Transient, BlueprintReadWrite, Category = "FairyGUI") FVector2D MinSize; UPROPERTY(Transient, BlueprintReadWrite, Category = "FairyGUI") FVector2D MaxSize; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") FNVariant UserData; bool bUnderConstruct; bool bGearLocked; UFUNCTION(BlueprintCallable, Category = "FairyGUI") static UGObject* GetDraggingObject() { return DraggingObject.Get(); } public: virtual UWorld* GetWorld() const override; protected: TWeakObjectPtr Parent; TSharedPtr DisplayObject; TSharedPtr PackageItem; virtual void HandleSizeChanged(); virtual void HandleGrayedChanged(); virtual void HandlePositionChanged(); virtual void HandleControllerChanged(UGController* Controller); virtual void HandleAlphaChanged(); virtual void HandleVisibleChanged(); virtual void SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos); virtual void SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos); void UpdateGear(int32 Index); void CheckGearDisplay(); void SetSizeDirectly(const FVector2D& InSize); FVector2D Position; FVector2D Size; FVector2D RawSize; FVector2D Pivot; FVector2D Scale; FVector2D Skew; uint8 bPivotAsAnchor : 1; float Alpha; float Rotation; uint8 bVisible : 1; uint8 bGrayed : 1; private: bool InternalVisible() const; bool InternalVisible2() const; bool InternalVisible3() const; void UpdateGearFromRelations(int32 Index, const FVector2D& Delta); void UpdateTransform(); UFUNCTION() void OnRollOverHandler(UEventContext* Context); UFUNCTION() void OnRollOutHandler(UEventContext* Context); void InitDrag(); void DragBegin(int32 UserIndex, int32 PointerIndex); void DragEnd(); UFUNCTION() void OnTouchBeginHandler(UEventContext* Context); UFUNCTION() void OnTouchMoveHandler(UEventContext* Context); UFUNCTION() void OnTouchEndHandler(UEventContext* Context); uint8 bInternalVisible : 1; uint8 bHandlingController : 1; uint8 bDraggable : 1; int32 SortingOrder; FString Tooltips; TWeakObjectPtr Group; float SizePercentInGroup; TSharedPtr Relations; TSharedPtr Gears[10]; FVector2D DragTouchStartPos; TOptional DragBounds; uint8 bDragTesting : 1; UGTreeNode* TreeNode; UFairyApplication* CachedApp; struct FUnifiedEventDelegate { FGUIEventMDelegate Func; FGUIEventDynMDelegate* DynFunc; }; TMap EventDelegates; FUnifiedEventDelegate& GetEventDelegate(const FName& EventType); FSimpleMulticastDelegate OnPositionChangedEvent; FSimpleMulticastDelegate OnSizeChangedEvent; static TWeakObjectPtr DraggingObject; static FVector2D GlobalDragStart; static FBox2D GlobalRect; static bool bUpdateInDragging; friend class UGComponent; friend class UGGroup; friend class FRelationItem; friend class FUIObjectFactory; friend class UGTree; }; template inline T* UGObject::As() const { return const_cast(Cast(this)); } template inline T UGObject::GetProp(EObjectPropID PropID) const { return GetProp(PropID).As(); } ================================================ FILE: Source/FairyGUI/Public/UI/GObjectPool.h ================================================ #pragma once #include "CoreMinimal.h" #include "UObject/NoExportTypes.h" class UGObject; class FGObjectPool : public FGCObject { public: UGObject* GetObject(const FString& URL, UObject* WorldContextObject); void ReturnObject(UGObject* Obj); virtual void AddReferencedObjects(FReferenceCollector& Collector) override; private: TMap> Pool; }; ================================================ FILE: Source/FairyGUI/Public/UI/GProgressBar.h ================================================ #pragma once #include "GComponent.h" #include "GProgressBar.generated.h" UCLASS(BlueprintType, Blueprintable) class FAIRYGUI_API UGProgressBar : public UGComponent { GENERATED_BODY() public: UGProgressBar(); virtual ~UGProgressBar(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") EProgressTitleType GetTitleType() const { return TitleType; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetTitleType(EProgressTitleType InType); UFUNCTION(BlueprintCallable, Category = "FairyGUI") float GetMin() const { return Min; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetMin(float InMin); UFUNCTION(BlueprintCallable, Category = "FairyGUI") float GetMax() const { return Max; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetMax(float InMax); UFUNCTION(BlueprintCallable, Category = "FairyGUI") float GetValue() const { return Value; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetValue(float InValue); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void TweenValue(float InValue, float Duration); void Update(float NewValue); protected: virtual void HandleSizeChanged() override; virtual void ConstructExtension(FByteBuffer* Buffer); virtual void SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos) override; bool SetFillAmount(UGObject* Bar, float Amount); private: float Min; float Max; float Value; EProgressTitleType TitleType; bool bReverse; FTweenerHandle TweenHandle; UGObject* TitleObject; UGObject* BarObjectH; UGObject* BarObjectV; FVector2D BarMaxSize; FVector2D BarMaxSizeDelta; FVector2D BarStartPosition; }; ================================================ FILE: Source/FairyGUI/Public/UI/GRichTextField.h ================================================ #pragma once #include "GTextField.h" #include "GRichTextField.generated.h" UCLASS(BlueprintType) class FAIRYGUI_API UGRichTextField : public UGTextField { GENERATED_BODY() public: UGRichTextField(); virtual ~UGRichTextField(); UPROPERTY(BlueprintAssignable, Category = "FairyGUI|Event") FGUIEventDynMDelegate OnClickLink; protected: }; ================================================ FILE: Source/FairyGUI/Public/UI/GRoot.h ================================================ #pragma once #include "GComponent.h" #include "GRoot.generated.h" class UGGraph; class UGWindow; UCLASS(BlueprintType, NotBlueprintable) class FAIRYGUI_API UGRoot : public UGComponent { GENERATED_BODY() public: UFUNCTION(BlueprintPure, Category = "FairyGUI", meta = (DisplayName = "Get UI Root", WorldContext = "WorldContextObject")) static UGRoot* Get(UObject* WorldContextObject); static int32 ContentScaleLevel; UGRoot(); virtual ~UGRoot(); void ShowWindow(UGWindow* Window); void HideWindow(UGWindow* Window); void HideWindowImmediately(UGWindow* Window); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void BringToFront(UGWindow* Window); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void ShowModalWait(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void CloseModalWait(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void CloseAllExceptModals(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void CloseAllWindows(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGWindow* GetTopWindow() const; UGObject* GetModalWaitingPane(); UGGraph* GetModalLayer(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool HasModalWindow() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool IsModalWaiting() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void ShowPopup(UGObject* Popup, UGObject* AtObject, EPopupDirection Direction); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void TogglePopup(UGObject* Popup, UGObject* AtObject = nullptr, EPopupDirection Direction = EPopupDirection::Auto); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void HidePopup(UGObject* Popup = nullptr); UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool HasAnyPopup() const; FVector2D GetPoupPosition(UGObject* Popup, UGObject* AtObject, EPopupDirection Direction); void CheckPopups(SWidget* ClickTarget); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void ShowTooltips(const FString& Text); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void ShowTooltipsWin(UGObject* InTooltipWin); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void HideTooltips(); void AddToViewport(); private: void CreateModalLayer(); void AdjustModalLayer(); void ClosePopup(UGObject* Popup); //void UpdateContentScaleLevel(); void DoShowTooltipsWin(); UPROPERTY(Transient) UGGraph* ModalLayer; UPROPERTY(Transient) UGObject* ModalWaitPane; UPROPERTY(Transient) UGObject* TooltipWin; UPROPERTY(Transient) UGObject* DefaultTooltipWin; TArray> PopupStack; TArray> JustClosedPopups; FTimerHandle ShowTooltipsTimerHandle; friend class UFairyApplication; }; ================================================ FILE: Source/FairyGUI/Public/UI/GScrollBar.h ================================================ #pragma once #include "GComponent.h" #include "GScrollBar.generated.h" class UScrollPane; UCLASS(BlueprintType, Blueprintable) class FAIRYGUI_API UGScrollBar : public UGComponent { GENERATED_BODY() public: UGScrollBar(); virtual ~UGScrollBar(); void SetScrollPane(UScrollPane* Target, bool bVertical); void SetDisplayPerc(float Value); void SetScrollPerc(float Value); float GetMinSize(); bool bGripDragging; protected: virtual void ConstructExtension(FByteBuffer* Buffer); private: void OnTouchBeginHandler(UEventContext* Context); void OnGripTouchBegin(UEventContext* Context); void OnGripTouchMove(UEventContext* Context); void OnGripTouchEnd(UEventContext* Context); void OnArrowButton1Click(UEventContext* Context); void OnArrowButton2Click(UEventContext* Context); UGObject* GripObject; UGObject* ArrowButton1; UGObject* ArrowButton2; UGObject* BarObject; UScrollPane* Target; bool bVertical; float ScrollPerc; bool bFixedGripSize; FVector2D DragOffset; }; ================================================ FILE: Source/FairyGUI/Public/UI/GSlider.h ================================================ #pragma once #include "GComponent.h" #include "GSlider.generated.h" UCLASS(BlueprintType, Blueprintable) class FAIRYGUI_API UGSlider : public UGComponent { GENERATED_BODY() public: UGSlider(); virtual ~UGSlider(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") EProgressTitleType GetTitleType() const { return TitleType; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetTitleType(EProgressTitleType InTitleType); UFUNCTION(BlueprintCallable, Category = "FairyGUI") float GetMin() const { return Min; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetMin(float InMin); UFUNCTION(BlueprintCallable, Category = "FairyGUI") float GetMax() const { return Max; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetMax(float InMax); UFUNCTION(BlueprintCallable, Category = "FairyGUI") float GetValue() const { return Value; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetValue(float InValue); UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool GetWholeNumbers() const { return bWholeNumbers; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetWholeNumbers(bool bWholeNumbers); UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") bool bChangeOnClick; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") bool bCanDrag; UPROPERTY(BlueprintAssignable, Category = "FairyGUI|Event") FGUIEventDynMDelegate OnChanged; protected: virtual void HandleSizeChanged() override; virtual void ConstructExtension(FByteBuffer* Buffer); virtual void SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos) override; void Update(); void UpdateWithPercent(float Percent, bool bManual); private: void OnTouchBeginHandler(UEventContext* Context); void OnGripTouchBegin(UEventContext* Context); void OnGripTouchMove(UEventContext* Context); float Min; float Max; float Value; EProgressTitleType TitleType; bool bReverse; bool bWholeNumbers; UGObject* TitleObject; UGObject* BarObjectH; UGObject* BarObjectV; UGObject* GripObject; FVector2D BarMaxSize; FVector2D BarMaxSizeDelta; FVector2D BarStartPosition; FVector2D ClickPos; float ClickPercent; }; ================================================ FILE: Source/FairyGUI/Public/UI/GTextField.h ================================================ #pragma once #include "GObject.h" #include "Widgets/NTextFormat.h" #include "GTextField.generated.h" UCLASS(BlueprintType) class FAIRYGUI_API UGTextField : public UGObject { GENERATED_BODY() public: UGTextField(); virtual ~UGTextField(); virtual const FString& GetText() const override { return Text; } void SetText(const FString& InText) override; UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool IsUBBEnabled() const { return bUBBEnabled; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") virtual void SetUBBEnabled(bool InEnabled); UFUNCTION(BlueprintCallable, Category = "FairyGUI") EAutoSizeType GetAutoSize() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") virtual void SetAutoSize(EAutoSizeType InAutoSize); UFUNCTION(BlueprintCallable, Category = "FairyGUI") virtual bool IsSingleLine() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") virtual void SetSingleLine(bool InSingleLine); UFUNCTION(BlueprintPure, Category = "FairyGUI") FNTextFormat& GetTextFormat(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetTextFormat(const FNTextFormat& InTextFormat); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void ApplyFormat(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") virtual FVector2D GetTextSize(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGTextField* SetVar(const FString& VarKey, const FString& VarValue); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void FlushVars(); virtual FNVariant GetProp(EObjectPropID PropID) const override; virtual void SetProp(EObjectPropID PropID, const FNVariant& InValue) override; TOptional> TemplateVars; protected: virtual void SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos) override; virtual void SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos) override; void UpdateSize(); FString ParseTemplate(const FString& Template); FString Text; bool bUBBEnabled; bool bFormatApplied; bool bSupportHTML; TSharedPtr Content; }; ================================================ FILE: Source/FairyGUI/Public/UI/GTextInput.h ================================================ #pragma once #include "GObject.h" #include "Widgets/NTextFormat.h" #include "GTextInput.generated.h" UCLASS(BlueprintType) class FAIRYGUI_API UGTextInput : public UGObject { GENERATED_BODY() public: UGTextInput(); virtual ~UGTextInput(); virtual const FString& GetText() const override { return Text; } void SetText(const FString& InText) override; TSharedRef GetInputWidget() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool IsSingleLine() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetSingleLine(bool InSingleLine); UFUNCTION(BlueprintPure, Category = "FairyGUI") FNTextFormat& GetTextFormat() { return TextFormat; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetTextFormat(const FNTextFormat& InTextFormat); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void ApplyFormat(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetPrompt(const FString& InPrompt); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetPassword(bool bInPassword); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetKeyboardType(int32 InKeyboardType); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetMaxLength(int32 InMaxLength); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetRestrict(const FString& InRestrict); UPROPERTY(BlueprintAssignable, Category = "FairyGUI|Event") FGUIEventDynMDelegate OnSubmit; virtual FNVariant GetProp(EObjectPropID PropID) const override; virtual void SetProp(EObjectPropID PropID, const FNVariant& InValue) override; void NotifyTextChanged(const FText& InText); protected: virtual void SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos) override; virtual void SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos) override; FString Text; bool bFormatApplied; FNTextFormat TextFormat; TSharedPtr Content; }; ================================================ FILE: Source/FairyGUI/Public/UI/GTree.h ================================================ #pragma once #include "GList.h" #include "GTreeNode.h" #include "GTree.generated.h" DECLARE_DELEGATE_TwoParams(FTreeNodeRenderer, UGTreeNode*, UGComponent*); DECLARE_DELEGATE_TwoParams(FOnTreeNodeWillExpand, UGTreeNode*, bool); DECLARE_DYNAMIC_DELEGATE_TwoParams(FDynTreeNodeRenderer, UGTreeNode*, Node, UGComponent*, Obj); DECLARE_DYNAMIC_DELEGATE_TwoParams(FDynOnTreeNodeWillExpand, UGTreeNode*, Node, bool, bToExpand); UCLASS(BlueprintType) class FAIRYGUI_API UGTree : public UGList { GENERATED_BODY() public: UGTree(); virtual ~UGTree(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGTreeNode* GetRootNode() const { return RootNode; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGTreeNode* GetSelectedNode() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void GetSelectedNodes(TArray& Result) const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SelectNode(UGTreeNode* Node, bool bScrollItToView = false); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void UnselectNode(UGTreeNode* Node); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void ExpandAll(UGTreeNode* Node); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void CollapseAll(UGTreeNode* Node); void SetTreeNodeRenderer(const FTreeNodeRenderer& InDelegate) { TreeNodeRenderer = InDelegate; } void SetOnTreeNodeWillExpand(const FOnTreeNodeWillExpand& InDelegate) { OnTreeNodeWillExpand = InDelegate; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetTreeNodeRenderer(const FDynTreeNodeRenderer& InDelegate) { if (InDelegate.IsBound()) TreeNodeRenderer = FTreeNodeRenderer::CreateUFunction(const_cast(InDelegate.GetUObject()), InDelegate.GetFunctionName()); else TreeNodeRenderer.Unbind(); } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetOnTreeNodeWillExpand(const FDynOnTreeNodeWillExpand& InDelegate) { if (InDelegate.IsBound()) OnTreeNodeWillExpand = FOnTreeNodeWillExpand::CreateUFunction(const_cast(InDelegate.GetUObject()), InDelegate.GetFunctionName()); else OnTreeNodeWillExpand.Unbind(); } UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") int32 Indent; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") int32 ClickToExpand; protected: virtual void SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos) override; virtual void ReadItems(FByteBuffer* Buffer) override; virtual void DispatchItemEvent(UGObject* Obj, UEventContext* Context) override; private: void CreateCell(UGTreeNode* Node); void AfterInserted(UGTreeNode* Node); int32 GetInsertIndexForNode(UGTreeNode* Node); void AfterRemoved(UGTreeNode* Node); void AfterExpanded(UGTreeNode* Node); void AfterCollapsed(UGTreeNode* Node); void AfterMoved(UGTreeNode* Node); int32 CheckChildren(UGTreeNode* FolderNode, int32 Index); void HideFolderNode(UGTreeNode* FolderNode); void RemoveNode(UGTreeNode* Node); int32 GetFolderEndIndex(int32 StartIndex, int32 Level); UFUNCTION() void OnCellTouchBegin(UEventContext* Context); void OnExpandedStateChanged(UGController* Controller); UPROPERTY() UGTreeNode* RootNode; bool bExpandedStatusInEvt; FTreeNodeRenderer TreeNodeRenderer; FOnTreeNodeWillExpand OnTreeNodeWillExpand; friend class UGTreeNode; }; ================================================ FILE: Source/FairyGUI/Public/UI/GTreeNode.h ================================================ #pragma once #include "CoreMinimal.h" #include "UObject/NoExportTypes.h" #include "Utils/NVariant.h" #include "GTreeNode.generated.h" class UGComponent; class UGTree; UCLASS(BlueprintType, Blueprintable) class FAIRYGUI_API UGTreeNode : public UObject { GENERATED_BODY() public: UFUNCTION(BlueprintCallable, Category = "FairyGUI", meta = (DisplayName = "Create Tree Node")) static UGTreeNode* CreateNode(bool bIsFolder = false, const FString& ResourceURL = ""); UGTreeNode(); virtual ~UGTreeNode(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGTreeNode* GetParent() const { return Parent.Get(); } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetParent(UGTreeNode* InParent); UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGTree* GetTree() const { return Tree.Get(); } UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGComponent* GetCell() const { return Cell; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool IsExpanded() const { return bExpanded; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetExpaned(bool bInExpanded); UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool IsFolder() const { return bIsFolder; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") const FString& GetText() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetText(const FString& InText); UFUNCTION(BlueprintCallable, Category = "FairyGUI") const FString& GetIcon() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetIcon(const FString& InIcon); UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGTreeNode* AddChild(UGTreeNode* Child); UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGTreeNode* AddChildAt(UGTreeNode* Child, int32 Index); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void RemoveChild(UGTreeNode* Child); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void RemoveChildAt(int32 Index); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void RemoveChildren(int32 BeginIndex = 0, int32 EndIndex = -1); UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGTreeNode* GetChildAt(int32 Index) const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGTreeNode* GetPrevSibling() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGTreeNode* GetNextSibling() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") int32 GetChildIndex(const UGTreeNode* Child) const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetChildIndex(UGTreeNode* Child, int32 Index); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SwapChildren(UGTreeNode* Child, UGTreeNode* Child2); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SwapChildrenAt(int32 Index1, int32 Index2); UFUNCTION(BlueprintCallable, Category = "FairyGUI") int32 NumChildren() const; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") FNVariant UserData; private: int32 MoveChild(UGTreeNode* Child, int32 OldIndex, int32 Index); void SetTree(UGTree* InTree); TWeakObjectPtr Tree; TWeakObjectPtr Parent; UPROPERTY() UGComponent* Cell; UPROPERTY() TArray Children; int32 Level; bool bExpanded; bool bIsFolder; FString ResourceURL; friend class UGTree; }; ================================================ FILE: Source/FairyGUI/Public/UI/GWindow.h ================================================ #pragma once #include "GComponent.h" #include "GWindow.generated.h" class FAIRYGUI_API IUISource { public: virtual const FString& GetFileName() = 0; virtual void SetFileName(const FString& InFileName) = 0; virtual bool IsLoaded() = 0; virtual void Load(FSimpleDelegate Callback) = 0; }; DECLARE_DYNAMIC_DELEGATE_OneParam(FWindowDynDelegate, class UGWindow*, Window); UCLASS(BlueprintType, Blueprintable) class FAIRYGUI_API UGWindow : public UGComponent { GENERATED_BODY() public: UFUNCTION(BlueprintCallable, Category = "FairyGUI", meta = (WorldContext = "WorldContextObject")) static UGWindow* CreateWindow(const FString& PackageName, const FString& ResourceName, UObject* WorldContextObject); UGWindow(); virtual ~UGWindow(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void Show(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void Hide(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void HideImmediately(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void ToggleStatus(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void BringToFront(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool IsShowing() const { return Parent.IsValid(); } UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool IsTop() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool IsModal() const { return bModal; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetModal(bool bInModal) { bModal = bInModal; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void ShowModalWait(int32 InRequestingCmd = 0); UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool CloseModalWait(int32 InRequestingCmd = 0); void Init(); void AddUISource(TSharedPtr UISource); UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGComponent* GetContentPane() const { return ContentPane; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetContentPane(UGComponent* Obj); UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGComponent* GetFrame() const { return FrameObject; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGObject* GetCloseButton() const { return CloseButton; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetCloseButton(UGObject* Obj); UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGObject* GetDragArea() const { return DragArea; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetDragArea(UGObject* Obj); UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGObject* GetContentArea() const { return ContentArea; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetContentArea(UGObject* Obj) { ContentArea = Obj; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGObject* GetModalWaitingPane() const { return ModalWaitPane; } virtual void OnShown(); virtual void OnHide(); UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") bool bBringToFontOnClick; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") FWindowDynDelegate InitCallback; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") FWindowDynDelegate ShownCallback; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") FWindowDynDelegate HideCallback; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") FWindowDynDelegate ShowingCallback; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") FWindowDynDelegate HidingCallback; protected: virtual void OnInit(); virtual void DoShowAnimation(); virtual void DoHideAnimation(); UFUNCTION() void CloseEventHandler(UEventContext* Context); UPROPERTY(Transient) UGComponent* ContentPane; private: void LayoutModalWaitPane(); void OnUILoadComplete(); void InternalInit(); void OnTouchBeginHandler(UEventContext* Context); UFUNCTION() void OnDragStartHandler(UEventContext* Context); void OnAddedToStageHandler(UEventContext* Context); void OnRemovedFromStageHandler(UEventContext* Context); UPROPERTY(Transient) UGObject* ModalWaitPane; UPROPERTY(Transient) UGComponent* FrameObject; UPROPERTY(Transient) UGObject* CloseButton; UPROPERTY(Transient) UGObject* DragArea; UPROPERTY(Transient) UGObject* ContentArea; int32 RequestingCmd; TArray> UISources; uint8 bModal : 1; uint8 bInited : 1; uint8 bLoading : 1; }; ================================================ FILE: Source/FairyGUI/Public/UI/Gears/GearAnimation.h ================================================ #pragma once #include "GearBase.h" class FAIRYGUI_API FGearAnimation : public FGearBase { public: FGearAnimation(UGObject* InOwner); virtual ~FGearAnimation(); virtual void Apply() override; virtual void UpdateState() override; protected: virtual void AddStatus(const FString& PageID, FByteBuffer* Buffer) override; virtual void Init() override; private: struct FValue { bool bPlaying; int32 Frame; FValue(); }; TMap Storage; FValue Default; }; ================================================ FILE: Source/FairyGUI/Public/UI/Gears/GearBase.h ================================================ #pragma once #include "CoreMinimal.h" #include "Tween/GTween.h" class UGObject; class UGController; class FByteBuffer; class FAIRYGUI_API FGearTweenConfig { public: FGearTweenConfig(); bool bTween; EEaseType EaseType; float Duration; float Delay; uint32 DisplayLockToken; FTweenerHandle Handle; }; class FGearBase { public: enum class EType { Display, XY, Size, Look, Color, Animation, Text, Icon, Display2, FontSize }; FGearBase(UGObject* InOwner); virtual ~FGearBase(); EType GetType() const { return Type; } UGController* GetController() const { return Controller; } void SetController(UGController* InController); FGearTweenConfig& GetTweenConfig(); virtual void UpdateFromRelations(const FVector2D& Delta); virtual void Apply(); virtual void UpdateState(); void Setup(FByteBuffer* Buffer); static TSharedPtr Create(UGObject* InOwner, EType InType); static bool bDisableAllTweenEffect; protected: virtual void AddStatus(const FString& PageID, FByteBuffer* Buffer); virtual void Init(); EType Type; UGObject* Owner; UGController* Controller; TOptional TweenConfig; }; ================================================ FILE: Source/FairyGUI/Public/UI/Gears/GearColor.h ================================================ #pragma once #include "GearBase.h" class FAIRYGUI_API FGearColor : public FGearBase { public: FGearColor(UGObject* InOwner); virtual ~FGearColor(); virtual void Apply() override; virtual void UpdateState() override; protected: virtual void AddStatus(const FString& PageID, FByteBuffer* Buffer) override; virtual void Init() override; private: void OnTweenUpdate(FGTweener* Tweener); void OnTweenComplete(); struct FValue { public: FColor Color; FColor OutlineColor; FValue(); }; TMap Storage; FValue Default; }; ================================================ FILE: Source/FairyGUI/Public/UI/Gears/GearDisplay.h ================================================ #pragma once #include "GearBase.h" class FAIRYGUI_API FGearDisplay : public FGearBase { public: FGearDisplay(UGObject* InOwner); virtual ~FGearDisplay(); virtual void Apply() override; virtual void UpdateState() override; uint32 AddLock(); void ReleaseLock(uint32 Token); bool IsConnected(); TArray Pages; protected: virtual void AddStatus(const FString& PageID, FByteBuffer* Buffer) override; virtual void Init() override; private: int32 Visible; uint32 DisplayLockToken; }; ================================================ FILE: Source/FairyGUI/Public/UI/Gears/GearDisplay2.h ================================================ #pragma once #include "GearBase.h" class FAIRYGUI_API FGearDisplay2 : public FGearBase { public: FGearDisplay2(UGObject* InOwner); virtual ~FGearDisplay2(); virtual void Apply() override; virtual void UpdateState() override; bool Evaluate(bool bConnected); TArray Pages; int32 Condition; protected: virtual void AddStatus(const FString& pageID, FByteBuffer* Buffer) override; virtual void Init() override; private: int32 Visible; }; ================================================ FILE: Source/FairyGUI/Public/UI/Gears/GearFontSize.h ================================================ #pragma once #include "GearBase.h" class FAIRYGUI_API FGearFontSize : public FGearBase { public: FGearFontSize(UGObject* InOwner); virtual ~FGearFontSize(); virtual void Apply() override; virtual void UpdateState() override; protected: virtual void AddStatus(const FString& PageID, FByteBuffer* Buffer) override; virtual void Init() override; private: TMap Storage; int32 Default; }; ================================================ FILE: Source/FairyGUI/Public/UI/Gears/GearIcon.h ================================================ #pragma once #include "GearBase.h" class FAIRYGUI_API FGearIcon : public FGearBase { public: FGearIcon(UGObject* InOwner); virtual ~FGearIcon(); virtual void Apply() override; virtual void UpdateState() override; protected: virtual void AddStatus(const FString& PageID, FByteBuffer* Buffer) override; virtual void Init() override; private: TMap Storage; FString Default; }; ================================================ FILE: Source/FairyGUI/Public/UI/Gears/GearLook.h ================================================ #pragma once #include "GearBase.h" class FAIRYGUI_API FGearLook : public FGearBase { public: FGearLook(UGObject* InOwner); virtual ~FGearLook(); virtual void Apply() override; virtual void UpdateState() override; protected: virtual void AddStatus(const FString& PageID, FByteBuffer* Buffer) override; virtual void Init() override; private: void OnTweenUpdate(FGTweener* Tweener); void OnTweenComplete(); struct FValue { float Alpha; float Rotation; bool bGrayed; bool bTouchable; FValue(); }; TMap Storage; FValue Default; }; ================================================ FILE: Source/FairyGUI/Public/UI/Gears/GearSize.h ================================================ #pragma once #include "GearBase.h" class FAIRYGUI_API FGearSize : public FGearBase { public: FGearSize(UGObject* InOwner); virtual ~FGearSize(); virtual void Apply() override; virtual void UpdateState() override; virtual void UpdateFromRelations(const FVector2D& Delta) override; protected: virtual void AddStatus(const FString& PageID, FByteBuffer* Buffer) override; virtual void Init() override; private: void OnTweenUpdate(FGTweener* Tweener); void OnTweenComplete(); TMap Storage; FVector4 Default; }; ================================================ FILE: Source/FairyGUI/Public/UI/Gears/GearText.h ================================================ #pragma once #include "GearBase.h" class FAIRYGUI_API FGearText : public FGearBase { public: FGearText(UGObject* InOwner); virtual ~FGearText(); virtual void Apply() override; virtual void UpdateState() override; protected: virtual void AddStatus(const FString& PageID, FByteBuffer* Buffer) override; virtual void Init() override; private: TMap Storage; FString Default; }; ================================================ FILE: Source/FairyGUI/Public/UI/Gears/GearXY.h ================================================ #pragma once #include "GearBase.h" class FAIRYGUI_API FGearXY : public FGearBase { public: FGearXY(UGObject* InOwner); virtual ~FGearXY(); virtual void Apply() override; virtual void UpdateState() override; virtual void UpdateFromRelations(const FVector2D& Delta) override; bool bPositionsInPercent; void AddExtStatus(const FString& PageID, FByteBuffer* Buffer); protected: virtual void AddStatus(const FString& PageID, FByteBuffer* Buffer) override; virtual void Init() override; private: void OnTweenUpdate(FGTweener* Tweener); void OnTweenComplete(); TMap Storage; FVector4 Default; }; ================================================ FILE: Source/FairyGUI/Public/UI/PackageItem.h ================================================ #pragma once #include "CoreMinimal.h" #include "Engine/Texture2D.h" #include "FieldTypes.h" #include "Engine.h" #include "FairyCommons.h" #include "Widgets/HitTest.h" class FByteBuffer; struct FMovieClipData; struct FBitmapFont; class UUIPackage; class UNTexture; class UGComponent; class FAIRYGUI_API FPackageItem : public FGCObject, public TSharedFromThis { public: FPackageItem(); void Load(); TSharedPtr GetBranch(); TSharedPtr GetHighResolution(); virtual void AddReferencedObjects(FReferenceCollector& Collector) override; public: UUIPackage* Owner; EPackageItemType Type; EObjectType ObjectType; FString ID; FString Name; FVector2D Size; FString File; TSharedPtr RawData; TOptional> Branches; TOptional> HighResolution; //atlas UNTexture* Texture; //image TOptional Scale9Grid; bool bScaleByTile; int32 TileGridIndice; TSharedPtr PixelHitTestData; //movie clip TSharedPtr MovieClipData; //component FGComponentCreator ExtensionCreator; bool bTranslated; //font TSharedPtr BitmapFont; //sound TSharedPtr Sound; }; ================================================ FILE: Source/FairyGUI/Public/UI/PopupMenu.h ================================================ #pragma once #include "GList.h" #include "GButton.h" #include "PopupMenu.generated.h" UCLASS(BlueprintType) class FAIRYGUI_API UPopupMenu : public UObject { GENERATED_BODY() public: UFUNCTION(BlueprintCallable, Category = "FairyGUI", meta = (WorldContext = "WorldContextObject")) static UPopupMenu* CreatePopupMenu(const FString& ResourceURL, UObject* WorldContextObject); static UPopupMenu* CreatePopupMenu(UObject* WorldContextObject) { return CreatePopupMenu("", WorldContextObject); } UPopupMenu(); virtual ~UPopupMenu(); UGButton* AddItem(const FString& Caption, FGUIEventDelegate Callback); UFUNCTION(BlueprintCallable, Category = "FairyGUI", meta = (AutoCreateRefTerm = "Callback")) UGButton* AddItem(const FString& Caption, const FGUIEventDynDelegate& Callback); UGButton* AddItemAt(const FString& Caption, int32 index, FGUIEventDelegate Callback); UFUNCTION(BlueprintCallable, Category = "FairyGUI", meta = (AutoCreateRefTerm = "Callback")) UGButton* AddItemAt(const FString& Caption, int32 index, const FGUIEventDynDelegate& Callback); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void AddSeperator(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") const FString& GetItemName(int32 Index) const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetItemText(const FString& Name, const FString& Caption); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetItemVisible(const FString& Name, bool bVisible); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetItemGrayed(const FString& Name, bool bGrayed); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetItemCheckable(const FString& Name, bool bCheckable); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetItemChecked(const FString& Name, bool bCheck); UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool IsItemChecked(const FString& Name) const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool RemoveItem(const FString& Name); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void ClearItems(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") int32 GetItemCount() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGComponent* GetContentPane() const { return ContentPane; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGList* GetList() const { return List; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void Show(UGObject* AtObject, EPopupDirection Dir = EPopupDirection::Auto); protected: void Create(const FString& ResourceURL); UPROPERTY(Transient) UGComponent* ContentPane; UGList* List; private: void OnClickItem(UEventContext* Context); void OnAddedToStage(UEventContext* Context); static const FName ClickMenu; }; ================================================ FILE: Source/FairyGUI/Public/UI/RelationItem.h ================================================ #pragma once #include "CoreMinimal.h" #include "FieldTypes.h" class UGObject; struct FAIRYGUI_API FRelationDef { bool bPercent; ERelationType Type; int32 Axis; FRelationDef() : bPercent(false), Type(ERelationType::Left_Left), Axis(0) {} }; class FAIRYGUI_API FRelationItem { public: FRelationItem(UGObject* InOwner); ~FRelationItem(); UGObject* GetTarget() const { return Target.Get(); } void SetTarget(UGObject* InTarget); void Add(ERelationType RelationType, bool bUsePercent); void InternalAdd(ERelationType RelationType, bool bUsePercent); void Remove(ERelationType RelationType); void CopyFrom(const FRelationItem& Source); bool IsEmpty() const; void ApplyOnSelfSizeChanged(float DeltaWidth, float DeltaHeight, bool bApplyPivot); private: void ApplyOnXYChanged(UGObject* InTarget, const FRelationDef& info, float dx, float dy); void ApplyOnSizeChanged(UGObject* InTarget, const FRelationDef& info); void AddRefTarget(UGObject* InTarget); void ReleaseRefTarget(); void OnTargetXYChanged(); void OnTargetSizeChanged(); UGObject* Owner; TWeakObjectPtr Target; TArray Defs; FVector4 TargetData; FDelegateHandle PositionDelegateHandle; FDelegateHandle SizeDelegateHandle; }; ================================================ FILE: Source/FairyGUI/Public/UI/Relations.h ================================================ #pragma once #include "CoreMinimal.h" #include "UObject/NoExportTypes.h" #include "RelationItem.h" class UGObject; class FByteBuffer; class FAIRYGUI_API FRelations { public: FRelations(UGObject* InOwner); ~FRelations(); void Add(UGObject* InTarget, ERelationType RelationType); void Add(UGObject* InTarget, ERelationType RelationType, bool bUsePercent); void Remove(UGObject* InTarget, ERelationType RelationType); bool Contains(UGObject* InTarget); void ClearFor(UGObject* InTarget); void ClearAll(); void CopyFrom(const FRelations& Source); void OnOwnerSizeChanged(const FVector2D& Delta, bool bApplyPivot); bool IsEmpty() const; void Setup(FByteBuffer* Buffer, bool bParentToChild); UGObject* Handling; private: UGObject* Owner; TIndirectArray Items; }; ================================================ FILE: Source/FairyGUI/Public/UI/ScrollPane.h ================================================ #pragma once #include "CoreMinimal.h" #include "Styling/SlateTypes.h" #include "FieldTypes.h" #include "Tween/GTween.h" #include "Event/EventContext.h" #include "ScrollPane.generated.h" class UGObject; class UGComponent; class UGScrollBar; class UGController; class FByteBuffer; class FGTweener; class SContainer; UCLASS(BlueprintType) class FAIRYGUI_API UScrollPane : public UObject { GENERATED_BODY() public: UScrollPane(); ~UScrollPane(); void Setup(FByteBuffer* Buffer); UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGComponent* GetHeader() const { return Header; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGComponent* GetFooter() const { return Footer; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGScrollBar* GetVtScrollBar() const { return VtScrollBar; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") UGScrollBar* GetHzScrollBar() const { return HzScrollBar; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") float GetPosX() const { return XPos; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetPosX(float Value, bool bAnimation = false); UFUNCTION(BlueprintCallable, Category = "FairyGUI") float GetPosY() const { return YPos; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetPosY(float Value, bool bAnimation = false); UFUNCTION(BlueprintCallable, Category = "FairyGUI") float GetPercX() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetPercX(float Value, bool bAnimation = false); UFUNCTION(BlueprintCallable, Category = "FairyGUI") float GetPercY() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetPercY(float Value, bool bAnimation = false); UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool IsBottomMost() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool IsRightMost() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void ScrollLeft(float Ratio = 1, bool bAnimation = false); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void ScrollRight(float Ratio = 1, bool bAnimation = false); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void ScrollUp(float Ratio = 1, bool bAnimation = false); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void ScrollDown(float Ratio = 1, bool bAnimation = false); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void ScrollTop(bool bAnimation = false); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void ScrollBottom(bool bAnimation = false); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void ScrollToView(UGObject* Obj, bool bAnimation = false, bool bSetFirst = false); void ScrollToView(const FBox2D& Rect, bool bAnimation = false, bool bSetFirst = false); UFUNCTION(BlueprintCallable, Category = "FairyGUI") bool IsChildInView(UGObject* Obj) const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") int32 GetPageX() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetPageX(int32 PageX, bool bAnimation = false); UFUNCTION(BlueprintCallable, Category = "FairyGUI") int32 GetPageY() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetPageY(int32 PageY, bool bAnimation = false); UFUNCTION(BlueprintCallable, Category = "FairyGUI") float GetScrollingPosX() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") float GetScrollingPosY() const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") const FVector2D& GetContentSize() const { return ContentSize; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") const FVector2D& GetViewSize() const { return ViewSize; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void LockHeader(int32 Size); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void LockFooter(int32 Size); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void CancelDragging(); static UScrollPane* GetDraggingPane() { return DraggingPane.Get(); } UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") uint8 bBouncebackEffect : 1; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") uint8 bTouchEffect : 1; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") uint8 bInertiaDisabled : 1; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") uint8 bMouseWheelEnabled : 1; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") uint8 bSnapToItem : 1; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") uint8 bPageMode : 1; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") float DecelerationRate; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") float ScrollStep; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") UGController* PageController; private: void OnOwnerSizeChanged(); void AdjustMaskContainer(); void SetContentSize(const FVector2D& InSize); void ChangeContentSizeOnScrolling(float DeltaWidth, float DeltaHeight, float DeltaPosX, float DeltaPosY); void SetViewWidth(float Width); void SetViewHeight(float Height); void SetSize(const FVector2D& InSize); void HandleSizeChanged(); void HandleControllerChanged(UGController* Controller); void UpdatePageController(); void PosChanged(bool bAnimation); void Refresh(); void Refresh2(); void UpdateScrollBarPos(); void UpdateScrollBarVisible(); void UpdateScrollBarVisible2(UGScrollBar* Bar); float GetLoopPartSize(float Division, int32 Axis); bool LoopCheckingCurrent(); void LoopCheckingTarget(FVector2D& EndPos); void LoopCheckingTarget(FVector2D& EndPos, int32 Axis); void LoopCheckingNewPos(float& Value, int32 Axis); void AlignPosition(FVector2D& Pos, bool bInertialScrolling); float AlignByPage(float Pos, int32 Axis, bool bInertialScrolling); FVector2D UpdateTargetAndDuration(const FVector2D& OrignPos); float UpdateTargetAndDuration(float Pos, int32 Axis); void FixDuration(int32 Axis, float DldChange); void StartTween(int32 Type); void KillTween(); void TweenUpdate(); float RunTween(int32 Axis, float Delta); void CheckRefreshBar(); void OnTouchBegin(UEventContext* Context); void OnTouchMove(UEventContext* Context); void OnTouchEnd(UEventContext* Context); void OnMouseWheel(UEventContext* Context); void OnRollOver(UEventContext* Context); void OnRollOut(UEventContext* Context); void OnBarTweenComplete(FGTweener* Tweener); private: UGComponent* Owner; TSharedPtr MaskContainer; TSharedPtr Container; UPROPERTY(Transient) UGScrollBar* HzScrollBar; UPROPERTY(Transient) UGScrollBar* VtScrollBar; UPROPERTY(Transient) UGComponent* Header; UPROPERTY(Transient) UGComponent* Footer; EScrollType ScrollType; FMargin ScrollBarMargin; uint8 bScrollBarDisplayAuto : 1; uint8 bVScrollNone : 1; uint8 bHScrollNone : 1; uint8 bNeedRefresh : 1; int32 RefreshBarAxis; uint8 bDisplayOnLeft : 1; uint8 bDisplayInDemand : 1; uint8 bFloating : 1; uint8 bDontClipMargin : 1; float XPos; float YPos; FVector2D ViewSize; FVector2D ContentSize; FVector2D OverlapSize; FVector2D PageSize; FVector2D ContainerPos; FVector2D BeginTouchPos; FVector2D LastTouchPos; FVector2D LastTouchGlobalPos; FVector2D Velocity; float VelocityScale; float LastMoveTime; uint8 bDragged : 1; uint8 bIsHoldAreaDone : 1; int32 AniFlag; int32 LoopMode; uint8 bHover : 1; float HeaderLockedSize; float FooterLockedSize; uint8 bDispatchingPullDown : 1; uint8 bDispatchingPullUp : 1; int32 Tweening; FVector2D TweenStart; FVector2D TweenChange; FVector2D TweenTime; FVector2D TweenDuration; FTimerHandle RefreshTimerHandle; FTimerHandle TickTimerHandle; static int32 GestureFlag; static TWeakObjectPtr DraggingPane; friend class UGComponent; friend class UGList; friend class UGScrollBar; }; ================================================ FILE: Source/FairyGUI/Public/UI/Transition.h ================================================ #pragma once #include "CoreMinimal.h" #include "Tween/GTween.h" #include "Event/EventContext.h" #include "Transition.generated.h" class UGObject; class UGComponent; class UGController; class FByteBuffer; class FGTweener; struct FTransitionItem; UCLASS(BlueprintType) class FAIRYGUI_API UTransition : public UObject { GENERATED_BODY() public: UTransition(); virtual ~UTransition(); bool IsPlaying() const { return bPlaying; } void Play(const FSimpleDelegate& InCompleteCallback = FSimpleDelegate()) { Play(1, 0, 0, -1, false, InCompleteCallback); } void Play(int32 InTimes, float InDelay, float InStartTime = 0, float InEndTime = -1, const FSimpleDelegate& InCompleteCallback = FSimpleDelegate()) { Play(InTimes, InDelay, InStartTime, InEndTime, false, InCompleteCallback); } UFUNCTION(BlueprintCallable, Category = "FairyGUI", meta = (AutoCreateRefTerm = "InCompleteCallback")) void Play(const FSimpleDynDelegate& InCompleteCallback, int32 InTimes = 1, float InDelay = 0, float InStartTime = 0, float InEndTime = -1) { Play(InTimes, InDelay, InStartTime, InEndTime, false, InCompleteCallback.IsBound() ? FSimpleDelegate::CreateUFunction(const_cast(InCompleteCallback.GetUObject()), InCompleteCallback.GetFunctionName()) : FSimpleDelegate()); } void PlayReverse(const FSimpleDelegate& InCompleteCallback = FSimpleDelegate()) { Play(1, 0, 0, -1, true, InCompleteCallback); } void PlayReverse(int32 InTimes, float InDelay, const FSimpleDelegate& InCompleteCallback = FSimpleDelegate()) { Play(InTimes, InDelay, 0, -1, true, InCompleteCallback); } UFUNCTION(BlueprintCallable, Category = "FairyGUI", meta = (AutoCreateRefTerm = "InCompleteCallback")) void PlayReverse(const FSimpleDynDelegate& InCompleteCallback, int32 InTimes = 1, float InDelay = 0) { Play(InTimes, InDelay, 0, -1, true, InCompleteCallback.IsBound() ? FSimpleDelegate::CreateUFunction(const_cast(InCompleteCallback.GetUObject()), InCompleteCallback.GetFunctionName()) : FSimpleDelegate()); } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void ChangePlayTimes(int32 InTimes); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void Stop(bool bSetToComplete = false, bool bProcessCallback = false); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetAutoPlay(bool bInAutoPlay, int32 InTimes, float InDelay); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetPaused(bool bInPaused); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetValue(const FString& InLabel, const TArray& InValues); void SetHook(const FString& InLabel, FSimpleDelegate Callback); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetHook(const FString& InLabel, FSimpleDynDelegate Callback) { SetHook(InLabel, Callback.IsBound() ? FSimpleDelegate::CreateUFunction(const_cast(Callback.GetUObject()), Callback.GetFunctionName()) : FSimpleDelegate()); } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void ClearHooks(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetTarget(const FString& InLabel, UGObject* InTarget); UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetDuration(const FString& InLabel, float InDuration); UFUNCTION(BlueprintCallable, Category = "FairyGUI") float GetLabelTime(const FString& InLabel) const; UFUNCTION(BlueprintCallable, Category = "FairyGUI") float GetTimeScale() const { return TimeScale; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") void SetTimeScale(float InTimeScale); void UpdateFromRelations(const FString& TargetID, const FVector2D& Delta); void OnOwnerAddedToStage(); void OnOwnerRemovedFromStage(); void Setup(FByteBuffer* Buffer); UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") FString Name; private: void Play(int32 InTimes, float InDelay, float InStartTime, float InEndTime, bool bInReverse, FSimpleDelegate InCompleteCallback); void StopItem(FTransitionItem* Item, bool bSetToComplete); void OnDelayedPlay(); void InternalPlay(); void PlayItem(FTransitionItem* Item); void SkipAnimations(); void OnDelayedPlayItem(FGTweener* Tweener); void OnTweenStart(FGTweener* Tweener); void OnTweenUpdate(FGTweener* Tweener); void OnTweenComplete(FGTweener* Tweener); void OnPlayTransCompleted(FTransitionItem* item); void CallHook(FTransitionItem* Item, bool bTweenEnd); void CheckAllComplete(); void ApplyValue(FTransitionItem* Item); void DecodeValue(FTransitionItem* Item, FByteBuffer* Buffer, struct FTransitionItemData* Value); UGComponent* Owner; TArray Items; int32 TotalTimes; int32 TotalTasks; bool bPlaying; bool bPaused; FVector2D OwnerBasePos; FSimpleDelegate CompleteCallback; int32 Options; bool bReversed; float TotalDuration; bool bAutoPlay; int32 AutoPlayTimes; float AutoPlayDelay; float TimeScale; float StartTime; float EndTime; FTweenerHandle DelayHandle; }; ================================================ FILE: Source/FairyGUI/Public/UI/TranslationHelper.h ================================================ #pragma once #include "CoreMinimal.h" class FPackageItem; class FTranslationHelper { public: static TMap> Strings; static void LoadFromXML(const FString XmlString); static void TranslateComponent(const TSharedPtr& Item); }; ================================================ FILE: Source/FairyGUI/Public/UI/UIConfig.h ================================================ #pragma once #include "CoreMinimal.h" #include "Engine/Texture2D.h" #include "FieldTypes.h" #include "UIConfig.generated.h" USTRUCT(BlueprintType) struct FAIRYGUI_API FUIConfig { GENERATED_USTRUCT_BODY() public: static FUIConfig Config; FUIConfig(); UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") FString DefaultFont; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") FString ButtonSound; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") float ButtonSoundVolumeScale; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") int32 DefaultScrollStep; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") float DefaultScrollDecelerationRate; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") bool DefaultScrollTouchEffect; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") bool DefaultScrollBounceEffect; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") EScrollBarDisplayType DefaultScrollBarDisplay; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") FString VerticalScrollBar; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") FString HorizontalScrollBar; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") int32 TouchDragSensitivity; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") int32 ClickDragSensitivity; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") int32 TouchScrollSensitivity; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") int32 DefaultComboBoxVisibleItemCount; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") FString GlobalModalWaiting; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") FColor ModalLayerColor; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") FString TooltipsWin; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") bool BringWindowToFrontOnClick; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") FString WindowModalWaiting; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") FString PopupMenu; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") FString PopupMenuSeperator; }; ================================================ FILE: Source/FairyGUI/Public/UI/UIObjectFactory.h ================================================ #pragma once #include "CoreMinimal.h" #include "FieldTypes.h" #include "PackageItem.h" class UGComponent; class UGLoader; class UGObject; class FAIRYGUI_API FUIObjectFactory { public: static void SetExtension(const FString& URL, FGComponentCreator Creator); static void SetExtension(const FString& URL, TSubclassOf ClassType); static UGObject* NewObject(const TSharedPtr& PackageItem, UObject* Outer); static UGObject* NewObject(EObjectType Type, UObject* Outer); static void ResolvePackageItemExtension(const TSharedPtr& PackageItem); public: static TMap PackageItemExtensions; static TSubclassOf LoaderExtension; friend class UFGUIPackage; }; ================================================ FILE: Source/FairyGUI/Public/UI/UIPackage.h ================================================ #pragma once #include "CoreMinimal.h" #include "UObject/NoExportTypes.h" #include "UIPackage.generated.h" class FPackageItem; class UGObject; class FByteBuffer; class UUIPackageAsset; UCLASS(BlueprintType) class FAIRYGUI_API UUIPackage : public UObject { GENERATED_BODY() public: UFUNCTION(BlueprintCallable, Category = "FairyGUI") static const FString& GetBranch(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") static void SetBranch(const FString& InBranch); UFUNCTION(BlueprintCallable, Category = "FairyGUI", meta = (DisplayName = "Get UI Global Variable")) static FString GetVar(const FString& VarKey); UFUNCTION(BlueprintCallable, Category = "FairyGUI", meta = (DisplayName = "Set UI Global Variable")) static void SetVar(const FString& VarKey, const FString& VarValue); static UUIPackage* AddPackage(const TCHAR* InAssetPath, UObject* WorldContextObject); UFUNCTION(BlueprintCallable, Category = "FairyGUI", meta = (WorldContext = "WorldContextObject")) static UUIPackage* AddPackage(class UUIPackageAsset* InAsset, UObject* WorldContextObject); UFUNCTION(BlueprintCallable, Category = "FairyGUI", meta = (WorldContext = "WorldContextObject")) static void RemovePackage(const FString& IDOrName, UObject* WorldContextObject); UFUNCTION(BlueprintCallable, Category = "FairyGUI") static void RemoveAllPackages(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") static UUIPackage* GetPackageByID(const FString& PackageID); UFUNCTION(BlueprintCallable, Category = "FairyGUI") static UUIPackage* GetPackageByName(const FString& PackageName); UFUNCTION(BlueprintCallable, Category = "FairyGUI", meta = (DisplayName = "Create UI", DeterminesOutputType = "ClassType", WorldContext = "WorldContextObject")) static UGObject* CreateObject(const FString& PackageName, const FString& ResourceName, UObject* WorldContextObject, TSubclassOf ClassType = nullptr); UFUNCTION(BlueprintCallable, Category = "FairyGUI", meta = (DisplayName = "Create UI From URL", DeterminesOutputType = "ClassType", WorldContext = "WorldContextObject")) static UGObject* CreateObjectFromURL(const FString& URL, UObject* WorldContextObject, TSubclassOf ClassType = nullptr); static FString GetItemURL(const FString& PackageName, const FString& ResourceName); static TSharedPtr GetItemByURL(const FString& URL); static FString NormalizeURL(const FString& URL); static int32 Constructing; public: UFUNCTION(BlueprintCallable, Category = "FairyGUI") static void RegisterFont(const FString& FontFace, UObject* Font); public: UUIPackage(); virtual ~UUIPackage(); UFUNCTION(BlueprintCallable, Category = "FairyGUI") const FString& GetID() const { return ID; } UFUNCTION(BlueprintCallable, Category = "FairyGUI") const FString& GetName() const { return Name; } TSharedPtr GetItem(const FString& ResourceID) const; TSharedPtr GetItemByName(const FString& ResourceName); void* GetItemAsset(const TSharedPtr& Item); UGObject* CreateObject(const FString& ResourceName, UObject* WorldContextObject); UGObject* CreateObject(const TSharedPtr& Item, UObject* WorldContextObject); private: void Load(FByteBuffer* Buffer); void LoadAtlas(const TSharedPtr& Item); void LoadImage(const TSharedPtr& Item); void LoadMovieClip(const TSharedPtr& Item); void LoadFont(const TSharedPtr& Item); void LoadSound(const TSharedPtr& Item); private: FString ID; FString Name; FString AssetPath; UPROPERTY(Transient) UUIPackageAsset* Asset; TArray> Items; TMap> ItemsByID; TMap> ItemsByName; TMap Sprites; FString CustomID; TArray> Dependencies; TArray Branches; int32 BranchIndex; TSet RefWorlds; friend class FPackageItem; friend class UFairyApplication; }; UCLASS(Transient) class FAIRYGUI_API UUIPackageStatic : public UObject { GENERATED_BODY() public: static UUIPackageStatic* Singleton; static UUIPackageStatic& Get(); static void Destroy(); UPROPERTY(Transient) TArray PackageList; TMap PackageInstByID; TMap PackageInstByName; TMap Vars; FString Branch; UPROPERTY(Transient) TMap Fonts; }; ================================================ FILE: Source/FairyGUI/Public/UIPackageAsset.h ================================================ #pragma once #include "CoreMinimal.h" #include "UObject/NoExportTypes.h" #include "UIPackageAsset.generated.h" UCLASS() class FAIRYGUI_API UUIPackageAsset : public UObject { GENERATED_BODY() public: UPROPERTY(EditAnywhere) TArray Data; #if WITH_EDITORONLY_DATA UPROPERTY(Instanced) class UAssetImportData* AssetImportData; virtual void GetAssetRegistryTags(TArray& OutTags) const override; #endif }; ================================================ FILE: Source/FairyGUI/Public/Utils/ByteBuffer.h ================================================ #pragma once #include "CoreMinimal.h" #include "FairyCommons.h" class FAIRYGUI_API FByteBuffer { public: FByteBuffer(const uint8* InBuffer, int32 InOffset, int32 InLen, bool bInTransferOwnerShip); ~FByteBuffer(); const uint8* GetBuffer() const { return Buffer; } int32 GetBytesAvailable() const; int32 GetLength() const { return Length; } int32 GetPos() const { return Position; } void SetPos(int32 InPos) { Position = InPos; } void Skip(int32 Count) { Position += Count; } int8 ReadByte(); uint8 ReadUbyte(); bool ReadBool(); int16 ReadShort(); uint16 ReadUshort(); int32 ReadInt(); uint32 ReadUint(); float ReadFloat(); FString ReadString(); FString ReadString(int32 InLen); const FString& ReadS(); void ReadSArray(TArray& OutArray, int32 InCount); bool ReadS(FString& OutString); const FString* ReadSP(); void WriteS(const FString& InString); FColor ReadColor(); TSharedPtr ReadBuffer(bool bCloneBuffer); bool Seek(int32 IndexTablePos, int32 BlockIndex); bool bLittleEndian; int32 Version; TSharedPtr> StringTable; private: const uint8* Buffer; int32 Offset; int32 Length; int32 Position;; bool bOwnsBuffer; }; ================================================ FILE: Source/FairyGUI/Public/Utils/HTMLElement.h ================================================ #pragma once #include "Slate.h" #include "Widgets/NTextFormat.h" #include "XMLAttributes.h" enum class EHTMLElementType { Text, Link, Image, Input, Select, Object, //internal LinkEnd, }; class FAIRYGUI_API FHTMLElement { public: EHTMLElementType Type; FString Name; FString Text; FNTextFormat Format; int32 CharIndex; int32 Space; FVector2D Position; FXMLAttributes Attributes; }; ================================================ FILE: Source/FairyGUI/Public/Utils/HTMLParser.h ================================================ #pragma once #include "HTMLElement.h" struct FAIRYGUI_API FHTMLParseOptions { bool bLinkUnderline; FColor LinkColor; FColor LinkBgColor; FColor LinkHoverBgColor; bool bIgnoreWhiteSpace; }; class FAIRYGUI_API FHTMLParser { public: static FHTMLParser DefaultParser; static FHTMLParseOptions DefaultParseOptions; FHTMLParser(); void Parse(const FString& InText, const FNTextFormat& InFormat, TArray& OutElements, const FHTMLParseOptions& InParseOptions); protected: void PushTextFormat(); void PopTextFormat(); bool IsNewLine(); void AppendText(const FString& InText); struct FMyTextFormat : FNTextFormat { bool bColorChanged; }; TArray TextFormatStack; FMyTextFormat Format; TArray* Elements; FHTMLParseOptions ParseOptions; }; ================================================ FILE: Source/FairyGUI/Public/Utils/NVariant.h ================================================ #pragma once #include "CoreMinimal.h" #include "Containers/Union.h" #include "NVariant.generated.h" USTRUCT(BlueprintType) struct FAIRYGUI_API FNVariant { GENERATED_USTRUCT_BODY() public: FNVariant(); FNVariant(const FNVariant& other); FNVariant(FNVariant&& other); ~FNVariant(); explicit FNVariant(bool bValue); explicit FNVariant(int32 Value); explicit FNVariant(float Value); explicit FNVariant(const FString& Value); explicit FNVariant(const FColor& Value); explicit FNVariant(void* Value); FNVariant& operator= (const FNVariant& other); FNVariant& operator= (FNVariant&& other); FNVariant& operator= (bool bValue); FNVariant& operator= (int32 Value); FNVariant& operator= (float Value); FNVariant& operator= (const FString& Value); FNVariant& operator= (const FColor& Value); FNVariant& operator= (void* Value); bool AsBool() const { return As(); } int32 AsInt() const { return As(); } float AsFloat() const { return As(); } FString AsString() const { return As(); } FColor AsColor() const { return As(); } UObject* AsUObject() const { return (UObject*)As(); } template DataType As() const { if (TheUnion.HasSubtype()) return TheUnion.GetSubtype(); else return DataType(); } void Reset() { TheUnion.Reset(); } static const FNVariant Null; private: TUnion TheUnion; }; ================================================ FILE: Source/FairyGUI/Public/Utils/UBBParser.h ================================================ #pragma once #include "Slate.h" #include "Widgets/NTextFormat.h" DECLARE_DELEGATE_RetVal_ThreeParams(FString, FTagHandler, const FString&, bool, const FString&); DECLARE_DELEGATE_RetVal_FourParams(bool, FDefaultTagHandler, const FString&, bool, const FString&, FString&); class FAIRYGUI_API FUBBParser { public: static FUBBParser DefaultParser; FUBBParser(); virtual ~FUBBParser(); FString Parse(const FString& Text, bool bRemove = false); int32 DefaultImgWidth; int32 DefaultImgHeight; FString LastColor; FString LastFontSize; FDefaultTagHandler DefaultTagHandler; TMap Handlers; protected: virtual FString OnTag_URL(const FString& TagName, bool bEnd, const FString& Attr); virtual FString OnTag_IMG(const FString& TagName, bool bEnd, const FString& Attr); virtual FString OnTag_Simple(const FString& TagName, bool bEnd, const FString& Attr); virtual FString OnTag_COLOR(const FString& TagName, bool bEnd, const FString& Attr); virtual FString OnTag_FONT(const FString& TagName, bool bEnd, const FString& Attr); virtual FString OnTag_SIZE(const FString& TagName, bool bEnd, const FString& Attr); virtual FString OnTag_ALIGN(const FString& TagName, bool bEnd, const FString& Attr); FString GetTagText(bool bRemove); const FString* Source; int32 ReadPos; }; ================================================ FILE: Source/FairyGUI/Public/Utils/XMLAttributes.h ================================================ #pragma once #include "CoreMinimal.h" struct FXMLAttributes : TMap { const FString& Get(const FString& AttrName, const FString& DefaultValue = ""); int32 GetInt(const FString& AttrName, int32 DefaultValue = 0); float GetFloat(const FString& AttrName, float DefaultValue = 0); bool GetBool(const FString& AttrName, bool DefaultValue = false); FColor GetColor(const FString& AttrName, const FColor& DefaultValue); }; ================================================ FILE: Source/FairyGUI/Public/Utils/XMLIterator.h ================================================ #pragma once #include "XMLAttributes.h" enum class EXMLTagType { Start, End, Void, CDATA, Comment, Instruction }; struct FAIRYGUI_API FXMLIterator { public: void Begin(const FString& InText, bool bLowerCaseName = false); bool NextTag(); FString GetTagSource() const; FString GetRawText(bool bTrim = false) const; FString GetText(bool bTrim = false) const; void ParseAttributes(); static FString DecodeString(const FString& InSource); FString TagName; EXMLTagType TagType; FString LastTagName; FXMLAttributes Attributes; private: const FString* Source; int32 SourceLen; int32 ParsePos; int32 TagPos; int32 TagLength; int32 LastTagEnd; bool bAttrParsed; bool bLowerCaseName; }; ================================================ FILE: Source/FairyGUI/Public/Widgets/BitmapFont.h ================================================ #pragma once #include "CoreMinimal.h" class UNTexture; struct FAIRYGUI_API FBitmapFont : public FGCObject { struct FGlyph { FVector2D Offset; FVector2D Size; float XAdvance; float LineHeight; FBox2D UVRect; int32 Channel; }; int32 FontSize; bool bResizable; bool bHasChannel; bool bCanTint; TMap Glyphs; UNTexture* Texture; virtual void AddReferencedObjects(FReferenceCollector& Collector) override; }; ================================================ FILE: Source/FairyGUI/Public/Widgets/BitmapFontRun.h ================================================ #pragma once #include "Slate.h" #include "BitmapFont.h" class FArrangedChildren; class FPaintArgs; class FSlateWindowElementList; struct FTextBlockStyle; enum class ETextHitPoint : uint8; class FAIRYGUI_API FBitmapFontRun : public ISlateRun, public TSharedFromThis< FBitmapFontRun > { public: static TSharedRef< FBitmapFontRun > Create(const TSharedRef< const FString >& InText, const TSharedRef& InFont, const FTextRange& InRange); public: virtual ~FBitmapFontRun(); virtual FTextRange GetTextRange() const override; virtual void SetTextRange(const FTextRange& Value) override; virtual int16 GetBaseLine(float Scale) const override; virtual int16 GetMaxHeight(float Scale) const override; virtual FVector2D Measure(int32 StartIndex, int32 EndIndex, float Scale, const FRunTextContext& TextContext) const override; virtual int8 GetKerning(int32 CurrentIndex, float Scale, const FRunTextContext& TextContext) const override; virtual TSharedRef< ILayoutBlock > CreateBlock(int32 StartIndex, int32 EndIndex, FVector2D Size, const FLayoutBlockTextContext& TextContext, const TSharedPtr< IRunRenderer >& Renderer) override; 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; virtual const TArray< TSharedRef >& GetChildren() override; virtual void ArrangeChildren(const TSharedRef< ILayoutBlock >& Block, const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const override; virtual int32 GetTextIndexAt(const TSharedRef< ILayoutBlock >& Block, const FVector2D& Location, float Scale, ETextHitPoint* const OutHitPoint = nullptr) const override; virtual FVector2D GetLocationAt(const TSharedRef< ILayoutBlock >& Block, int32 Offset, float Scale) const override; virtual void BeginLayout() override {} virtual void EndLayout() override {} virtual void Move(const TSharedRef& NewText, const FTextRange& NewRange) override; virtual TSharedRef Clone() const override; virtual void AppendTextTo(FString& AppendToText) const override; virtual void AppendTextTo(FString& AppendToText, const FTextRange& PartialRange) const override; virtual const FRunInfo& GetRunInfo() const override; virtual ERunAttributes GetRunAttributes() const override; protected: FBitmapFontRun(const TSharedRef< const FString >& InText, const TSharedRef& InFont, const FTextRange& InRange); private: TSharedRef< const FString > Text; FTextRange Range; TSharedRef Font; FBitmapFont::FGlyph* Glyph; FSlateBrush Brush; }; ================================================ FILE: Source/FairyGUI/Public/Widgets/HitTest.h ================================================ #pragma once #include "CoreMinimal.h" class FAIRYGUI_API IHitTest { public: virtual bool HitTest(const FBox2D& ContentRect, const FVector2D& LayoutScaleMultiplier, const FVector2D& LocalPoint) const = 0; }; struct FAIRYGUI_API FPixelHitTestData { public: int32 PixelWidth; float Scale; TArray Pixels; void Load(class FByteBuffer* Buffer); }; class FAIRYGUI_API FPixelHitTest : public IHitTest { public: FPixelHitTest(const TSharedPtr& Data, int32 OffsetX, int32 OffsetY); virtual ~FPixelHitTest(); bool HitTest(const FBox2D& ContentRect, const FVector2D& LayoutScaleMultiplier, const FVector2D& LocalPoint) const; int32 OffsetX; int32 OffsetY; private: TSharedPtr Data; }; class UGObject; class FAIRYGUI_API FChildHitTest : public IHitTest { public: FChildHitTest(UGObject* InObj); virtual ~FChildHitTest(); bool HitTest(const FBox2D& ContentRect, const FVector2D& LayoutScaleMultiplier, const FVector2D& LocalPoint) const; TWeakObjectPtr Obj; }; ================================================ FILE: Source/FairyGUI/Public/Widgets/LoaderRun.h ================================================ #pragma once #include "Slate.h" #include "Utils/HTMLElement.h" class UFairyApplication; class FArrangedChildren; class FPaintArgs; class FSlateWindowElementList; struct FTextBlockStyle; enum class ETextHitPoint : uint8; class FAIRYGUI_API FLoaderRun : public ISlateRun, public TSharedFromThis< FLoaderRun >, public FGCObject { public: static TSharedRef< FLoaderRun > Create(UFairyApplication* App, const FHTMLElement& InHTMLElement, const TSharedRef< const FString >& InText, const FTextRange& InRange); public: virtual ~FLoaderRun(); virtual FTextRange GetTextRange() const override; virtual void SetTextRange(const FTextRange& Value) override; virtual int16 GetBaseLine(float Scale) const override; virtual int16 GetMaxHeight(float Scale) const override; virtual FVector2D Measure(int32 StartIndex, int32 EndIndex, float Scale, const FRunTextContext& TextContext) const override; virtual int8 GetKerning(int32 CurrentIndex, float Scale, const FRunTextContext& TextContext) const override; virtual TSharedRef< ILayoutBlock > CreateBlock(int32 StartIndex, int32 EndIndex, FVector2D Size, const FLayoutBlockTextContext& TextContext, const TSharedPtr< IRunRenderer >& Renderer) override; 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; virtual const TArray< TSharedRef >& GetChildren() override; virtual void ArrangeChildren(const TSharedRef< ILayoutBlock >& Block, const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const override; virtual int32 GetTextIndexAt(const TSharedRef< ILayoutBlock >& Block, const FVector2D& Location, float Scale, ETextHitPoint* const OutHitPoint = nullptr) const override; virtual FVector2D GetLocationAt(const TSharedRef< ILayoutBlock >& Block, int32 Offset, float Scale) const override; virtual void BeginLayout() override {} virtual void EndLayout() override {} virtual void Move(const TSharedRef& NewText, const FTextRange& NewRange) override; virtual TSharedRef Clone() const override; virtual void AppendTextTo(FString& AppendToText) const override; virtual void AppendTextTo(FString& AppendToText, const FTextRange& PartialRange) const override; virtual const FRunInfo& GetRunInfo() const override; virtual ERunAttributes GetRunAttributes() const override; virtual void AddReferencedObjects(FReferenceCollector& Collector) override; protected: FLoaderRun(UFairyApplication* App, const FHTMLElement& HTMLElement, const TSharedRef< const FString >& InText, const FTextRange& InRange); private: TArray< TSharedRef > Children; FHTMLElement HTMLElement; TSharedRef< const FString > Text; FTextRange Range; class UGLoader* Loader; }; ================================================ FILE: Source/FairyGUI/Public/Widgets/Mesh/EllipseMesh.h ================================================ #pragma once #include "MeshFactory.h" #include "Widgets/HitTest.h" class FAIRYGUI_API FEllipseMesh : public IMeshFactory, public IHitTest { public: MESHFACTORY_TYPE(FEllipseMesh, this) FEllipseMesh(); virtual ~FEllipseMesh() {} TOptional DrawRect; float LineWidth; FColor LineColor; TOptional CenterColor; TOptional FillColor; float StartDegree; float EndDegreee; void OnPopulateMesh(FVertexHelper& Helper); bool HitTest(const FBox2D& ContentRect, const FVector2D& LayoutScaleMultiplier, const FVector2D& LocalPoint) const; }; ================================================ FILE: Source/FairyGUI/Public/Widgets/Mesh/FillMesh.h ================================================ #pragma once #include "MeshFactory.h" #include "UI/FieldTypes.h" class FAIRYGUI_API FFillMesh : public IMeshFactory { public: MESHFACTORY_TYPE(FFillMesh, nullptr) FFillMesh(); virtual ~FFillMesh() {} EFillMethod Method; int32 Origin; bool bClockwise; float Amount; void OnPopulateMesh(FVertexHelper& Helper); }; ================================================ FILE: Source/FairyGUI/Public/Widgets/Mesh/MeshFactory.h ================================================ #pragma once #include "CoreMinimal.h" #include "UObject/NoExportTypes.h" #include "VertexHelper.h" #include "Widgets/HitTest.h" #define MESHFACTORY_TYPE(TYPE, HITTEST) \ static const FName& GetMeshFactoryTypeId() { static FName Type(TEXT(#TYPE)); return Type; } \ virtual bool IsMeshFactoryOfType(const FName& Type) const override { return GetMeshFactoryTypeId() == Type; } \ virtual IHitTest* GetMeshHitTest() const { return (IHitTest*)HITTEST; } class FAIRYGUI_API IMeshFactory { public: virtual void OnPopulateMesh(FVertexHelper& Helper) = 0; virtual bool IsMeshFactoryOfType(const FName& Type) const = 0; virtual IHitTest* GetMeshHitTest() const = 0; }; class FAIRYGUI_API FMeshFactory : public IMeshFactory { public: FMeshFactory(IMeshFactory* InSourceFactory) { SourceFactory = InSourceFactory; } inline virtual void OnPopulateMesh(FVertexHelper& Helper) override { SourceFactory->OnPopulateMesh(Helper); } inline virtual bool IsMeshFactoryOfType(const FName& Type) const override { return SourceFactory->IsMeshFactoryOfType(Type); } inline virtual IHitTest* GetMeshHitTest() const override { return SourceFactory->GetMeshHitTest(); } IMeshFactory* SourceFactory; }; ================================================ FILE: Source/FairyGUI/Public/Widgets/Mesh/PolygonMesh.h ================================================ #pragma once #include "MeshFactory.h" class FAIRYGUI_API FPolygonMesh : public IMeshFactory, public IHitTest { public: MESHFACTORY_TYPE(FPolygonMesh, this) FPolygonMesh(); virtual ~FPolygonMesh() {} TArray Points; TArray Texcoords; float LineWidth; FColor LineColor; TOptional FillColor; TOptional> Colors; bool bUsePercentPositions; void OnPopulateMesh(FVertexHelper& Helper); bool HitTest(const FBox2D& ContentRect, const FVector2D& LayoutScaleMultiplier, const FVector2D& LocalPoint) const; private: void DrawOutline(FVertexHelper& Helper); bool IsPointInTriangle(const FVector2D& p, const FVector2D& a, const FVector2D& b, const FVector2D& c); }; ================================================ FILE: Source/FairyGUI/Public/Widgets/Mesh/RectMesh.h ================================================ #pragma once #include "MeshFactory.h" class FAIRYGUI_API FRectMesh : public IMeshFactory { public: MESHFACTORY_TYPE(FRectMesh, nullptr) FRectMesh(); virtual ~FRectMesh() {} TOptional DrawRect; float LineWidth; FColor LineColor; TOptional FillColor; TOptional> Colors; void OnPopulateMesh(FVertexHelper& Helper); }; ================================================ FILE: Source/FairyGUI/Public/Widgets/Mesh/RegularPolygonMesh.h ================================================ #pragma once #include "MeshFactory.h" class FAIRYGUI_API FRegularPolygonMesh : public IMeshFactory { public: MESHFACTORY_TYPE(FRegularPolygonMesh, nullptr) FRegularPolygonMesh(); virtual ~FRegularPolygonMesh() {} TOptional DrawRect; int32 Sides; float LineWidth; FColor LineColor; TOptional CenterColor; TOptional FillColor; TArray Distances; float Rotation; void OnPopulateMesh(FVertexHelper& Helper); }; ================================================ FILE: Source/FairyGUI/Public/Widgets/Mesh/RoundedRectMesh.h ================================================ #pragma once #include "MeshFactory.h" class FAIRYGUI_API FRoundedRectMesh : public IMeshFactory { public: MESHFACTORY_TYPE(FRoundedRectMesh, nullptr) FRoundedRectMesh(); virtual ~FRoundedRectMesh() {} TOptional DrawRect; float LineWidth; FColor LineColor; TOptional FillColor; float TopLeftRadius; float TopRightRadius; float BottomLeftRadius; float BottomRightRadius; void OnPopulateMesh(FVertexHelper& Helper); }; ================================================ FILE: Source/FairyGUI/Public/Widgets/Mesh/VertexHelper.h ================================================ #pragma once #include "Slate.h" class FAIRYGUI_API FVertexHelper { public: FVertexHelper(); void Clear(); int32 GetVertexCount() const; void AddVertex(const FVector2D& Position); void AddVertex(const FVector2D& Position, const FColor& Color); void AddVertex(const FVector2D& Position, const FColor& Color, const FVector2D& TexCoords); void AddQuad(const FBox2D& VertRect); void AddQuad(const FBox2D& VertRect, const FColor& Color); void AddQuad(const FBox2D& VertRect, const FColor& Color, const FBox2D& InUVRect); void RepeatColors(FColor* Colors, int32 ColorCount, int32 StartIndex, int32 Count); void AddTriangle(SlateIndex idx0, SlateIndex idx1, SlateIndex idx2); void AddTriangles(const SlateIndex* Indice, int32 IndiceLength, int32 StartVertexIndex = 0); void AddTriangles(int32 StartVertexIndex = 0); const FVector2D& GetPosition(int32 Index); FVector2D GetUVAtPosition(const FVector2D& Position, bool bUsePercent); void Append(const FVertexHelper& VertexHelper); void Insert(const FVertexHelper& VertexHelper); public: FBox2D ContentRect; FBox2D UVRect; FColor VertexColor; FVector2D TextureSize; TArray Vertices; TArray Triangles; }; ================================================ FILE: Source/FairyGUI/Public/Widgets/MeshFactory.h ================================================ #pragma once #include "VertexHelper.h" #define MESHFACTORY_TYPE(TYPE) \ static const FName& GetMeshFactoryTypeId() { static FName Type(TEXT(#TYPE)); return Type; } \ virtual bool IsMeshFactoryOfType(const FName& Type) const override { return GetMeshFactoryTypeId() == Type; } class FAIRYGUI_API IMeshFactory { public: virtual void OnPopulateMesh(FVertexHelper& Helper) = 0; virtual bool IsMeshFactoryOfType(const FName& Type) const = 0; }; class FAIRYGUI_API FMeshFactory : public IMeshFactory { public: FMeshFactory(IMeshFactory* InSourceFactory) { SourceFactory = InSourceFactory; } inline virtual void OnPopulateMesh(FVertexHelper& Helper) override { SourceFactory->OnPopulateMesh(Helper); } inline virtual bool IsMeshFactoryOfType(const FName& Type) const override { return SourceFactory->IsMeshFactoryOfType(Type); } IMeshFactory* SourceFactory; }; ================================================ FILE: Source/FairyGUI/Public/Widgets/NGraphics.h ================================================ #pragma once #include "Mesh/MeshFactory.h" #include "NTexture.h" #include "UI/FieldTypes.h" class FAIRYGUI_API FNGraphics : public FGCObject { public: FNGraphics(); virtual ~FNGraphics(); const FColor& GetColor() const { return Color; } void SetColor(const FColor& InColor); EFlipType GetFlip() const { return Flip; } void SetFlip(EFlipType Value); void SetTexture(UNTexture* InTexture); UNTexture* GetTexture() const { return Texture; } void SetMeshFactory(const TSharedPtr& InMeshFactory); const TSharedPtr& GetMeshFactory() { return MeshFactory; } template T& GetMeshFactory(); void SetMeshDirty() { bMeshDirty = true; } void Paint(const FGeometry& AllottedGeometry, FSlateWindowElementList& OutDrawElements, int32 LayerId, float Alpha, bool bEnabled); void PopulateDefaultMesh(FVertexHelper& Helper); virtual void AddReferencedObjects(FReferenceCollector& Collector) override; private: void UpdateMeshNow(); FVector2D Size; FColor Color; EFlipType Flip; UNTexture* Texture; FSlateBrush Brush; FSlateResourceHandle ResourceHandle; TSharedPtr MeshFactory; TArray Vertices; TArray Triangles; TArray PositionsBackup; TArray AlphaBackup; float UsingAlpha; bool bMeshDirty; }; template inline T& FNGraphics::GetMeshFactory() { if (MeshFactory.IsValid() && MeshFactory->IsMeshFactoryOfType(T::GetMeshFactoryTypeId())) return *static_cast(MeshFactory.Get()); T* Ret = new T(); MeshFactory = MakeShareable(Ret); return *Ret; } ================================================ FILE: Source/FairyGUI/Public/Widgets/NTextFormat.h ================================================ #pragma once #include "Slate.h" #include "UI/FieldTypes.h" #include "NTextFormat.generated.h" USTRUCT(BlueprintType) struct FAIRYGUI_API FNTextFormat { GENERATED_USTRUCT_BODY() public: FNTextFormat(); bool EqualStyle(const FNTextFormat& AnotherFormat) const; FTextBlockStyle GetStyle() const; public: UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") FString Face; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") int32 Size; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") FColor Color; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") bool bBold; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") bool bItalic; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") bool bUnderline; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") int32 LineSpacing; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") int32 LetterSpacing; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") EAlignType Align; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") EVerticalAlignType VerticalAlign; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") FColor OutlineColor; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") int32 OutlineSize; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") FColor ShadowColor; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FairyGUI") FVector2D ShadowOffset; }; ================================================ FILE: Source/FairyGUI/Public/Widgets/NTexture.h ================================================ #pragma once #include "CoreMinimal.h" #include "UObject/NoExportTypes.h" #include "Runtime/Engine/Classes/Engine/Texture2D.h" #include "NTexture.generated.h" UCLASS() class FAIRYGUI_API UNTexture : public UObject { GENERATED_BODY() public: static UNTexture* GetWhiteTexture(); static void DestroyWhiteTexture(); UNTexture(); UPROPERTY(Transient) UNTexture* Root; UPROPERTY(Transient) UTexture2D* NativeTexture; FBox2D UVRect; bool bRotated; FBox2D Region; FVector2D Offset; FVector2D OriginalSize; void Init(UTexture2D* NewNativeTexture); void Init(UTexture2D* NewNativeTexture, float ScaleX, float ScaleY); void Init(UTexture2D* NewNativeTexture, const FBox2D& NewRegion); void Init(UNTexture* NewRoot, const FBox2D& NewRegion, bool bNewRotated); void Init(UNTexture* NewRoot, const FBox2D& NewRegion, bool bNewRotated, const FVector2D& NewOriginalSize, const FVector2D& NewOffset); FVector2D GetSize() const; FBox2D GetDrawRect(FBox2D& InDrawRect) const; private: static UNTexture* WhiteTexture; friend class UFairyApplication; }; ================================================ FILE: Source/FairyGUI/Public/Widgets/SContainer.h ================================================ #pragma once #include "SDisplayObject.h" class FAIRYGUI_API SContainer : public SDisplayObject { public: SLATE_BEGIN_ARGS(SContainer) : _GObject(nullptr) {} SLATE_ARGUMENT(UGObject*, GObject) SLATE_END_ARGS() SContainer(); void Construct(const FArguments& InArgs); void AddChild(const TSharedRef& SlotWidget); void AddChildAt(const TSharedRef& SlotWidget, int32 Index); int32 GetChildIndex(const TSharedRef& SlotWidget) const; void SetChildIndex(const TSharedRef& SlotWidget, int32 Index); void RemoveChild(const TSharedRef& SlotWidget); void RemoveChildAt(int32 Index); void RemoveChildren(int32 BeginIndex = 0, int32 EndIndex = -1); int32 NumChildren() const; public: virtual void OnArrangeChildren(const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const override; virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override; virtual FChildren* GetChildren() override; protected: TPanelChildren Children; }; ================================================ FILE: Source/FairyGUI/Public/Widgets/SDisplayObject.h ================================================ #pragma once #include "CoreMinimal.h" #include "UObject/NoExportTypes.h" #include "Slate.h" class UGObject; class FAIRYGUI_API SDisplayObject : public SWidget { public: SLATE_BEGIN_ARGS(SDisplayObject) : _GObject(nullptr), _Tag(SDisplayObject::SDisplayObjectTag) { } SLATE_ARGUMENT(UGObject*, GObject) SLATE_ARGUMENT(FName, Tag) SLATE_END_ARGS() static FName SDisplayObjectTag; SDisplayObject(); void Construct(const FArguments& InArgs); const FVector2D& GetPosition() const; void SetPosition(const FVector2D& InPosition); void SetX(float InX); void SetY(float InY); void SetSize(const FVector2D& InSize); FVector2D GetSize() const { return Size; } void SetVisible(bool bInVisible); bool IsVisible() const { return bVisible; } void SetTouchable(bool bInTouchable); bool IsTouchable() const { return bTouchable; } void SetOpaque(bool bInOpaque); bool IsOpaque() const { return bOpaque; } void SetInteractable(bool bInInteractable); virtual bool IsInteractable() const override { return bInteractable; } void UpdateVisibilityFlags(); virtual FReply OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override; virtual FReply OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override; virtual FReply OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override; virtual FReply OnMouseButtonDoubleClick(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override; virtual void OnMouseEnter(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override; virtual void OnMouseLeave(const FPointerEvent& MouseEvent) override; virtual FReply OnMouseWheel(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override; TWeakObjectPtr GObject; static bool IsWidgetOnStage(const TSharedPtr& InWidget); static UGObject* GetWidgetGObject(const TSharedPtr& InWidget); static UGObject* GetWidgetGObjectIfOnStage(const TSharedPtr& InWidget); static void GetWidgetDescendants(const TSharedRef& InWidget, TArray& OutArray); static void GetWidgetPathToRoot(const TSharedRef& InWidget, TArray& OutArray); protected: virtual FVector2D ComputeDesiredSize(float LayoutScaleMultiplier) const override; virtual FChildren* GetChildren() override; virtual void OnArrangeChildren(const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const override; virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override; EVisibility GetVisibilityFlags() const; protected: uint8 bVisible : 1; uint8 bInteractable : 1; uint8 bTouchable : 1; uint8 bOpaque : 1; FVector2D Size; static bool bMindVisibleOnly; private: static FNoChildren NoChildrenInstance; }; ================================================ FILE: Source/FairyGUI/Public/Widgets/SFImage.h ================================================ #pragma once #include "SDisplayObject.h" #include "UI/FieldTypes.h" #include "Mesh/FillMesh.h" #include "NTexture.h" #include "NGraphics.h" class FAIRYGUI_API SFImage : public SDisplayObject, public IMeshFactory { public: SLATE_BEGIN_ARGS(SFImage) : _GObject(nullptr) {} SLATE_ARGUMENT(UGObject*, GObject) SLATE_END_ARGS() MESHFACTORY_TYPE(SFImage, nullptr) SFImage(); void Construct(const FArguments& InArgs); void SetTexture(UNTexture* InTexture); UNTexture* GetTexture() const { return Graphics.GetTexture(); } void SetNativeSize(); void SetScale9Grid(const TOptional& GridRect); void SetScaleByTile(bool bInScaleByTile); void SetTileGridIndice(int32 InTileGridIndex); EFillMethod GetFillMethod() const; void SetFillMethod(EFillMethod Method); int32 GetFillOrigin() const; void SetFillOrigin(int32 Origin); bool IsFillClockwise() const; void SetFillClockwise(bool bClockwise); float GetFillAmount() const; void SetFillAmount(float Amount); FNGraphics Graphics; public: // SWidget overrides virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override; virtual void OnPopulateMesh(FVertexHelper& Helper) override; protected: void TileFill(FVertexHelper& Helper, const FBox2D& ContentRect, const FBox2D& UVRect, const FVector2D& TextureSize); void SliceFill(FVertexHelper& Helper); protected: TOptional Scale9Grid; bool bScaleByTile; FVector2D TextureScale; int32 TileGridIndice; TUniquePtr FillMesh; }; ================================================ FILE: Source/FairyGUI/Public/Widgets/SMovieClip.h ================================================ #pragma once #include "SFImage.h" struct FAIRYGUI_API FMovieClipData : public FGCObject { struct Frame { UNTexture *Texture; float AddDelay; }; TArray Frames; float Interval; float RepeatDelay; bool bSwing; FMovieClipData(); virtual void AddReferencedObjects(FReferenceCollector& Collector) override; }; class FAIRYGUI_API SMovieClip : public SFImage { public: SLATE_BEGIN_ARGS(SMovieClip) : _GObject(nullptr) {} SLATE_ARGUMENT(UGObject*, GObject) SLATE_END_ARGS() SMovieClip(); void Construct(const FArguments& InArgs); void SetClipData(TSharedPtr InData); const TSharedPtr& GetClipData() const { return Data; } bool IsPlaying() const { return bPlaying; } void SetPlaying(bool bInPlaying); int32 GetFrame() const { return Frame; } void SetFrame(int32 InFrame); float GetTimeScale() const { return TimeScale; } void SetTimeScale(float InTimeScale); void Advance(float Time); //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) void SetPlaySettings(int32 InStart = 0, int32 InEnd = -1, int32 InTimes = 0, int32 InEndAt = -1, const FSimpleDelegate& InCompleteCallback = FSimpleDelegate()); public: // SWidget overrides virtual void Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) override; protected: void DrawFrame(); TSharedPtr Data; int32 Frame; bool bPlaying; float TimeScale; int32 Start; int32 End; int32 Times; int32 EndAt; int32 Status; //0-none, 1-next loop, 2-ending, 3-ended FSimpleDelegate CompleteCallback; float FrameElapsed; bool bReversed; int32 RepeatedCount; }; ================================================ FILE: Source/FairyGUI/Public/Widgets/SShape.h ================================================ #pragma once #include "SDisplayObject.h" #include "NTexture.h" #include "NGraphics.h" class FAIRYGUI_API SShape : public SDisplayObject { public: SLATE_BEGIN_ARGS(SShape) : _GObject(nullptr) {} SLATE_ARGUMENT(UGObject*, GObject) SLATE_END_ARGS() SShape(); void Construct(const FArguments& InArgs); FNGraphics Graphics; public: // SWidget overrides virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override; }; ================================================ FILE: Source/FairyGUI/Public/Widgets/STextField.h ================================================ #pragma once #include "SDisplayObject.h" #include "UI/FieldTypes.h" #include "NTextFormat.h" #include "Utils/HTMLElement.h" class FSlateTextLayout; class FSlateTextUnderlineLineHighlighter; class FAIRYGUI_API STextField : public SDisplayObject { public: SLATE_BEGIN_ARGS(STextField) : _GObject(nullptr) {} SLATE_ARGUMENT(UGObject*, GObject) SLATE_END_ARGS() STextField(); void Construct(const FArguments& InArgs); const FString& GetText() const { return Text; } void SetText(const FString& InText, bool bInHTML = false); EAutoSizeType GetAutoSize() const { return AutoSize; }; void SetAutoSize(EAutoSizeType InAutoSize); bool IsSingleLine() const { return bSingleLine; } void SetSingleLine(bool InSingleLine); FNTextFormat& GetTextFormat() { return TextFormat; } void SetTextFormat(const FNTextFormat& InFormat); float GetMaxWidth() const { return MaxWidth; } void SetMaxWidth(float InMaxWidth); FVector2D GetTextSize(); virtual FChildren* GetChildren() override; virtual void OnArrangeChildren(const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const override; protected: virtual FVector2D ComputeDesiredSize(float LayoutScaleMultiplier) const override; virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override; virtual bool ComputeVolatility() const override { return true; } void UpdateTextLayout(); void BuildLines(); protected: FString Text; bool bHTML; EAutoSizeType AutoSize; bool bSingleLine; float MaxWidth; FNTextFormat TextFormat; TSharedRef TextLayout; TArray HTMLElements; }; ================================================ FILE: Source/FairyGUI/Public/Widgets/STextInput.h ================================================ #pragma once #include "SDisplayObject.h" #include "NTextFormat.h" class FAIRYGUI_API STextInput : public SDisplayObject { public: SLATE_BEGIN_ARGS(STextInput) : _GObject(nullptr) {} SLATE_ARGUMENT(UGObject*, GObject) SLATE_END_ARGS() STextInput(); void Construct(const FArguments& InArgs); void SetPassword(bool bInPassword); void SetSingleLine(bool bInSingleLine); void SetTextFormat(const FNTextFormat& InTextFormat); void SetOnTextChanged(FOnTextChanged Callback); void SetOnTextCommitted(FOnTextCommitted Callback); virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override; virtual FChildren* GetChildren() override; virtual void OnArrangeChildren(const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const override; TSharedRef Widget; protected: FSimpleSlot ChildSlot; }; ================================================ FILE: Source/FairyGUIEditor/FairyGUIEditor.Build.cs ================================================ // Copyright 1998-2019 Epic Games, Inc. All Rights Reserved. using UnrealBuildTool; public class FairyGUIEditor : ModuleRules { public FairyGUIEditor(ReadOnlyTargetRules Target) : base(Target) { PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; PublicIncludePaths.AddRange( new string[] { // ... add public include paths required here ... } ); PrivateIncludePaths.AddRange( new string[] { // ... add other private include paths required here ... } ); PublicDependencyModuleNames.AddRange( new string[] { "Core", // ... add other public dependencies that you statically link with here ... } ); PrivateDependencyModuleNames.AddRange( new string[] { "FairyGUI", "CoreUObject", "Engine", "Slate", "SlateCore", "UnrealEd", // ... add private dependencies that you statically link with here ... } ); DynamicallyLoadedModuleNames.AddRange( new string[] { // ... add any modules that your module loads dynamically here ... } ); } } ================================================ FILE: Source/FairyGUIEditor/Private/FairyGUIEditor.cpp ================================================ // Copyright 1998-2019 Epic Games, Inc. All Rights Reserved. #include "FairyGUIEditor.h" #include "Editor.h" #define LOCTEXT_NAMESPACE "FFairyGUIEditorModule" void FFairyGUIEditorModule::StartupModule() { // This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module } void FFairyGUIEditorModule::ShutdownModule() { // This function may be called during shutdown to clean up your module. For modules that support dynamic reloading, // we call this function before unloading the module. } #undef LOCTEXT_NAMESPACE IMPLEMENT_MODULE(FFairyGUIEditorModule, FairyGUIEditor) ================================================ FILE: Source/FairyGUIEditor/Private/FairyGUIFactory.cpp ================================================ #include "FairyGUIFactory.h" #include "Serialization/BufferArchive.h" #include "EditorFramework/AssetImportData.h" #include "Misc/Paths.h" #include "Misc/FileHelper.h" #include "UIPackageAsset.h" UFairyGUIFactory::UFairyGUIFactory() { SupportedClass = UUIPackageAsset::StaticClass(); bEditorImport = true; bCreateNew = false; bText = false; Formats.Add(TEXT("fui;FairyGUI package files")); } UObject* UFairyGUIFactory::FactoryCreateBinary(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, const TCHAR* Type, const uint8*& Buffer, const uint8* BufferEnd, FFeedbackContext* Warn) { UUIPackageAsset* UIAsset = NewObject(InParent, InName, Flags); const int32 InDataSize = BufferEnd - Buffer; UIAsset->Data.Empty(InDataSize); UIAsset->Data.AddUninitialized(InDataSize); FMemory::Memcpy(UIAsset->Data.GetData(), Buffer, InDataSize); if (!UIAsset->AssetImportData) { UIAsset->AssetImportData = NewObject(UIAsset, UAssetImportData::StaticClass()); } UIAsset->AssetImportData->Update(CurrentFilename); return UIAsset; } bool UFairyGUIFactory::CanReimport(UObject* Obj, TArray& OutFilenames) { UUIPackageAsset* UIAsset = Cast(Obj); if (UIAsset && UIAsset->AssetImportData) { UIAsset->AssetImportData->ExtractFilenames(OutFilenames); return true; } return false; } void UFairyGUIFactory::SetReimportPaths(UObject* Obj, const TArray& NewReimportPaths) { UUIPackageAsset* UIAsset = Cast(Obj); if (UIAsset && ensure(NewReimportPaths.Num() == 1)) { UIAsset->AssetImportData->UpdateFilenameOnly(NewReimportPaths[0]); } } EReimportResult::Type UFairyGUIFactory::Reimport(UObject* Obj) { UUIPackageAsset* UIAsset = Cast(Obj); if (!UIAsset) { return EReimportResult::Failed; } const FString Filename = UIAsset->AssetImportData->GetFirstFilename(); if (!Filename.Len() || IFileManager::Get().FileSize(*Filename) == INDEX_NONE) { return EReimportResult::Failed; } if (UFactory::StaticImportObject( UIAsset->GetClass(), UIAsset->GetOuter(), *UIAsset->GetName(), RF_Public | RF_Standalone, *Filename, NULL, this)) { if (UIAsset->GetOuter()) { UIAsset->GetOuter()->MarkPackageDirty(); } else { UIAsset->MarkPackageDirty(); } return EReimportResult::Succeeded; } return EReimportResult::Failed; } ================================================ FILE: Source/FairyGUIEditor/Public/FairyGUIEditor.h ================================================ // Copyright 1998-2019 Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "Modules/ModuleManager.h" class FFairyGUIEditorModule : public IModuleInterface { public: /** IModuleInterface implementation */ virtual void StartupModule() override; virtual void ShutdownModule() override; }; ================================================ FILE: Source/FairyGUIEditor/Public/FairyGUIFactory.h ================================================ #pragma once #include "CoreMinimal.h" #include "Factories/Factory.h" #include "EditorReimportHandler.h" #include "FairyGUIFactory.generated.h" UCLASS() class FAIRYGUIEDITOR_API UFairyGUIFactory : public UFactory, public FReimportHandler { GENERATED_BODY() public: UFairyGUIFactory(); virtual UObject* FactoryCreateBinary(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, const TCHAR* Type, const uint8*& Buffer, const uint8* BufferEnd, FFeedbackContext* Warn) override; virtual bool CanReimport(UObject* Obj, TArray& OutFilenames) override; virtual void SetReimportPaths(UObject* Obj, const TArray& NewReimportPaths) override; virtual EReimportResult::Type Reimport(UObject* Obj) override; };