diff --git a/Project/Source/GasaEditor/GasaGen/GasaGen_AttributeSets.cpp b/Project/Source/GasaEditor/GasaGen/AttributeSets.cpp similarity index 99% rename from Project/Source/GasaEditor/GasaGen/GasaGen_AttributeSets.cpp rename to Project/Source/GasaEditor/GasaGen/AttributeSets.cpp index 82b8f01..58b6e31 100644 --- a/Project/Source/GasaEditor/GasaGen/GasaGen_AttributeSets.cpp +++ b/Project/Source/GasaEditor/GasaGen/AttributeSets.cpp @@ -1,4 +1,4 @@ -#include "GasaGen_AttributeSets.h" +#include "AttributeSets.h" #include "GasaGen_Common.h" #include "Gasa/AbilitySystem/GasaAbilitySystem.h" diff --git a/Project/Source/GasaEditor/GasaGen/GasaGen_AttributeSets.h b/Project/Source/GasaEditor/GasaGen/AttributeSets.h similarity index 100% rename from Project/Source/GasaEditor/GasaGen/GasaGen_AttributeSets.h rename to Project/Source/GasaEditor/GasaGen/AttributeSets.h diff --git a/Project/Source/GasaEditor/GasaGen/ChangeBPActionMenu.cpp b/Project/Source/GasaEditor/GasaGen/ChangeBPActionMenu.cpp new file mode 100644 index 0000000..abbda96 --- /dev/null +++ b/Project/Source/GasaEditor/GasaGen/ChangeBPActionMenu.cpp @@ -0,0 +1,279 @@ +// Used in the GasaGen.cpp translation unit +#include "GasaGen_Common.h" + +constexpr StrC SBlueprintActionMenu_Construct_Replacement = txt(R"( +void SBlueprintActionMenu::Construct( const FArguments& InArgs, TSharedPtr InEditor ) +{ + bActionExecuted = false; + + this->GraphObj = InArgs._GraphObj; + this->DraggedFromPins = InArgs._DraggedFromPins; + this->NewNodePosition = InArgs._NewNodePosition; + this->OnClosedCallback = InArgs._OnClosedCallback; + this->bAutoExpandActionMenu = InArgs._AutoExpandActionMenu; + this->EditorPtr = InEditor; + this->OnCloseReasonCallback = InArgs._OnCloseReason; + + // Generate the context display; showing the user what they're picking something for + //@TODO: Should probably be somewhere more schema-sensitive than the graph panel! + FSlateColor TypeColor; + FString TypeOfDisplay; + const FSlateBrush* ContextIcon = nullptr; + + if (DraggedFromPins.Num() == 1) + { + UEdGraphPin* OnePin = DraggedFromPins[0]; + + const UEdGraphSchema* Schema = OnePin->GetSchema(); + const UEdGraphSchema_K2* K2Schema = GetDefault(); + + if (!Schema->IsA(UEdGraphSchema_K2::StaticClass()) || !K2Schema->IsExecPin(*OnePin)) + { + // Get the type color and icon + TypeColor = Schema->GetPinTypeColor(OnePin->PinType); + ContextIcon = FAppStyle::GetBrush( OnePin->PinType.IsArray() ? TEXT("Graph.ArrayPin.Connected") : TEXT("Graph.Pin.Connected") ); + } + } + + FBlueprintActionContext MenuContext; + ConstructActionContext(MenuContext); + + TSharedPtr AddImportTargetContent = SNullWidget::NullWidget; + if (GetDefault()->bEnableNamespaceImportingFeatures) + { + SAssignNew(AddImportTargetContent, SBox) + .ToolTipText(LOCTEXT("ImportActionLabelTooltip", "Choose a namespace to import and load additional actions.")) + [ + SNew(SHorizontalBox) + +SHorizontalBox::Slot() + .AutoWidth() + .VAlign(VAlign_Center) + [ + SNew(STextBlock) + .Text(LOCTEXT("ImportActionButtonLabel", "Import Actions From:")) + ] + +SHorizontalBox::Slot() + .AutoWidth() + .Padding(4.f, 0.f) + [ + SNew(SBlueprintNamespaceEntry) + .AllowTextEntry(false) + .OnNamespaceSelected(this, &SBlueprintActionMenu::OnNamespaceSelectedForImport) + .OnGetNamespacesToExclude(this, &SBlueprintActionMenu::OnGetNamespacesToExcludeFromImportMenu) + .ExcludedNamespaceTooltipText(LOCTEXT("CannotSelectNamespaceForImport", "This namespace has already been imported by this Blueprint.")) + ] + ]; + } + + TSharedPtr TargetContextSubMenuButton; + // @TODO: would be nice if we could use a checkbox style for this, and have a different state for open/closed + SAssignNew(TargetContextSubMenuButton, SComboButton) + .MenuPlacement(MenuPlacement_MenuRight) + .HasDownArrow(false) + .ButtonStyle(FAppStyle::Get(), "BlueprintEditor.ContextMenu.TargetsButton") + .ContentPadding(FMargin(5)) + .MenuContent() + [ + SAssignNew(ContextTargetSubMenu, SBlueprintContextTargetMenu, MenuContext) + .OnTargetMaskChanged(this, &SBlueprintActionMenu::OnContextTargetsChanged) + .CustomTargetContent() + [ + AddImportTargetContent.ToSharedRef() + ] + ]; + + // Build the widget layout + TSharedRef ContentBox = SNew(SBox); + { + TSharedRef VBox = SNew(SVerticalBox); + { + SVerticalBox::FSlot::FSlotArguments + SearchIndicator = SVerticalBox::Slot(); + { + TSharedRef HBox = SNew(SHorizontalBox); + { + SHorizontalBox::FSlot::FSlotArguments + TypePill = SHorizontalBox::Slot(); + { + TSharedRef PillImage = SNew(SImage); + { + SImage::FArguments Args; + Args.Visibility(this, & SBlueprintActionMenu::GetTypeImageVisibility); + PillImage->SetColorAndOpacity(TypeColor); + PillImage->SetImage(ContextIcon); + PillImage->Construct(Args); + } + SHorizontalBox::FSlot* Slot; TypePill.Expose(Slot); + TypePill.AutoWidth(); + TypePill.VAlign(VAlign_Center); + TypePill.Padding( FMargin(0.f, 0.f, (ContextIcon != nullptr) ? 5.f : 0.f, 0.f)); + TypePill.AttachWidget(PillImage); + } + + SHorizontalBox::FSlot::FSlotArguments + SearchContextDescription = SHorizontalBox::Slot(); + { + TSharedRef TextBlock = SNew(STextBlock); + { + STextBlock::FArguments Args; + Args.Text(this, & SBlueprintActionMenu::GetSearchContextDesc); + Args.Font(FAppStyle::GetFontStyle(FName("BlueprintEditor.ActionMenu.ContextDescriptionFont"))); + Args.ToolTip(IDocumentation::Get()->CreateToolTip( + LOCTEXT("BlueprintActionMenuContextTextTooltip", "Describes the current context of the action list"), + NULL, + TEXT("Shared/Editors/BlueprintEditor"), + TEXT("BlueprintActionMenuContextText"))); + Args.AutoWrapText(true); + TextBlock->Construct(Args); + } + SearchContextDescription.FillWidth(1.f); + SearchContextDescription.VAlign(VAlign_Center); + SearchContextDescription.AttachWidget(TextBlock); + } + + SHorizontalBox::FSlot::FSlotArguments + ContextToggle = SHorizontalBox::Slot(); + { + TSharedRef CheckBox = SNew(SCheckBox); + { + SCheckBox::FArguments Args; + Args.OnCheckStateChanged(this, & SBlueprintActionMenu::OnContextToggleChanged); + Args.IsChecked(this, & SBlueprintActionMenu::ContextToggleIsChecked); + Args.ToolTip(IDocumentation::Get()->CreateToolTip( + LOCTEXT("BlueprintActionMenuContextToggleTooltip" + , "Should the list be filtered to only actions that make sense in the current context?"), + NULL, + TEXT("Shared/Editors/BlueprintEditor"), + TEXT("BlueprintActionMenuContextToggle"))); + Args.Content().SlotContent.Widget = SNew(STextBlock) + .Text(LOCTEXT("BlueprintActionMenuContextToggle", "Context Sensitive")); + CheckBox->Construct(Args); + } + ContextToggle.HAlign(HAlign_Right); + ContextToggle.VAlign(VAlign_Center); + ContextToggle.AutoWidth(); + ContextToggle.AttachWidget( CheckBox ); + } + + SHorizontalBox::FSlot::FSlotArguments + ContextButton = SHorizontalBox::Slot(); + { + ContextButton.HAlign(HAlign_Right); + ContextButton.VAlign(VAlign_Center); + ContextButton.AutoWidth(); + ContextButton.Padding( FMargin( 3.f, 0.f, 0.f, 0.f )); + ContextButton.AttachWidget( TargetContextSubMenuButton.ToSharedRef() ); + } + + SHorizontalBox::FArguments Args = SHorizontalBox::FArguments(); + Args.operator+( TypePill ); + Args.operator+( SearchContextDescription ); + Args.operator+( ContextToggle ); + Args.operator+( ContextButton ); + HBox->Construct(Args); + } + + SearchIndicator.AutoHeight(); + SearchIndicator.Padding( FMargin(2, 2, 2, 5)); + SearchIndicator.AttachWidget(HBox); + } + + SVerticalBox::FSlot::FSlotArguments + ActionList = SVerticalBox::Slot(); + { + SAssignNew( GraphActionMenu, SGraphActionMenu); + + SGraphActionMenu::FArguments Args; + Args.OnActionSelected(this, &SBlueprintActionMenu::OnActionSelected); + Args.OnCreateWidgetForAction(SGraphActionMenu::FOnCreateWidgetForAction::CreateSP(this, &SBlueprintActionMenu::OnCreateWidgetForAction)); + Args.OnGetActionList(this, &SBlueprintActionMenu::OnGetActionList); + Args.OnCreateCustomRowExpander_Static(&CreateCustomBlueprintActionExpander); + Args.DraggedFromPins(DraggedFromPins); + Args.GraphObj(GraphObj); + GraphActionMenu->Construct(Args); + + ActionList.AttachWidget( GraphActionMenu.ToSharedRef() ); + } + + SVerticalBox::FSlot::FSlotArguments + ProgressBar = SVerticalBox::Slot(); + { + TSharedRef Box = SNew(SBox); + { + TSharedRef Bar = SNew(SProgressBar); + { + Bar->SetBorderPadding(FVector2D( 0, 0 )); + Bar->SetPercent( TAttribute>::CreateLambda([this]() + { + return ContextMenuBuilder.IsValid() ? ContextMenuBuilder->GetPendingActionsProgress() : 0.0f; + })); + } + Box->SetContent( Bar ); + Box->SetHeightOverride(2); + Box->SetVisibility(TAttribute().CreateLambda([this]() + { + return ContextMenuBuilder.IsValid() && ContextMenuBuilder->GetNumPendingActions() > 0 ? EVisibility::SelfHitTestInvisible : EVisibility::Collapsed; + })); + } + ProgressBar.AutoHeight(); + ProgressBar.AttachWidget(Box); + } + + SVerticalBox::FArguments Args; + Args.operator+( SearchIndicator ); + Args.operator+( ActionList ); + Args.operator+( ProgressBar ); + VBox->Construct( Args ); + } + + ContentBox->SetMaxDesiredWidth(500.f); + ContentBox->SetMaxDesiredHeight(650.f); + ContentBox->SetContent( VBox ); + + SBorder::FArguments Args; + Args.BorderImage(FAppStyle::GetBrush("Menu.Background")); + Args.Padding(5.0f); + Args.operator[](ContentBox); + SBorder::Construct(Args); + } +})"); + +void change_SBlueprintActionMenu_Construct() +{ +#define path_SBlueprintActionMenuCpp \ + R"(C:\projects\Unreal\Surgo\UE\Engine\Source\Editor\Kismet\Private\SBlueprintActionMenu.cpp)" + + FileContents content = file_read_contents( GlobalAllocator, true, path_SBlueprintActionMenuCpp ); + CodeBody parsed_SBlueprintActionMenu = parse_global_body( StrC { content.size, (char const*)content.data }); + + CodeFn signature_to_change = parse_function( code( + void SBlueprintActionMenu::Construct( const FArguments& InArgs, TSharedPtr InEditor ) {} + )); + + CodeBody changed_SBlueprintActionMenu = def_body(ECode::Global_Body); + for ( Code code : parsed_SBlueprintActionMenu ) + { + switch ( code->Type ) + { + using namespace ECode; + case Function: + CodeFn function_def = code.cast(); + + if ( String::are_equal(function_def->Name, signature_to_change->Name) + && function_def->Params.is_equal(signature_to_change->Params)) + { + code = parse_function( SBlueprintActionMenu_Construct_Replacement ); + log_fmt("Swapped: %S", function_def->Name); + } + break; + } + changed_SBlueprintActionMenu.append(code); + } + log_fmt("\n"); + + Builder SBlueprintActionMenu_Changed = Builder::open(path_SBlueprintActionMenuCpp); + SBlueprintActionMenu_Changed.print( def_comment(txt("This file was regenerated by GasaGen/ChangeBPActionMenu.cpp"))); + SBlueprintActionMenu_Changed.print(changed_SBlueprintActionMenu); + SBlueprintActionMenu_Changed.write(); + format_file(path_SBlueprintActionMenuCpp, false); +} diff --git a/Project/Source/GasaEditor/GasaGen/ChangeBPActionMenu.h b/Project/Source/GasaEditor/GasaGen/ChangeBPActionMenu.h new file mode 100644 index 0000000..00f7dbc --- /dev/null +++ b/Project/Source/GasaEditor/GasaGen/ChangeBPActionMenu.h @@ -0,0 +1,3 @@ +#pragma once + +void change_SBlueprintActionMenu_Construct(); diff --git a/Project/Source/GasaEditor/GasaGen/ChangeEditorContentList.cpp b/Project/Source/GasaEditor/GasaGen/ChangeEditorContentList.cpp new file mode 100644 index 0000000..3928f20 --- /dev/null +++ b/Project/Source/GasaEditor/GasaGen/ChangeEditorContentList.cpp @@ -0,0 +1,727 @@ +#include "ChangeEditorContentList.h" + +#include "GasaGen_Common.h" +#include "GasaEditorCommon.h" + +constexpr StrC SAssetView_Construct_Replacement = txt(R"( +void SAssetView::Construct( const FArguments& InArgs ) +{ + ViewCorrelationGuid = FGuid::NewGuid(); + + InitialNumAmortizedTasks = 0; + TotalAmortizeTime = 0; + AmortizeStartTime = 0; + MaxSecondsPerFrame = 0.015f; + + bFillEmptySpaceInTileView = InArgs._FillEmptySpaceInTileView; + FillScale = 1.0f; + + bShowRedirectors = InArgs._ShowRedirectors; + bLastShowRedirectors = bShowRedirectors.Get(false); + + ThumbnailHintFadeInSequence.JumpToStart(); + ThumbnailHintFadeInSequence.AddCurve(0, 0.5f, ECurveEaseFunction::Linear); + + UContentBrowserDataSubsystem* ContentBrowserData = IContentBrowserDataModule::Get().GetSubsystem(); + ContentBrowserData->OnItemDataUpdated().AddSP(this, &SAssetView::HandleItemDataUpdated); + ContentBrowserData->OnItemDataRefreshed().AddSP(this, &SAssetView::RequestSlowFullListRefresh); + ContentBrowserData->OnItemDataDiscoveryComplete().AddSP(this, &SAssetView::HandleItemDataDiscoveryComplete); + FilterCacheID.Initialaze(ContentBrowserData); + + FCollectionManagerModule& CollectionManagerModule = FCollectionManagerModule::GetModule(); + CollectionManagerModule.Get().OnAssetsAddedToCollection().AddSP( this, &SAssetView::OnAssetsAddedToCollection ); + CollectionManagerModule.Get().OnAssetsRemovedFromCollection().AddSP( this, &SAssetView::OnAssetsRemovedFromCollection ); + CollectionManagerModule.Get().OnCollectionRenamed().AddSP( this, &SAssetView::OnCollectionRenamed ); + CollectionManagerModule.Get().OnCollectionUpdated().AddSP( this, &SAssetView::OnCollectionUpdated ); + + // Listen for when view settings are changed + UContentBrowserSettings::OnSettingChanged().AddSP(this, &SAssetView::HandleSettingChanged); + + ThumbnailSize = InArgs._InitialThumbnailSize; + + // Get desktop metrics + FDisplayMetrics DisplayMetrics; + FSlateApplication::Get().GetCachedDisplayMetrics( DisplayMetrics ); + + const FIntPoint DisplaySize( + DisplayMetrics.PrimaryDisplayWorkAreaRect.Right - DisplayMetrics.PrimaryDisplayWorkAreaRect.Left, + DisplayMetrics.PrimaryDisplayWorkAreaRect.Bottom - DisplayMetrics.PrimaryDisplayWorkAreaRect.Top ); + + ThumbnailScaleRangeScalar = (float)DisplaySize.Y / 2160.f; + + // Use the shared ThumbnailPool for the rendering of thumbnails + AssetThumbnailPool = UThumbnailManager::Get().GetSharedThumbnailPool(); + NumOffscreenThumbnails = 128; + ListViewThumbnailResolution = 128; + ListViewThumbnailSize = 32; + ListViewThumbnailPadding = 2; + TileViewThumbnailResolution = 256; + + // Max Size for the thumbnail +#if UE_CONTENTBROWSER_NEW_STYLE + constexpr int32 MaxTileViewThumbnailSize = 160; +#else + constexpr int32 MaxTileViewThumbnailSize = 150; +#endif + + TileViewThumbnailSize = MaxTileViewThumbnailSize; + + TileViewThumbnailPadding = 9; + + TileViewNameHeight = 50; + + UpdateThumbnailSizeValue(); + MinThumbnailScale = 0.1f * ThumbnailScaleRangeScalar; + MaxThumbnailScale = 1.9f * ThumbnailScaleRangeScalar; + + bCanShowClasses = InArgs._CanShowClasses; + + bCanShowFolders = InArgs._CanShowFolders; + + bCanShowReadOnlyFolders = InArgs._CanShowReadOnlyFolders; + + bFilterRecursivelyWithBackendFilter = InArgs._FilterRecursivelyWithBackendFilter; + + bCanShowRealTimeThumbnails = InArgs._CanShowRealTimeThumbnails; + + bCanShowDevelopersFolder = InArgs._CanShowDevelopersFolder; + + bCanShowFavorites = InArgs._CanShowFavorites; + bCanDockCollections = InArgs._CanDockCollections; + + SelectionMode = InArgs._SelectionMode; + + bShowPathInColumnView = InArgs._ShowPathInColumnView; + bShowTypeInColumnView = InArgs._ShowTypeInColumnView; + bSortByPathInColumnView = bShowPathInColumnView && InArgs._SortByPathInColumnView; + bShowTypeInTileView = InArgs._ShowTypeInTileView; + bForceShowEngineContent = InArgs._ForceShowEngineContent; + bForceShowPluginContent = InArgs._ForceShowPluginContent; + bForceHideScrollbar = InArgs._ForceHideScrollbar; + bShowDisallowedAssetClassAsUnsupportedItems = InArgs._ShowDisallowedAssetClassAsUnsupportedItems; + + bPendingUpdateThumbnails = false; + bShouldNotifyNextAssetSync = true; + CurrentThumbnailSize = TileViewThumbnailSize; + + SourcesData = InArgs._InitialSourcesData; + BackendFilter = InArgs._InitialBackendFilter; + + FrontendFilters = InArgs._FrontendFilters; + if (FrontendFilters.IsValid()) + { + FrontendFilters->OnChanged().AddSP(this, &SAssetView::OnFrontendFiltersChanged); + } + TextFilter = InArgs._TextFilter; + if (TextFilter.IsValid()) + { + TextFilter->OnChanged().AddSP(this, &SAssetView::OnFrontendFiltersChanged); + } + + OnShouldFilterAsset = InArgs._OnShouldFilterAsset; + OnShouldFilterItem = InArgs._OnShouldFilterItem; + + OnNewItemRequested = InArgs._OnNewItemRequested; + OnItemSelectionChanged = InArgs._OnItemSelectionChanged; + OnItemsActivated = InArgs._OnItemsActivated; + OnGetItemContextMenu = InArgs._OnGetItemContextMenu; + OnItemRenameCommitted = InArgs._OnItemRenameCommitted; + OnAssetTagWantsToBeDisplayed = InArgs._OnAssetTagWantsToBeDisplayed; + OnIsAssetValidForCustomToolTip = InArgs._OnIsAssetValidForCustomToolTip; + OnGetCustomAssetToolTip = InArgs._OnGetCustomAssetToolTip; + OnVisualizeAssetToolTip = InArgs._OnVisualizeAssetToolTip; + OnAssetToolTipClosing = InArgs._OnAssetToolTipClosing; + OnGetCustomSourceAssets = InArgs._OnGetCustomSourceAssets; + HighlightedText = InArgs._HighlightedText; + ThumbnailLabel = InArgs._ThumbnailLabel; + AllowThumbnailHintLabel = InArgs._AllowThumbnailHintLabel; + InitialCategoryFilter = InArgs._InitialCategoryFilter; + AssetShowWarningText = InArgs._AssetShowWarningText; + bAllowDragging = InArgs._AllowDragging; + bAllowFocusOnSync = InArgs._AllowFocusOnSync; + HiddenColumnNames = DefaultHiddenColumnNames = InArgs._HiddenColumnNames; + CustomColumns = InArgs._CustomColumns; + OnSearchOptionsChanged = InArgs._OnSearchOptionsChanged; + bShowPathViewFilters = InArgs._bShowPathViewFilters; + OnExtendAssetViewOptionsMenuContext = InArgs._OnExtendAssetViewOptionsMenuContext; + AssetViewOptionsProfile = InArgs._AssetViewOptionsProfile; + + if ( InArgs._InitialViewType >= 0 && InArgs._InitialViewType < EAssetViewType::MAX ) + { + CurrentViewType = InArgs._InitialViewType; + } + else + { + CurrentViewType = EAssetViewType::Tile; + } + + bPendingSortFilteredItems = false; + bQuickFrontendListRefreshRequested = false; + bSlowFullListRefreshRequested = false; + LastSortTime = 0; + SortDelaySeconds = 8; + + bBulkSelecting = false; + bAllowThumbnailEditMode = InArgs._AllowThumbnailEditMode; + bThumbnailEditMode = false; + bUserSearching = false; + bPendingFocusOnSync = false; + bWereItemsRecursivelyFiltered = false; + + OwningContentBrowser = InArgs._OwningContentBrowser; + + FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked("AssetTools"); + AssetClassPermissionList = AssetToolsModule.Get().GetAssetClassPathPermissionList(EAssetClassAction::ViewAsset); + FolderPermissionList = AssetToolsModule.Get().GetFolderPermissionList(); + WritableFolderPermissionList = AssetToolsModule.Get().GetWritableFolderPermissionList(); + + if(InArgs._AllowCustomView) + { + FContentBrowserModule& ContentBrowserModule = FModuleManager::GetModuleChecked(TEXT("ContentBrowser")); + + if(ContentBrowserModule.GetContentBrowserViewExtender().IsBound()) + { + ViewExtender = ContentBrowserModule.GetContentBrowserViewExtender().Execute(); + + // Bind the delegates the custom view is responsible for firing + if(ViewExtender) + { + ViewExtender->OnSelectionChanged().BindSP(this, &SAssetView::AssetSelectionChanged); + ViewExtender->OnContextMenuOpened().BindSP(this, &SAssetView::OnGetContextMenuContent); + ViewExtender->OnItemScrolledIntoView().BindSP(this, &SAssetView::ItemScrolledIntoView); + ViewExtender->OnItemDoubleClicked().BindSP(this, &SAssetView::OnListMouseButtonDoubleClick); + } + } + } + + FEditorWidgetsModule& EditorWidgetsModule = FModuleManager::LoadModuleChecked("EditorWidgets"); + TSharedRef AssetDiscoveryIndicator = EditorWidgetsModule.CreateAssetDiscoveryIndicator(EAssetDiscoveryIndicatorScaleMode::Scale_Vertical); + + TSharedRef VerticalBox = SNew(SVerticalBox); + + BindCommands(); + + ChildSlot + .Padding(0.0f) + [ + SNew(SBorder) + .Padding(0.f) + .BorderImage(FAppStyle::Get().GetBrush("Brushes.Panel")) + [ + VerticalBox + ] + ]; + + // Assets area + VerticalBox->AddSlot() + .FillHeight(1.f) + [ + SNew( SVerticalBox ) + + + SVerticalBox::Slot() + .AutoHeight() + [ + SNew( SBox ) + .Visibility_Lambda([this] { return InitialNumAmortizedTasks > 0 ? EVisibility::SelfHitTestInvisible : EVisibility::Collapsed; }) + .HeightOverride( 2.f ) + [ + SNew( SProgressBar ) + .Percent( this, &SAssetView::GetIsWorkingProgressBarState ) + .BorderPadding( FVector2D(0,0) ) + ] + ] + + + SVerticalBox::Slot() + .FillHeight(1.f) + [ + SNew(SOverlay) + + + SOverlay::Slot() + .HAlign(HAlign_Fill) + .VAlign(VAlign_Fill) + [ + SAssignNew(ViewContainer, SBox) + .Padding(6.0f) + + ] + + + SOverlay::Slot() + .HAlign(HAlign_Fill) + .VAlign(VAlign_Center) + .Padding(FMargin(0, 14, 0, 0)) + [ + // A warning to display when there are no assets to show + SNew( STextBlock ) + .Justification( ETextJustify::Center ) + .Text( this, &SAssetView::GetAssetShowWarningText ) + .Visibility( this, &SAssetView::IsAssetShowWarningTextVisible ) + .AutoWrapText( true ) + ] + + + SOverlay::Slot() + .HAlign(HAlign_Fill) + .VAlign(VAlign_Bottom) + .Padding(FMargin(24, 0, 24, 0)) + [ + // Asset discovery indicator + AssetDiscoveryIndicator + ] + + + SOverlay::Slot() + .HAlign(HAlign_Right) + .VAlign(VAlign_Bottom) + .Padding(FMargin(8, 0)) + [ + SNew(SBorder) + .BorderImage(FAppStyle::GetBrush("ErrorReporting.EmptyBox")) + .BorderBackgroundColor(this, &SAssetView::GetQuickJumpColor) + .Visibility(this, &SAssetView::IsQuickJumpVisible) + [ + SNew(STextBlock) + .Text(this, &SAssetView::GetQuickJumpTerm) + ] + ] + ] + ]; + + // Thumbnail edit mode banner + VerticalBox->AddSlot() + .AutoHeight() + .Padding(0.f, 4.f) + [ + SNew(SBorder) + .Visibility( this, &SAssetView::GetEditModeLabelVisibility ) + .BorderImage(FAppStyle::Get().GetBrush("Brushes.Panel")) + .Content() + [ + SNew(SHorizontalBox) + +SHorizontalBox::Slot() + .VAlign(VAlign_Center) + .Padding(4.f, 0.f, 0.f, 0.f) + .FillWidth(1.f) + [ + SNew(STextBlock) + .Text(LOCTEXT("ThumbnailEditModeLabel", "Editing Thumbnails. Drag a thumbnail to rotate it if there is a 3D environment.")) + .ColorAndOpacity(FAppStyle::Get().GetSlateColor("Colors.Primary")) + ] + + +SHorizontalBox::Slot() + .AutoWidth() + .VAlign(VAlign_Center) + [ + SNew(SPrimaryButton) + .Text(LOCTEXT("EndThumbnailEditModeButton", "Done Editing")) + .OnClicked(this, &SAssetView::EndThumbnailEditModeClicked) + ] + ] + ]; + + if (InArgs._ShowBottomToolbar) + { + // Bottom panel + VerticalBox->AddSlot() + .AutoHeight() + [ + SNew(SHorizontalBox) + + // Asset count + +SHorizontalBox::Slot() + .FillWidth(1.f) + .VAlign(VAlign_Center) + .Padding(8, 5) + [ + SNew(STextBlock) + .Text(this, &SAssetView::GetAssetCountText) + ] + + // View mode combo button + +SHorizontalBox::Slot() + .AutoWidth() + [ + SNew(SComboButton) + .Visibility(InArgs._ShowViewOptions ? EVisibility::Visible : EVisibility::Collapsed) + .ContentPadding(0.f) + .ButtonStyle( FAppStyle::Get(), "ToggleButton" ) // Use the tool bar item style for this button + .OnGetMenuContent( this, &SAssetView::GetViewButtonContent ) + .ButtonContent() + [ + SNew(SHorizontalBox) + + +SHorizontalBox::Slot() + .AutoWidth() + .VAlign(VAlign_Center) + [ + SNew(SImage) + .Image( FAppStyle::GetBrush("GenericViewButton") ) + ] + + +SHorizontalBox::Slot() + .AutoWidth() + .Padding(2.f, 0.f, 0.f, 0.f) + .VAlign(VAlign_Center) + [ + SNew(STextBlock) + .Text( LOCTEXT("ViewButton", "View Options") ) + ] + ] + ] + ]; + } + + CreateCurrentView(); + + if( InArgs._InitialAssetSelection.IsValid() ) + { + // sync to the initial item without notifying of selection + bShouldNotifyNextAssetSync = false; + SyncToLegacy( MakeArrayView(&InArgs._InitialAssetSelection, 1), TArrayView() ); + } + + // If currently looking at column, and you could choose to sort by path in column first and then name + // Generalizing this is a bit difficult because the column ID is not accessible or is not known + // Currently I assume this won't work, if this view mode is not column. Otherwise, I don't think sorting by path + // is a good idea. + if (CurrentViewType == EAssetViewType::Column && bSortByPathInColumnView) + { + SortManager.SetSortColumnId(EColumnSortPriority::Primary, SortManager.PathColumnId); + SortManager.SetSortColumnId(EColumnSortPriority::Secondary, SortManager.NameColumnId); + SortManager.SetSortMode(EColumnSortPriority::Primary, EColumnSortMode::Ascending); + SortManager.SetSortMode(EColumnSortPriority::Secondary, EColumnSortMode::Ascending); + SortList(); + } +})"); + +constexpr StrC SAssetView_GetThumbnailScale_Replacement = txt(R"( +float SAssetView::GetThumbnailScale() const +{ + float BaseScale; + switch (ThumbnailSize) + { + case EThumbnailSize::Tiny: + BaseScale = 0.1f; + break; + case EThumbnailSize::Small: + BaseScale = 0.25f; + break; + case EThumbnailSize::Medium: + BaseScale = 0.40f; + break; + case EThumbnailSize::Large: + BaseScale = 0.60f; + break; + case EThumbnailSize::XLarge: + BaseScale = 0.8f; + break; + case EThumbnailSize::Huge: + BaseScale = 1.0f; + break; + default: + BaseScale = 0.5f; + break; + } + + return BaseScale * GetTickSpaceGeometry().Scale; +})"); + +constexpr StrC SPropertyMenuAssetPicker_Construct_Replacement = txt(R"( +void SPropertyMenuAssetPicker::Construct( const FArguments& InArgs ) +{ + CurrentObject = InArgs._InitialObject; + PropertyHandle = InArgs._PropertyHandle; + const TArray& OwnerAssetArray = InArgs._OwnerAssetArray; + bAllowClear = InArgs._AllowClear; + bAllowCopyPaste = InArgs._AllowCopyPaste; + AllowedClasses = InArgs._AllowedClasses; + DisallowedClasses = InArgs._DisallowedClasses; + NewAssetFactories = InArgs._NewAssetFactories; + OnShouldFilterAsset = InArgs._OnShouldFilterAsset; + OnSet = InArgs._OnSet; + OnClose = InArgs._OnClose; + + const bool bForceShowEngineContent = PropertyHandle ? PropertyHandle->HasMetaData(TEXT("ForceShowEngineContent")) : false; + const bool bForceShowPluginContent = PropertyHandle ? PropertyHandle->HasMetaData(TEXT("ForceShowPluginContent")) : false; + + const bool bInShouldCloseWindowAfterMenuSelection = true; + const bool bCloseSelfOnly = true; + const bool bSearchable = false; + + FMenuBuilder MenuBuilder(bInShouldCloseWindowAfterMenuSelection, nullptr, nullptr, bCloseSelfOnly, &FCoreStyle::Get(), bSearchable); + + if (NewAssetFactories.Num() > 0) + { + MenuBuilder.BeginSection(NAME_None, LOCTEXT("CreateNewAsset", "Create New Asset")); + { + for (UFactory* Factory : NewAssetFactories) + { + TWeakObjectPtr FactoryPtr(Factory); + + MenuBuilder.AddMenuEntry( + Factory->GetDisplayName(), + Factory->GetToolTip(), + FSlateIconFinder::FindIconForClass(Factory->GetSupportedClass()), + FUIAction(FExecuteAction::CreateSP(this, &SPropertyMenuAssetPicker::OnCreateNewAssetSelected, FactoryPtr)) + ); + } + } + MenuBuilder.EndSection(); + } + + if (CurrentObject.IsValid() || bAllowCopyPaste || bAllowClear) + { + MenuBuilder.BeginSection(NAME_None, LOCTEXT("CurrentAssetOperationsHeader", "Current Asset")); + { + if (CurrentObject.IsValid()) + { + MenuBuilder.AddMenuEntry( + LOCTEXT("EditAsset", "Edit"), + LOCTEXT("EditAsset_Tooltip", "Edit this asset"), + FSlateIcon(FAppStyle::GetAppStyleSetName(),"Icons.Edit"), + FUIAction(FExecuteAction::CreateSP(this, &SPropertyMenuAssetPicker::OnEdit))); + } + + if (bAllowCopyPaste) + { + MenuBuilder.AddMenuEntry( + LOCTEXT("CopyAsset", "Copy"), + LOCTEXT("CopyAsset_Tooltip", "Copies the asset to the clipboard"), + FSlateIcon(FAppStyle::GetAppStyleSetName(),"GenericCommands.Copy"), + FUIAction(FExecuteAction::CreateSP(this, &SPropertyMenuAssetPicker::OnCopy)) + ); + + MenuBuilder.AddMenuEntry( + LOCTEXT("PasteAsset", "Paste"), + LOCTEXT("PasteAsset_Tooltip", "Pastes an asset from the clipboard to this field"), + FSlateIcon(FAppStyle::GetAppStyleSetName(),"GenericCommands.Paste"), + FUIAction( + FExecuteAction::CreateSP(this, &SPropertyMenuAssetPicker::OnPaste), + FCanExecuteAction::CreateSP(this, &SPropertyMenuAssetPicker::CanPaste)) + ); + } + + if (bAllowClear) + { + MenuBuilder.AddMenuEntry( + LOCTEXT("ClearAsset", "Clear"), + LOCTEXT("ClearAsset_ToolTip", "Clears the asset set on this field"), + FSlateIcon(FAppStyle::GetAppStyleSetName(),"GenericCommands.Delete"), + FUIAction(FExecuteAction::CreateSP(this, &SPropertyMenuAssetPicker::OnClear)) + ); + } + } + MenuBuilder.EndSection(); + } + + MenuBuilder.BeginSection(NAME_None, LOCTEXT("BrowseHeader", "Browse")); + { + FContentBrowserModule& ContentBrowserModule = FModuleManager::Get().LoadModuleChecked(TEXT("ContentBrowser")); + + FAssetPickerConfig AssetPickerConfig; + // Add filter classes - if we have a single filter class of "Object" then don't set a filter since it would always match everything (but slower!) + if (AllowedClasses.Num() == 1 && AllowedClasses[0] == UObject::StaticClass()) + { + AssetPickerConfig.Filter.ClassPaths.Reset(); + } + else + { + for(int32 i = 0; i < AllowedClasses.Num(); ++i) + { + AssetPickerConfig.Filter.ClassPaths.Add( AllowedClasses[i]->GetClassPathName() ); + } + } + + for (int32 i = 0; i < DisallowedClasses.Num(); ++i) + { + AssetPickerConfig.Filter.RecursiveClassPathsExclusionSet.Add(DisallowedClasses[i]->GetClassPathName()); + } + + // Allow child classes + AssetPickerConfig.Filter.bRecursiveClasses = true; + // Set a delegate for setting the asset from the picker + AssetPickerConfig.OnAssetSelected = FOnAssetSelected::CreateSP(this, &SPropertyMenuAssetPicker::OnAssetSelected); + // Set a delegate for setting the asset from the picker via the keyboard + AssetPickerConfig.OnAssetEnterPressed = FOnAssetEnterPressed::CreateSP(this, &SPropertyMenuAssetPicker::OnAssetEnterPressed); + // Use the list view by default + AssetPickerConfig.InitialAssetViewType = EAssetViewType::List; + // The initial selection should be the current value + AssetPickerConfig.InitialAssetSelection = CurrentObject; + // We'll do clearing ourselves + AssetPickerConfig.bAllowNullSelection = false; + // Focus search box + AssetPickerConfig.bFocusSearchBoxWhenOpened = true; + // Apply custom filter + AssetPickerConfig.OnShouldFilterAsset = OnShouldFilterAsset; + // Don't allow dragging + AssetPickerConfig.bAllowDragging = false; + + // Note(Ed): Personal changes + AssetPickerConfig.ThumbnailScale = 0.25; + AssetPickerConfig.InitialThumbnailSize = EThumbnailSize::Small; + + // Save the settings into a special section for asset pickers for properties + AssetPickerConfig.SaveSettingsName = TEXT("AssetPropertyPicker"); + // Populate the referencing assets via property handle + AssetPickerConfig.PropertyHandle = PropertyHandle; + // Populate the additional referencing assets with the Owner asset data + AssetPickerConfig.AdditionalReferencingAssets = OwnerAssetArray; + // Force show engine content if meta data says so + AssetPickerConfig.bForceShowEngineContent = bForceShowEngineContent; + // Force show plugin content if meta data says so + AssetPickerConfig.bForceShowPluginContent = bForceShowPluginContent; + + AssetPickerWidget = ContentBrowserModule.Get().CreateAssetPicker(AssetPickerConfig); + + TSharedRef MenuContent = + SNew(SBox) + .WidthOverride(static_cast(PropertyEditorAssetConstants::ContentBrowserWindowSize.X)) + .HeightOverride(static_cast(PropertyEditorAssetConstants::ContentBrowserWindowSize.Y)) + [ + AssetPickerWidget.ToSharedRef() + ]; + + MenuBuilder.AddWidget(MenuContent, FText::GetEmpty(), true); + } + MenuBuilder.EndSection(); + + ChildSlot + [ + MenuBuilder.MakeWidget() + ]; +})"); + +void change_EditorContentList() +{ + // Change property editor constant + { + #define path_PropertyEditorAssetConstantsHeader \ + R"(C:\Projects\Unreal\Surgo\UE\Engine\Source\Editor\PropertyEditor\Private\UserInterface\PropertyEditor\PropertyEditorAssetConstants.h)" + + FileContents content = file_read_contents( GlobalAllocator, true, path_PropertyEditorAssetConstantsHeader ); + CodeBody parsed_PropertyEditorAssetConstantsHeader = parse_global_body( StrC { content.size, (char const*)content.data }); + + CodeBody changed_PropertyEditorAssetConstantsHeader = def_body(ECode::Global_Body); + for ( Code code : parsed_PropertyEditorAssetConstantsHeader ) + { + switch ( code->Type ) + { + using namespace ECode; + case Namespace: + CodeNS ns = code.cast(); + for ( Code ns_code : ns->Body ) + { + switch ( ns_code->Type ) + { + case Variable: + CodeVar var = ns_code.cast(); + if ( var->Name.starts_with(txt("ContentBrowserWindowSize")) ) + { + // Swap value with new value + var->Value->Content = get_cached_string(txt("300.0f, 600.0f")); + Gasa::LogEditor("Swapped: " + to_fstring(var->Name)); + } + + break; + } + } + break; + } + changed_PropertyEditorAssetConstantsHeader.append( code ); + } + + Builder SBlueprintActionMenu_Changed = Builder::open(path_PropertyEditorAssetConstantsHeader); + SBlueprintActionMenu_Changed.print( def_comment(txt("This file was regenerated by GasaGen/ChangeEditorContentList.cpp"))); + SBlueprintActionMenu_Changed.print(changed_PropertyEditorAssetConstantsHeader); + SBlueprintActionMenu_Changed.write(); + format_file(path_PropertyEditorAssetConstantsHeader, false ); + } + + // Change SAssetView's Construct & GetThumbnailScale + { + #define path_SAssetView \ + R"(C:\projects\Unreal\Surgo\UE\Engine\Source\Editor\ContentBrowser\Private\SAssetView.cpp)" + + FileContents content = file_read_contents( GlobalAllocator, true, path_SAssetView ); + CodeBody parsed_SAssetViewCpp = parse_global_body( StrC { content.size, (char const*)content.data }); + + CodeFn signature_Construct = parse_function( code( + void SAssetView::Construct( const FArguments& InArgs ) {} + )); + CodeFn signature_GetThumbnailScale = parse_function( code( + float SAssetView::GetThumbnailScale() const {} + )); + + CodeBody changed_SAssetViewCpp = def_body(ECode::Global_Body); + for ( Code code : parsed_SAssetViewCpp ) + { + switch ( code->Type ) + { + using namespace ECode; + case Function: + { + CodeFn function_def = code.cast(); + + if ( String::are_equal(function_def->Name, signature_Construct->Name) + && function_def->Params.is_equal(signature_Construct->Params)) + { + code = parse_function( SAssetView_Construct_Replacement ); + Gasa::LogEditor("Swapped: " + to_fstring(function_def->Name)); + } + else if ( String::are_equal(function_def->Name, signature_GetThumbnailScale->Name) + && function_def->Params.is_equal(signature_GetThumbnailScale->Params)) + { + code = parse_function( SAssetView_GetThumbnailScale_Replacement ); + Gasa::LogEditor("Swapped: " + to_fstring(function_def->Name)); + } + } + break; + } + changed_SAssetViewCpp.append( code ); + } + + Builder SBlueprintActionMenu_Changed = Builder::open(path_SAssetView); + SBlueprintActionMenu_Changed.print( def_comment(txt("This file was regenerated by GasaGen/ChangeEditorContentList.cpp"))); + SBlueprintActionMenu_Changed.print(changed_SAssetViewCpp); + SBlueprintActionMenu_Changed.write(); + format_file(path_SAssetView, false ); + } + + // Change SAssetView's Construct & GetThumbnailScale + { + #define path_SPropertyMenuAssetPicker \ + R"(C:\projects\Unreal\Surgo\UE\Engine\Source\Editor\PropertyEditor\Private\UserInterface\PropertyEditor\SPropertyMenuAssetPicker.cpp)" + + FileContents content = file_read_contents( GlobalAllocator, true, path_SPropertyMenuAssetPicker ); + CodeBody parsed = parse_global_body( StrC { content.size, (char const*)content.data }); + + CodeFn signature = parse_function( code( + void SPropertyMenuAssetPicker::Construct( const FArguments& InArgs ) {} + )); + + CodeBody changed = def_body(ECode::Global_Body); + for ( Code code : parsed ) + { + switch ( code->Type ) + { + using namespace ECode; + case Function: + { + CodeFn function_def = code.cast(); + + if ( String::are_equal(function_def->Name, signature->Name) + && function_def->Params.is_equal(signature->Params)) + { + code = parse_function( SPropertyMenuAssetPicker_Construct_Replacement ); + Gasa::LogEditor("Swapped: " + to_fstring(function_def->Name)); + } + } + break; + } + changed.append( code ); + } + + Builder SBlueprintActionMenu_Changed = Builder::open(path_SPropertyMenuAssetPicker); + SBlueprintActionMenu_Changed.print( def_comment(txt("This file was regenerated by GasaGen/ChangeEditorContentList.cpp"))); + SBlueprintActionMenu_Changed.print(changed); + SBlueprintActionMenu_Changed.write(); + format_file(path_SPropertyMenuAssetPicker, false ); + } +} diff --git a/Project/Source/GasaEditor/GasaGen/ChangeEditorContentList.h b/Project/Source/GasaEditor/GasaGen/ChangeEditorContentList.h new file mode 100644 index 0000000..7a0d238 --- /dev/null +++ b/Project/Source/GasaEditor/GasaGen/ChangeEditorContentList.h @@ -0,0 +1,3 @@ +#pragma once + +void change_EditorContentList(); diff --git a/Project/Source/GasaEditor/GasaGen/GasaGen_DevOptionsCache.cpp b/Project/Source/GasaEditor/GasaGen/DevOptionsCache.cpp similarity index 99% rename from Project/Source/GasaEditor/GasaGen/GasaGen_DevOptionsCache.cpp rename to Project/Source/GasaEditor/GasaGen/DevOptionsCache.cpp index 9f22504..e6c9b67 100644 --- a/Project/Source/GasaEditor/GasaGen/GasaGen_DevOptionsCache.cpp +++ b/Project/Source/GasaEditor/GasaGen/DevOptionsCache.cpp @@ -1,4 +1,4 @@ -#include "GasaGen_DevOptionsCache.h" +#include "DevOptionsCache.h" #include "GasaGen_Common.h" #pragma push_macro("GASA_API") diff --git a/Project/Source/GasaEditor/GasaGen/GasaGen_DevOptionsCache.h b/Project/Source/GasaEditor/GasaGen/DevOptionsCache.h similarity index 100% rename from Project/Source/GasaEditor/GasaGen/GasaGen_DevOptionsCache.h rename to Project/Source/GasaEditor/GasaGen/DevOptionsCache.h diff --git a/Project/Source/GasaEditor/GasaGen/GasaGen.cpp b/Project/Source/GasaEditor/GasaGen/GasaGen.cpp index e57370d..60bb570 100644 --- a/Project/Source/GasaEditor/GasaGen/GasaGen.cpp +++ b/Project/Source/GasaEditor/GasaGen/GasaGen.cpp @@ -1,9 +1,11 @@ #include "GasaGen.h" #include "GasaGen_Common.h" -#include "GasaGen_AttributeSets.h" -#include "GasaGen_DevOptionsCache.h" +#include "AttributeSets.h" +#include "ChangeBPActionMenu.h" +#include "DevOptionsCache.h" // Editor Module +#include "ChangeEditorContentList.h" #include "GasaEditorCommon.h" #define LOCTEXT_NAMESPACE "GasaEditor" @@ -51,11 +53,11 @@ void Execute_GasaModule_Codegen() #undef USTRUCT #undef GENERATED_BODY #undef GASA_API - UHT_UCLASS = code_str(UCLASS()); - UHT_UPROPERTY = code_str(UPROPERTY()); - UHT_USTRUCT = code_str(USTRUCT()); + UHT_UCLASS = code_str(UCLASS()); + UHT_UPROPERTY = code_str(UPROPERTY()); + UHT_USTRUCT = code_str(USTRUCT()); UHT_GENERATED_BODY = code_str(GENERATED_BODY()\n); - UModule_GASA_API = code_str(GASA_API); + UModule_GASA_API = code_str(GASA_API); #pragma pop_macro("UCLASS") #pragma pop_macro("UPROPERTY") #pragma pop_macro("USTRUCT") @@ -111,9 +113,11 @@ void Execute_GasaModule_Codegen() PreprocessorDefines.append(get_cached_string(str_UE_REQUIRES)); } - generate_AttributeSets(); + // generate_AttributeSets(); //generate_DevOptionsCache(); //generate_HostWidgetController(); + change_SBlueprintActionMenu_Construct(); + change_EditorContentList(); gen::deinit(); }); diff --git a/Project/Source/GasaEditor/GasaGen/GasaGen_Common.h b/Project/Source/GasaEditor/GasaGen/GasaGen_Common.h index 79cc22c..35d98c9 100644 --- a/Project/Source/GasaEditor/GasaGen/GasaGen_Common.h +++ b/Project/Source/GasaEditor/GasaGen/GasaGen_Common.h @@ -1,7 +1,8 @@ #pragma once - +UE_DISABLE_OPTIMIZATION #include "gencpp/gen.hpp" #include "gencpp/gen.builder.hpp" +UE_ENABLE_OPTIMIZATION using namespace gen; // Codegen assumes its working directory is the project @@ -97,10 +98,12 @@ Builder builder_open(char const* path) { // CodeConstructor find_constructor( StrC parent_name, ) inline -void format_file( char const* path ) +void format_file( char const* path, bool relative_path = true ) { String - resolved_path = String::make(GlobalAllocator, StrC(Project_Path)); + resolved_path = String::make_reserve(GlobalAllocator, Project_Path.length()); + if (relative_path) + resolved_path.append(StrC(Project_Path)); resolved_path.append(path); String style_arg = String::make(GlobalAllocator, txt("-style=file:")); @@ -136,3 +139,9 @@ String to_string( FName ue_fname ) { char const* ansi_str = TCHAR_TO_ANSI(*ue_fname.ToString()); return String::make_length(GlobalAllocator, ansi_str, ue_fname.GetStringLength()); } + +FORCEINLINE +FString to_fstring( String string ) +{ + return FString::ConstructFromPtrSize( string.Data, string.length() ); +}