SExtAssetView.cpp 166 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208
  1. // Copyright 2017-2021 marynate. All Rights Reserved.
  2. #include "SExtAssetView.h"
  3. #include "ExtContentBrowserSingleton.h"
  4. #include "ExtAssetThumbnail.h"
  5. #include "ExtAssetViewWidgets.h"
  6. #include "ExtAssetViewTypes.h"
  7. #include "ExtContentBrowserUtils.h"
  8. #include "ExtContentBrowserStyle.h"
  9. #include "SExtAssetDiscoveryIndicator.h"
  10. #include "ExtFrontendFilterBase.h"
  11. #include "ExtAssetDragDropOp.h"
  12. #include "Adapters/DragDropHandler.h"
  13. #include "HAL/FileManager.h"
  14. #include "UObject/UnrealType.h"
  15. #include "Widgets/SOverlay.h"
  16. #include "Engine/GameViewportClient.h"
  17. #include "Factories/Factory.h"
  18. #include "Framework/Commands/UIAction.h"
  19. #include "Textures/SlateIcon.h"
  20. #include "Misc/CommandLine.h"
  21. #include "Misc/ConfigCacheIni.h"
  22. #include "SlateOptMacros.h"
  23. #include "Framework/Application/SlateApplication.h"
  24. #include "Widgets/Images/SImage.h"
  25. #include "Widgets/Notifications/SProgressBar.h"
  26. #include "Widgets/Text/STextBlock.h"
  27. #include "Framework/MultiBox/MultiBoxBuilder.h"
  28. #include "Widgets/Input/SButton.h"
  29. #include "Widgets/Layout/SScrollBorder.h"
  30. #include "Widgets/Input/SComboButton.h"
  31. #include "Widgets/Input/SSlider.h"
  32. #include "Widgets/Notifications/SNotificationList.h"
  33. #include "Widgets/Layout/SSplitter.h"
  34. #include "Widgets/Colors/SColorBlock.h"
  35. #include "Widgets/Colors/SColorPicker.h"
  36. #include "Widgets/Layout/SGridPanel.h"
  37. #include "Framework/Docking/TabManager.h"
  38. #include "EditorStyleSet.h"
  39. #include "Engine/Blueprint.h"
  40. #include "Editor.h"
  41. #include "AssetSelection.h"
  42. #include "AssetRegistry/AssetRegistryModule.h"
  43. #include "IAssetTools.h"
  44. #include "AssetToolsModule.h"
  45. #include "DragAndDrop/AssetDragDropOp.h"
  46. #include "ObjectTools.h"
  47. #include "Framework/Notifications/NotificationManager.h"
  48. #include "HAL/PlatformApplicationMisc.h"
  49. #include "Misc/FileHelper.h"
  50. //#include "Misc/TextFilterUtils.h"
  51. #include "AssetRegistry/AssetRegistryState.h"
  52. #include "Materials/Material.h"
  53. //#include "DragDropHandler.h"
  54. #include "DesktopPlatformModule.h"
  55. #include "EditorWidgetsModule.h"
  56. #include "ContentBrowserDelegates.h"
  57. #include "ContentBrowserModule.h"
  58. #include "LevelEditor.h"
  59. #define LOCTEXT_NAMESPACE "ExtContentBrowser"
  60. #define MAX_THUMBNAIL_SIZE 4096
  61. namespace
  62. {
  63. /** Time delay between recently added items being added to the filtered asset items list */
  64. const double TimeBetweenAddingNewAssets = 0.3;//4.0;
  65. /** Time delay between performing the last jump, and the jump term being reset */
  66. const double JumpDelaySeconds = 2.0;
  67. }
  68. #if ECB_WIP_INITIAL_ASSET
  69. namespace AssetViewUtils
  70. {
  71. /** Higher performance version of FAssetData::IsUAsset()
  72. * Returns true if this is the primary asset in a package, true for maps and assets but false for secondary objects like class redirectors
  73. */
  74. bool IsUAsset(const FAssetData& Item)
  75. {
  76. TextFilterUtils::FNameBufferWithNumber AssetNameBuffer(Item.AssetName);
  77. TextFilterUtils::FNameBufferWithNumber PackageNameBuffer(Item.PackageName);
  78. if (PackageNameBuffer.IsWide())
  79. {
  80. // Skip to final slash
  81. const WIDECHAR* LongPackageAssetNameWide = PackageNameBuffer.GetWideNamePtr();
  82. for (const WIDECHAR* CharPtr = PackageNameBuffer.GetWideNamePtr(); *CharPtr; ++CharPtr)
  83. {
  84. if (*CharPtr == '/')
  85. {
  86. LongPackageAssetNameWide = CharPtr + 1;
  87. }
  88. }
  89. if (AssetNameBuffer.IsWide())
  90. {
  91. return !FCStringWide::Stricmp(LongPackageAssetNameWide, AssetNameBuffer.GetWideNamePtr());
  92. }
  93. else if (FCString::IsPureAnsi(LongPackageAssetNameWide))
  94. {
  95. // Convert PackageName to ANSI for comparison
  96. ANSICHAR LongPackageAssetNameAnsi[NAME_WITH_NUMBER_SIZE];
  97. FPlatformString::Convert(LongPackageAssetNameAnsi, NAME_WITH_NUMBER_SIZE, LongPackageAssetNameWide, FCStringWide::Strlen(LongPackageAssetNameWide) + 1);
  98. return !FCStringAnsi::Stricmp(LongPackageAssetNameAnsi, AssetNameBuffer.GetAnsiNamePtr());
  99. }
  100. }
  101. else if (!AssetNameBuffer.IsWide())
  102. {
  103. // Skip to final slash
  104. const ANSICHAR* LongPackageAssetNameAnsi = PackageNameBuffer.GetAnsiNamePtr();
  105. for (const ANSICHAR* CharPtr = PackageNameBuffer.GetAnsiNamePtr(); *CharPtr; ++CharPtr)
  106. {
  107. if (*CharPtr == '/')
  108. {
  109. LongPackageAssetNameAnsi = CharPtr + 1;
  110. }
  111. }
  112. return !FCStringAnsi::Stricmp(LongPackageAssetNameAnsi, AssetNameBuffer.GetAnsiNamePtr());
  113. }
  114. return false;
  115. }
  116. class FInitialAssetFilter
  117. {
  118. public:
  119. FInitialAssetFilter(bool InDisplayL10N, bool InDisplayEngine, bool InDisplayPlugins) :
  120. bDisplayL10N(InDisplayL10N),
  121. bDisplayEngine(InDisplayEngine),
  122. bDisplayPlugins(InDisplayPlugins)
  123. {
  124. Init(InDisplayL10N, InDisplayEngine, InDisplayPlugins);
  125. }
  126. void Init(bool InDisplayL10N, bool InDisplayEngine, bool InDisplayPlugins)
  127. {
  128. ObjectRedirectorClassName = UObjectRedirector::StaticClass()->GetFName();
  129. bDisplayL10N = InDisplayL10N;
  130. bDisplayEngine = InDisplayEngine;
  131. bDisplayPlugins = InDisplayPlugins;
  132. Plugins = IPluginManager::Get().GetEnabledPluginsWithContent();
  133. PluginNamesUpperWide.Reset(Plugins.Num());
  134. PluginNamesUpperAnsi.Reset(Plugins.Num());
  135. PluginLoadedFromEngine.Reset(Plugins.Num());
  136. for (const TSharedRef<IPlugin>& PluginRef : Plugins)
  137. {
  138. FString& PluginNameUpperWide = PluginNamesUpperWide.Add_GetRef(PluginRef->GetName().ToUpper());
  139. TextFilterUtils::TryConvertWideToAnsi(PluginNameUpperWide, PluginNamesUpperAnsi.AddDefaulted_GetRef());
  140. PluginLoadedFromEngine.Add(PluginRef->GetLoadedFrom() == EPluginLoadedFrom::Engine);
  141. }
  142. }
  143. FORCEINLINE bool PassesFilter(const FAssetData& Item) const
  144. {
  145. if (!PassesRedirectorMainAssetFilter(Item))
  146. {
  147. return false;
  148. }
  149. return PassesPackagePathFilter(Item.PackagePath);
  150. }
  151. FORCEINLINE bool PassesRedirectorMainAssetFilter(const FAssetData& Item) const
  152. {
  153. // Do not show redirectors if they are not the main asset in the uasset file.
  154. if (Item.AssetClass == ObjectRedirectorClassName && !AssetViewUtils::IsUAsset(Item))
  155. {
  156. return false;
  157. }
  158. return true;
  159. }
  160. FORCEINLINE bool PassesPackagePathFilter(const FName& PackagePath) const
  161. {
  162. TextFilterUtils::FNameBufferWithNumber ObjectPathBuffer(PackagePath);
  163. if (ObjectPathBuffer.IsWide())
  164. {
  165. return PassesPackagePathFilter(ObjectPathBuffer.GetWideNamePtr());
  166. }
  167. else
  168. {
  169. return PassesPackagePathFilter(ObjectPathBuffer.GetAnsiNamePtr());
  170. }
  171. }
  172. template <typename CharType>
  173. FORCEINLINE bool PassesPackagePathFilter(CharType* PackagePath) const
  174. {
  175. CharType* PathCh = PackagePath;
  176. if (*PathCh++ != '/')
  177. {
  178. return true;
  179. }
  180. for (; *PathCh && *PathCh != '/'; ++PathCh)
  181. {
  182. *PathCh = TChar<CharType>::ToUpper(*PathCh);
  183. }
  184. if (*PathCh)
  185. {
  186. if (!bDisplayL10N)
  187. {
  188. if ((PathCh[1] == 'L' || PathCh[1] == 'l') &&
  189. PathCh[2] == '1' &&
  190. PathCh[3] == '0' &&
  191. (PathCh[4] == 'N' || PathCh[4] == 'n') &&
  192. (PathCh[5] == '/' || PathCh[5] == 0))
  193. {
  194. return false;
  195. }
  196. }
  197. *PathCh = 0;
  198. }
  199. CharType* PackageRootFolderName = PackagePath + 1;
  200. int32 PackageRootFolderNameLength = PathCh - PackageRootFolderName;
  201. if (PackageRootFolderNameLength == 4 && TCString<CharType>::Strncmp(PackageRootFolderName, LITERAL(CharType, "GAME"), 4) == 0)
  202. {
  203. return true;
  204. }
  205. else if (PackageRootFolderNameLength == 6 && TCString<CharType>::Strncmp(PackageRootFolderName, LITERAL(CharType, "ENGINE"), 4) == 0)
  206. {
  207. return bDisplayEngine;
  208. }
  209. else
  210. {
  211. if (!bDisplayPlugins || !bDisplayEngine)
  212. {
  213. int32 PluginIndex = FindPluginNameUpper(PackageRootFolderName, PackageRootFolderNameLength);
  214. if (PluginIndex != INDEX_NONE)
  215. {
  216. if (!bDisplayPlugins)
  217. {
  218. return false;
  219. }
  220. else if (!bDisplayEngine && PluginLoadedFromEngine[PluginIndex])
  221. {
  222. return false;
  223. }
  224. }
  225. }
  226. }
  227. return true;
  228. }
  229. private:
  230. FName ObjectRedirectorClassName;
  231. bool bDisplayL10N;
  232. bool bDisplayEngine;
  233. bool bDisplayPlugins;
  234. TArray<TArray<ANSICHAR>> PluginNamesUpperAnsi;
  235. TArray<FString> PluginNamesUpperWide;
  236. TArray<bool> PluginLoadedFromEngine;
  237. TArray<TSharedRef<IPlugin>> Plugins;
  238. FORCEINLINE int32 FindPluginNameUpper(const WIDECHAR* PluginNameUpper, int32 Length) const
  239. {
  240. int32 i = 0;
  241. for (const FString& OtherPluginNameUpper : PluginNamesUpperWide)
  242. {
  243. if (OtherPluginNameUpper.Len() == Length && TCString<WIDECHAR>::Strcmp(PluginNameUpper, *OtherPluginNameUpper) == 0)
  244. {
  245. return i;
  246. }
  247. ++i;
  248. }
  249. return INDEX_NONE;
  250. }
  251. FORCEINLINE int32 FindPluginNameUpper(const ANSICHAR* PluginNameUpper, int32 Length) const
  252. {
  253. const int32 LengthWithNull = Length + 1;
  254. int32 i = 0;
  255. for (const TArray<ANSICHAR>& OtherPluginNameUpper : PluginNamesUpperAnsi)
  256. {
  257. if (OtherPluginNameUpper.Num() == LengthWithNull && TCString<ANSICHAR>::Strcmp(PluginNameUpper, OtherPluginNameUpper.GetData()) == 0)
  258. {
  259. return i;
  260. }
  261. ++i;
  262. }
  263. return INDEX_NONE;
  264. }
  265. };
  266. } // namespace AssetViewUtils
  267. #endif
  268. /////////////////////////////////////////////////////////////
  269. // WidgetHelpers implementation
  270. //
  271. namespace WidgetHelpers
  272. {
  273. TSharedRef<SWidget> CreateColorWidget(FLinearColor* Color)
  274. {
  275. auto GetValue = [=] {
  276. return *Color;
  277. };
  278. auto SetValue = [=](FLinearColor NewColor) {
  279. *Color = NewColor;
  280. };
  281. auto OnGetMenuContent = [=]() -> TSharedRef<SWidget> {
  282. // Open a color picker
  283. return SNew(SColorPicker)
  284. .TargetColorAttribute_Lambda(GetValue)
  285. .UseAlpha(true)
  286. .DisplayInlineVersion(true)
  287. .OnColorCommitted_Lambda(SetValue);
  288. };
  289. return SNew(SComboButton)
  290. .ContentPadding(0)
  291. .HasDownArrow(false)
  292. .ButtonStyle(FAppStyle::Get(), "Sequencer.AnimationOutliner.ColorStrip")
  293. .OnGetMenuContent_Lambda(OnGetMenuContent)
  294. .CollapseMenuOnParentFocus(true)
  295. .ButtonContent()
  296. [
  297. SNew(SColorBlock)
  298. .Color_Lambda(GetValue)
  299. .ShowBackgroundForAlpha(true)
  300. .AlphaDisplayMode(EColorBlockAlphaDisplayMode::Ignore)
  301. .Size(FVector2D(10.0f, 10.0f))
  302. ];
  303. }
  304. }
  305. /////////////////////////////////////////////////////////////
  306. // SExtAssetView implementation
  307. //
  308. SExtAssetView::~SExtAssetView()
  309. {
  310. // Remove the listener for when view settings are changed
  311. UExtContentBrowserSettings::OnSettingChanged().RemoveAll(this);
  312. if ( FrontendFilters.IsValid() )
  313. {
  314. // Clear the frontend filter changed delegate
  315. FrontendFilters->OnChanged().RemoveAll( this );
  316. }
  317. FExtContentBrowserSingleton::GetAssetRegistry().OnRootPathAdded().RemoveAll(this);
  318. FExtContentBrowserSingleton::GetAssetRegistry().OnRootPathRemoved().RemoveAll(this);
  319. #if ECB_FEA_ASYNC_ASSET_DISCOVERY
  320. FExtContentBrowserSingleton::GetAssetRegistry().OnAssetGathered().RemoveAll(this);
  321. #endif
  322. #if ECB_WIP_REPARSE_ASSET
  323. FExtContentBrowserSingleton::GetAssetRegistry().OnAssetUpdated().RemoveAll(this);
  324. #endif
  325. // Release all rendering resources being held onto
  326. AssetThumbnailPool.Reset();
  327. }
  328. BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
  329. void SExtAssetView::Construct( const FArguments& InArgs )
  330. {
  331. bIsWorking = false;
  332. TotalAmortizeTime = 0;
  333. AmortizeStartTime = 0;
  334. MaxSecondsPerFrame = 0.015;
  335. bFillEmptySpaceInTileView = InArgs._FillEmptySpaceInTileView;
  336. FillScale = 1.0f;
  337. ThumbnailHintFadeInSequence.JumpToStart();
  338. ThumbnailHintFadeInSequence.AddCurve(0, 0.5f, ECurveEaseFunction::Linear);
  339. #if ECB_LEGACY
  340. // Load the asset registry module to listen for updates
  341. FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
  342. AssetRegistryModule.Get().OnAssetAdded().AddSP( this, &SExtAssetView::OnAssetAdded );
  343. AssetRegistryModule.Get().OnAssetRemoved().AddSP( this, &SExtAssetView::OnAssetRemoved );
  344. AssetRegistryModule.Get().OnAssetRenamed().AddSP( this, &SExtAssetView::OnAssetRenamed );
  345. AssetRegistryModule.Get().OnAssetUpdated().AddSP( this, &SExtAssetView::OnAssetUpdated );
  346. AssetRegistryModule.Get().OnPathAdded().AddSP( this, &SExtAssetView::OnAssetRegistryPathAdded );
  347. AssetRegistryModule.Get().OnPathRemoved().AddSP( this, &SExtAssetView::OnAssetRegistryPathRemoved );
  348. #endif
  349. #if ECB_FEA_ASYNC_ASSET_DISCOVERY
  350. FExtContentBrowserSingleton::GetAssetRegistry().OnAssetGathered().AddSP(this, &SExtAssetView::OnAssetRegistryAssetGathered);
  351. #endif
  352. #if ECB_WIP_REPARSE_ASSET
  353. FExtContentBrowserSingleton::GetAssetRegistry().OnAssetUpdated().AddSP(this, &SExtAssetView::OnAssetUpdated);
  354. #endif
  355. FExtContentBrowserSingleton::GetAssetRegistry().OnRootPathAdded().AddSP(this, &SExtAssetView::OnAssetRegistryRootPathAdded);
  356. FExtContentBrowserSingleton::GetAssetRegistry().OnRootPathRemoved().AddSP(this, &SExtAssetView::OnAssetRegistryRootPathRemoved);
  357. #if ECB_WIP_COLLECTION
  358. FCollectionManagerModule& CollectionManagerModule = FCollectionManagerModule::GetModule();
  359. CollectionManagerModule.Get().OnAssetsAdded().AddSP( this, &SExtAssetView::OnAssetsAddedToCollection );
  360. CollectionManagerModule.Get().OnAssetsRemoved().AddSP( this, &SExtAssetView::OnAssetsRemovedFromCollection );
  361. CollectionManagerModule.Get().OnCollectionRenamed().AddSP( this, &SExtAssetView::OnCollectionRenamed );
  362. CollectionManagerModule.Get().OnCollectionUpdated().AddSP( this, &SExtAssetView::OnCollectionUpdated );
  363. #endif
  364. #if ECB_LEGACY
  365. // Listen for when assets are loaded or changed to update item data
  366. FCoreUObjectDelegates::OnAssetLoaded.AddSP(this, &SExtAssetView::OnAssetLoaded);
  367. FCoreUObjectDelegates::OnObjectPropertyChanged.AddSP(this, &SExtAssetView::OnObjectPropertyChanged);
  368. // Listen to find out when previously empty paths are populated with content
  369. {
  370. TSharedRef<FEmptyFolderVisibilityManager> EmptyFolderVisibilityManager = FContentBrowserSingleton::Get().GetEmptyFolderVisibilityManager();
  371. EmptyFolderVisibilityManager->OnFolderPopulated().AddSP(this, &SExtAssetView::OnFolderPopulated);
  372. }
  373. #endif
  374. // Listen for when view settings are changed
  375. UExtContentBrowserSettings::OnSettingChanged().AddSP(this, &SExtAssetView::HandleSettingChanged);
  376. // Get desktop metrics
  377. FDisplayMetrics DisplayMetrics;
  378. FSlateApplication::Get().GetCachedDisplayMetrics( DisplayMetrics );
  379. const FVector2D DisplaySize(
  380. DisplayMetrics.PrimaryDisplayWorkAreaRect.Right - DisplayMetrics.PrimaryDisplayWorkAreaRect.Left,
  381. DisplayMetrics.PrimaryDisplayWorkAreaRect.Bottom - DisplayMetrics.PrimaryDisplayWorkAreaRect.Top );
  382. const float ThumbnailScaleRangeScalar = ( DisplaySize.Y / 1080 );
  383. // Create a thumbnail pool for rendering thumbnails
  384. AssetThumbnailPool = MakeShareable( new FExtAssetThumbnailPool(1024, /*InAreRealTimeThumbnailsAllowed = */ false) );
  385. NumOffscreenThumbnails = 64;
  386. ListViewThumbnailResolution = 128;
  387. ListViewThumbnailSize = 64;
  388. ListViewThumbnailPadding = 4;
  389. TileViewThumbnailResolution = 256;
  390. TileViewThumbnailSize = 128;
  391. TileViewThumbnailPadding = 5;
  392. TileViewNameHeight = 36;
  393. ThumbnailScaleSliderValue = InArgs._ThumbnailScale;
  394. if ( !ThumbnailScaleSliderValue.IsBound() )
  395. {
  396. ThumbnailScaleSliderValue = FMath::Clamp<float>(ThumbnailScaleSliderValue.Get(), 0.0f, 1.0f);
  397. }
  398. MinThumbnailScale = 0.2f * ThumbnailScaleRangeScalar;
  399. MaxThumbnailScale = 2.0f * ThumbnailScaleRangeScalar;
  400. bCanShowFolders = InArgs._CanShowFolders;
  401. bFilterRecursivelyWithBackendFilter = InArgs._FilterRecursivelyWithBackendFilter;
  402. bCanShowCollections = InArgs._CanShowCollections;
  403. bCanShowFavorites = InArgs._CanShowFavorites;
  404. #if ECB_TODO
  405. bPreloadAssetsForContextMenu = InArgs._PreloadAssetsForContextMenu;
  406. #endif
  407. SelectionMode = InArgs._SelectionMode;
  408. bShowMajorAssetTypeColumnsInColumnView = InArgs._ShowMajorAssetTypeColumnsInColumnView;
  409. bShowPathInColumnView = InArgs._ShowPathInColumnView;
  410. bShowTypeInColumnView = InArgs._ShowTypeInColumnView;
  411. bSortByPathInColumnView = bShowPathInColumnView & InArgs._SortByPathInColumnView;
  412. bPendingUpdateThumbnails = false;
  413. bShouldNotifyNextAssetSync = true;
  414. CurrentThumbnailSize = TileViewThumbnailSize;
  415. SourcesData = InArgs._InitialSourcesData;
  416. BackendFilter = InArgs._InitialBackendFilter;
  417. FrontendFilters = InArgs._FrontendFilters;
  418. if ( FrontendFilters.IsValid() )
  419. {
  420. FrontendFilters->OnChanged().AddSP( this, &SExtAssetView::OnFrontendFiltersChanged );
  421. }
  422. OnShouldFilterAsset = InArgs._OnShouldFilterAsset;
  423. OnAssetSelected = InArgs._OnAssetSelected;
  424. OnAssetsActivated = InArgs._OnAssetsActivated;
  425. OnGetAssetContextMenu = InArgs._OnGetAssetContextMenu;
  426. #if ECB_LEGACY
  427. OnGetFolderContextMenu = InArgs._OnGetFolderContextMenu;
  428. OnGetPathContextMenuExtender = InArgs._OnGetPathContextMenuExtender;
  429. OnFindInAssetTreeRequested = InArgs._OnFindInAssetTreeRequested;
  430. OnAssetRenameCommitted = InArgs._OnAssetRenameCommitted;
  431. OnAssetTagWantsToBeDisplayed = InArgs._OnAssetTagWantsToBeDisplayed;
  432. OnIsAssetValidForCustomToolTip = InArgs._OnIsAssetValidForCustomToolTip;
  433. OnGetCustomAssetToolTip = InArgs._OnGetCustomAssetToolTip;
  434. OnVisualizeAssetToolTip = InArgs._OnVisualizeAssetToolTip;
  435. OnAssetToolTipClosing = InArgs._OnAssetToolTipClosing;
  436. OnGetCustomSourceAssets = InArgs._OnGetCustomSourceAssets;
  437. #endif
  438. HighlightedText = InArgs._HighlightedText;
  439. ThumbnailLabel = InArgs._ThumbnailLabel;
  440. AllowThumbnailHintLabel = InArgs._AllowThumbnailHintLabel;
  441. AssetShowWarningText = InArgs._AssetShowWarningText;
  442. bAllowDragging = InArgs._AllowDragging;
  443. #if ECB_LEGACY
  444. bAllowFocusOnSync = InArgs._AllowFocusOnSync;
  445. #endif
  446. OnPathSelected = InArgs._OnPathSelected;
  447. HiddenColumnNames = DefaultHiddenColumnNames = InArgs._HiddenColumnNames;
  448. CustomColumns = InArgs._CustomColumns;
  449. OnSearchOptionsChanged = InArgs._OnSearchOptionsChanged;
  450. OnRequestShowChangeLog = InArgs._OnRequestShowChangeLog;
  451. if ( InArgs._InitialViewType >= 0 && InArgs._InitialViewType < EAssetViewType::MAX )
  452. {
  453. CurrentViewType = InArgs._InitialViewType;
  454. }
  455. else
  456. {
  457. CurrentViewType = EAssetViewType::Tile;
  458. }
  459. #if ECB_TODO
  460. bPendingSortFilteredItems = false;
  461. bQuickFrontendListRefreshRequested = false;
  462. bSlowFullListRefreshRequested = false;
  463. LastSortTime = 0;
  464. SortDelaySeconds = 8;
  465. LastProcessAddsTime = 0;
  466. #endif
  467. bBulkSelecting = false;
  468. bUserSearching = false;
  469. bPendingFocusOnSync = false;
  470. bWereItemsRecursivelyFiltered = false;
  471. NumVisibleColumns = 0;
  472. #if ECB_LEGACY
  473. FEditorWidgetsModule& EditorWidgetsModule = FModuleManager::LoadModuleChecked<FEditorWidgetsModule>("EditorWidgets");
  474. TSharedRef<SWidget> AssetDiscoveryIndicator = EditorWidgetsModule.CreateAssetDiscoveryIndicator(EAssetDiscoveryIndicatorScaleMode::Scale_Vertical);
  475. #endif
  476. TSharedRef<SVerticalBox> VerticalBox = SNew(SVerticalBox);
  477. ChildSlot
  478. [
  479. VerticalBox
  480. ];
  481. // Assets area
  482. VerticalBox->AddSlot()
  483. .FillHeight(1.f)
  484. [
  485. SNew( SVerticalBox )
  486. // Working Bar >>
  487. #if ECB_FOLD
  488. + SVerticalBox::Slot()
  489. .AutoHeight()
  490. [
  491. SNew( SBox )
  492. .Visibility_Lambda([this] { return bIsWorking ? EVisibility::SelfHitTestInvisible : EVisibility::Collapsed; })
  493. .HeightOverride( 2 )
  494. [
  495. SNew( SProgressBar )
  496. .Percent( this, &SExtAssetView::GetIsWorkingProgressBarState )
  497. .BorderPadding( FVector2D(0,0) )
  498. ]
  499. ]
  500. #endif // Working Bar <<
  501. + SVerticalBox::Slot()
  502. .FillHeight(1.f)
  503. [
  504. SNew(SOverlay)
  505. + SOverlay::Slot()
  506. .HAlign(HAlign_Fill)
  507. .VAlign(VAlign_Fill)
  508. [
  509. // Container for the view types
  510. SAssignNew(ViewContainer, SBorder)
  511. .Padding(0)
  512. ]
  513. + SOverlay::Slot().HAlign(HAlign_Fill).VAlign(VAlign_Center).Padding(FMargin(0, 14, 0, 0))
  514. [
  515. // A warning to display when there are no assets to show
  516. SNew( STextBlock ).Justification( ETextJustify::Center ).AutoWrapText(true)
  517. .Text( this, &SExtAssetView::GetAssetShowWarningText )
  518. .Visibility( this, &SExtAssetView::IsAssetShowWarningTextVisible )
  519. ]
  520. #if 0 //ECB_WIP_ASYNC_ASSET_DISCOVERY
  521. + SOverlay::Slot().HAlign(HAlign_Fill).VAlign(VAlign_Bottom).Padding(FMargin(24, 0, 24, 0))
  522. [
  523. // Asset discovery indicator
  524. SNew(SExtAssetDiscoveryIndicator)
  525. .ScaleMode(EAssetDiscoveryIndicatorScaleMode::Scale_None)
  526. .Padding(FMargin(2))
  527. .FadeIn(false/*bFadeIn*/)
  528. ]
  529. #endif
  530. #if ECB_LEGACY
  531. + SOverlay::Slot()
  532. .HAlign(HAlign_Right)
  533. .VAlign(VAlign_Bottom)
  534. .Padding(FMargin(8, 0))
  535. [
  536. SNew(SBorder)
  537. .BorderImage(FAppStyle::GetBrush("ErrorReporting.EmptyBox"))
  538. .BorderBackgroundColor(this, &SExtAssetView::GetQuickJumpColor)
  539. .Visibility(this, &SExtAssetView::IsQuickJumpVisible)
  540. [
  541. SNew(STextBlock)
  542. .Text(this, &SExtAssetView::GetQuickJumpTerm)
  543. ]
  544. ]
  545. #endif
  546. ]
  547. ];
  548. if (InArgs._ShowBottomToolbar)
  549. {
  550. // Bottom panel
  551. VerticalBox->AddSlot().AutoHeight()
  552. [
  553. SNew(SHorizontalBox)
  554. // Asset count
  555. +SHorizontalBox::Slot().FillWidth(1.f).VAlign(VAlign_Center).Padding(8, 0)
  556. [
  557. SNew(SHorizontalBox)
  558. + SHorizontalBox::Slot().AutoWidth().VAlign(VAlign_Center).Padding(0, 0)
  559. [
  560. SNew(STextBlock).Text(this, &SExtAssetView::GetAssetCountText)
  561. ]
  562. #if ECB_FEA_ASYNC_ASSET_DISCOVERY
  563. + SHorizontalBox::Slot().AutoWidth().VAlign(VAlign_Center).Padding(4, 0)
  564. [
  565. SNew(SExtAssetDiscoveryIndicator)
  566. .ScaleMode(EAssetDiscoveryIndicatorScaleMode::Scale_None)
  567. .Padding(FMargin(2))
  568. .FadeIn(true/*bFadeIn*/)
  569. ]
  570. #endif
  571. ]
  572. // View mode combo button
  573. +SHorizontalBox::Slot().AutoWidth()
  574. [
  575. SNew(SHorizontalBox)
  576. // Thumbnail Scale
  577. + SHorizontalBox::Slot().AutoWidth().VAlign(VAlign_Center).Padding(4, 0)
  578. [
  579. SAssignNew(ThumbnailScaleContainer, SHorizontalBox)
  580. + SHorizontalBox::Slot().AutoWidth().Padding(0, 0, 2, 0)
  581. .VAlign(VAlign_Center)
  582. [
  583. SNew(STextBlock).Text(LOCTEXT("ThumbnailScale", "Thumbnail Scale"))
  584. ]
  585. + SHorizontalBox::Slot().AutoWidth().VAlign(VAlign_Center)
  586. [
  587. SNew(SBox)
  588. .WidthOverride(120.0f)
  589. [
  590. SNew(SSlider)
  591. .ToolTipText(LOCTEXT("ThumbnailScaleToolTip", "Adjust the size of thumbnails."))
  592. .Value(this, &SExtAssetView::GetThumbnailScale)
  593. .OnValueChanged(this, &SExtAssetView::SetThumbnailScale)
  594. .Locked(this, &SExtAssetView::IsThumbnailScalingLocked)
  595. ]
  596. ]
  597. ]
  598. // View options
  599. +SHorizontalBox::Slot().AutoWidth()
  600. [
  601. SAssignNew(ViewOptionsComboButton, SComboButton)
  602. .ContentPadding(0)
  603. .ForegroundColor(this, &SExtAssetView::GetViewButtonForegroundColor)
  604. .ButtonStyle(FAppStyle::Get(), "ToggleButton") // Use the tool bar item style for this button
  605. .OnGetMenuContent(this, &SExtAssetView::GetViewButtonContent)
  606. .ButtonContent()
  607. [
  608. SNew(SHorizontalBox)
  609. + SHorizontalBox::Slot()
  610. .AutoWidth()
  611. .VAlign(VAlign_Center)
  612. [
  613. SNew(SImage).Image(FAppStyle::GetBrush("GenericViewButton"))
  614. ]
  615. + SHorizontalBox::Slot()
  616. .AutoWidth()
  617. .Padding(2, 0, 0, 0)
  618. .VAlign(VAlign_Center)
  619. [
  620. SNew(STextBlock).Text(LOCTEXT("ViewButton", "View Options"))
  621. ]
  622. ]
  623. ]
  624. ]
  625. ];
  626. }
  627. CreateCurrentView();
  628. #if ECB_WIP_INITIAL_ASSET
  629. if( InArgs._InitialAssetSelection.IsValid() )
  630. {
  631. // sync to the initial item without notifying of selection
  632. bShouldNotifyNextAssetSync = false;
  633. TArray<FAssetData> AssetsToSync;
  634. AssetsToSync.Add( InArgs._InitialAssetSelection );
  635. SyncToAssets( AssetsToSync );
  636. }
  637. #endif
  638. #if ECB_WIP_MORE_VIEWTYPE
  639. // If currently looking at column, and you could choose to sort by path in column first and then name
  640. // Generalizing this is a bit difficult because the column ID is not accessible or is not known
  641. // Currently I assume this won't work, if this view mode is not column. Otherwise, I don't think sorting by path
  642. // is a good idea.
  643. if (CurrentViewType == EAssetViewType::Column && bSortByPathInColumnView)
  644. {
  645. SortManager.SetSortColumnId(EColumnSortPriority::Primary, SortManager.PathColumnId);
  646. SortManager.SetSortColumnId(EColumnSortPriority::Secondary, SortManager.NameColumnId);
  647. SortManager.SetSortMode(EColumnSortPriority::Primary, EColumnSortMode::Ascending);
  648. SortManager.SetSortMode(EColumnSortPriority::Secondary, EColumnSortMode::Ascending);
  649. SortList();
  650. }
  651. #endif
  652. #if ECB_FEA_ASSET_DRAG_DROP
  653. static bool bInitAssetViewDragAndDropExtenders = false;
  654. if (!bInitAssetViewDragAndDropExtenders)
  655. {
  656. FContentBrowserModule& ContentBrowserModule = FModuleManager::GetModuleChecked<FContentBrowserModule>("ContentBrowser");
  657. TArray<FAssetViewDragAndDropExtender>& AssetViewDragAndDropExtenders = ContentBrowserModule.GetAssetViewDragAndDropExtenders();
  658. FAssetViewDragAndDropExtender DragAndDropExtender(
  659. FAssetViewDragAndDropExtender::FOnDropDelegate::CreateSP(this, &SExtAssetView::OnDropAndDropToAssetView)
  660. , FAssetViewDragAndDropExtender::FOnDragOverDelegate::CreateLambda([](const FAssetViewDragAndDropExtender::FPayload&) {return true; })
  661. , FAssetViewDragAndDropExtender::FOnDragLeaveDelegate::CreateLambda([](const FAssetViewDragAndDropExtender::FPayload&) {return true; })
  662. );
  663. AssetViewDragAndDropExtenders.Add(DragAndDropExtender);
  664. bInitAssetViewDragAndDropExtenders = true;
  665. }
  666. static bool bInitLevelViewportDragAndDropExtenders = false;
  667. if (!bInitLevelViewportDragAndDropExtenders)
  668. {
  669. // Get all menu extenders for this context menu from the level editor module
  670. static const FName LevelEditorName("LevelEditor");
  671. FLevelEditorModule& LevelEditorModule = FModuleManager::GetModuleChecked<FLevelEditorModule>(LevelEditorName);
  672. TArray<FLevelEditorModule::FLevelViewportMenuExtender_SelectedActors>& MenuExtenders = LevelEditorModule.GetAllLevelViewportContextMenuExtenders();
  673. MenuExtenders.Add(FLevelEditorModule::FLevelViewportMenuExtender_SelectedActors::CreateSP(this, &SExtAssetView::OnExtendLevelViewportMenu));
  674. //FDelegateHandle LevelViewportContextMenuExtenderDelegateHandle = ContextMenuExtenders.Last().GetHandle();
  675. }
  676. #endif
  677. }
  678. END_SLATE_FUNCTION_BUILD_OPTIMIZATION
  679. TOptional< float > SExtAssetView::GetIsWorkingProgressBarState() const
  680. {
  681. return bIsWorking ? TOptional< float >() : 0.0f;
  682. }
  683. void SExtAssetView::SetSourcesData(const FSourcesData& InSourcesData)
  684. {
  685. // Update the path and collection lists
  686. SourcesData = InSourcesData;
  687. RequestSlowFullListRefresh();
  688. ClearSelection();
  689. }
  690. const FSourcesData& SExtAssetView::GetSourcesData() const
  691. {
  692. return SourcesData;
  693. }
  694. #if ECB_TODO
  695. bool SExtAssetView::IsAssetPathSelected() const
  696. {
  697. int32 NumAssetPaths, NumClassPaths;
  698. ContentBrowserUtils::CountPathTypes(SourcesData.PackagePaths, NumAssetPaths, NumClassPaths);
  699. // Check that only asset paths are selected
  700. return NumAssetPaths > 0 && NumClassPaths == 0;
  701. }
  702. #endif
  703. void SExtAssetView::SetBackendFilter(const FARFilter& InBackendFilter)
  704. {
  705. // Update the path and collection lists
  706. BackendFilter = InBackendFilter;
  707. RequestSlowFullListRefresh();
  708. }
  709. #if ECB_TODO
  710. void SExtAssetView::RenameFolder(const FString& FolderToRename)
  711. {
  712. for ( auto ItemIt = FilteredAssetItems.CreateConstIterator(); ItemIt; ++ItemIt )
  713. {
  714. const TSharedPtr<FExtAssetViewItem>& Item = *ItemIt;
  715. if ( Item.IsValid() && Item->GetType() == EAssetItemType::Folder )
  716. {
  717. const TSharedPtr<FAssetViewFolder>& ItemAsFolder = StaticCastSharedPtr<FAssetViewFolder>(Item);
  718. if ( ItemAsFolder->FolderPath == FolderToRename )
  719. {
  720. ItemAsFolder->bRenameWhenScrolledIntoview = true;
  721. SetSelection(Item);
  722. RequestScrollIntoView(Item);
  723. break;
  724. }
  725. }
  726. }
  727. }
  728. void SExtAssetView::SyncToAssets( const TArray<FAssetData>& AssetDataList, const bool bFocusOnSync )
  729. {
  730. PendingSyncItems.Reset();
  731. for (const FAssetData& AssetData : AssetDataList)
  732. {
  733. PendingSyncItems.SelectedAssets.Add(AssetData.ObjectPath);
  734. }
  735. bPendingFocusOnSync = bFocusOnSync;
  736. }
  737. void SExtAssetView::SyncToFolders(const TArray<FString>& FolderList, const bool bFocusOnSync)
  738. {
  739. PendingSyncItems.Reset();
  740. PendingSyncItems.SelectedFolders = TSet<FString>(FolderList);
  741. bPendingFocusOnSync = bFocusOnSync;
  742. }
  743. void SExtAssetView::SyncTo(const FExtContentBrowserSelection& ItemSelection, const bool bFocusOnSync)
  744. {
  745. PendingSyncItems.Reset();
  746. PendingSyncItems.SelectedFolders = TSet<FString>(ItemSelection.SelectedFolders);
  747. for (const FAssetData& AssetData : ItemSelection.SelectedAssets)
  748. {
  749. PendingSyncItems.SelectedAssets.Add(AssetData.ObjectPath);
  750. }
  751. bPendingFocusOnSync = bFocusOnSync;
  752. }
  753. #endif
  754. void SExtAssetView::SyncToSelection( const bool bFocusOnSync )
  755. {
  756. PendingSyncItems.Reset();
  757. TArray<TSharedPtr<FExtAssetViewItem>> SelectedItems = GetSelectedItems();
  758. for (const TSharedPtr<FExtAssetViewItem>& Item : SelectedItems)
  759. {
  760. if (Item.IsValid())
  761. {
  762. if (Item->GetType() == EExtAssetItemType::Folder)
  763. {
  764. PendingSyncItems.SelectedFolders.Add(StaticCastSharedPtr<FExtAssetViewFolder>(Item)->FolderPath);
  765. }
  766. else
  767. {
  768. PendingSyncItems.SelectedAssets.Add(StaticCastSharedPtr<FExtAssetViewAsset>(Item)->Data.ObjectPath);
  769. }
  770. }
  771. }
  772. bPendingFocusOnSync = bFocusOnSync;
  773. }
  774. #if ECB_WIP_HISTORY
  775. void SExtAssetView::ApplyHistoryData( const FHistoryData& History )
  776. {
  777. SetSourcesData(History.SourcesData);
  778. PendingSyncItems = History.SelectionData;
  779. bPendingFocusOnSync = true;
  780. }
  781. #endif
  782. TArray<TSharedPtr<FExtAssetViewItem>> SExtAssetView::GetSelectedItems() const
  783. {
  784. switch ( GetCurrentViewType() )
  785. {
  786. case EAssetViewType::List: return ListView->GetSelectedItems();
  787. case EAssetViewType::Tile: return TileView->GetSelectedItems();
  788. case EAssetViewType::Column: return ColumnView->GetSelectedItems();
  789. default:
  790. ensure(0); // Unknown list type
  791. return TArray<TSharedPtr<FExtAssetViewItem>>();
  792. }
  793. }
  794. TArray<FExtAssetData> SExtAssetView::GetSelectedAssets() const
  795. {
  796. TArray<TSharedPtr<FExtAssetViewItem>> SelectedItems = GetSelectedItems();
  797. TArray<FExtAssetData> SelectedAssets;
  798. for ( auto ItemIt = SelectedItems.CreateConstIterator(); ItemIt; ++ItemIt )
  799. {
  800. const TSharedPtr<FExtAssetViewItem>& Item = *ItemIt;
  801. // Only report non-temporary & non-folder items
  802. if ( Item.IsValid() && !Item->IsTemporaryItem() && Item->GetType() != EExtAssetItemType::Folder )
  803. {
  804. SelectedAssets.Add(StaticCastSharedPtr<FExtAssetViewAsset>(Item)->Data);
  805. }
  806. }
  807. return SelectedAssets;
  808. }
  809. int32 SExtAssetView::GetNumSelectedAssets() const
  810. {
  811. int32 Num = 0;
  812. TArray<TSharedPtr<FExtAssetViewItem>> SelectedItems = GetSelectedItems();
  813. for (auto ItemIt = SelectedItems.CreateConstIterator(); ItemIt; ++ItemIt)
  814. {
  815. const TSharedPtr<FExtAssetViewItem>& Item = *ItemIt;
  816. // Only report non-temporary & non-folder items
  817. if (Item.IsValid() && !Item->IsTemporaryItem() && Item->GetType() != EExtAssetItemType::Folder)
  818. {
  819. ++Num;
  820. }
  821. }
  822. return Num;
  823. }
  824. TArray<FString> SExtAssetView::GetSelectedFolders() const
  825. {
  826. TArray<TSharedPtr<FExtAssetViewItem>> SelectedItems = GetSelectedItems();
  827. TArray<FString> SelectedFolders;
  828. for ( auto ItemIt = SelectedItems.CreateConstIterator(); ItemIt; ++ItemIt )
  829. {
  830. const TSharedPtr<FExtAssetViewItem>& Item = *ItemIt;
  831. if ( Item.IsValid() && Item->GetType() == EExtAssetItemType::Folder )
  832. {
  833. SelectedFolders.Add(StaticCastSharedPtr<FExtAssetViewFolder>(Item)->FolderPath);
  834. }
  835. }
  836. return SelectedFolders;
  837. }
  838. void SExtAssetView::RequestSlowFullListRefresh()
  839. {
  840. bSlowFullListRefreshRequested = true;
  841. // Prefetch assets
  842. {
  843. const bool bRecurse = ShouldFilterRecursively();
  844. const bool bUsingFolders = IsShowingFolders();
  845. FARFilter Filter = SourcesData.MakeFilter(bRecurse, bUsingFolders);
  846. // Add the backend filters from the filter list
  847. Filter.Append(BackendFilter);
  848. #if ECB_FEA_ASYNC_ASSET_DISCOVERY
  849. //FExtContentBrowserSingleton::GetAssetRegistry().CacheAssetsAsync(Filter);
  850. #else
  851. FExtContentBrowserSingleton::GetAssetRegistry().CacheAssets(Filter);
  852. #endif
  853. }
  854. }
  855. void SExtAssetView::RequestQuickFrontendListRefresh()
  856. {
  857. bQuickFrontendListRefreshRequested = true;
  858. }
  859. FString SExtAssetView::GetThumbnailScaleSettingPath(const FString& SettingsString) const
  860. {
  861. return SettingsString + TEXT(".ThumbnailSizeScale");
  862. }
  863. FString SExtAssetView::GetCurrentViewTypeSettingPath(const FString& SettingsString) const
  864. {
  865. return SettingsString + TEXT(".CurrentViewType");
  866. }
  867. void SExtAssetView::SaveSettings(const FString& IniFilename, const FString& IniSection, const FString& SettingsString) const
  868. {
  869. GConfig->SetFloat(*IniSection, *GetThumbnailScaleSettingPath(SettingsString), ThumbnailScaleSliderValue.Get(), IniFilename);
  870. #if ECB_WIP_MORE_VIEWTYPE
  871. GConfig->SetInt(*IniSection, *GetCurrentViewTypeSettingPath(SettingsString), CurrentViewType, IniFilename);
  872. #endif
  873. GConfig->SetArray(*IniSection, *(SettingsString + TEXT(".HiddenColumns")), HiddenColumnNames, IniFilename);
  874. }
  875. void SExtAssetView::LoadSettings(const FString& IniFilename, const FString& IniSection, const FString& SettingsString)
  876. {
  877. float Scale = 0.f;
  878. if ( GConfig->GetFloat(*IniSection, *GetThumbnailScaleSettingPath(SettingsString), Scale, IniFilename) )
  879. {
  880. // Clamp value to normal range and update state
  881. Scale = FMath::Clamp<float>(Scale, 0.f, 1.f);
  882. SetThumbnailScale(Scale);
  883. }
  884. #if ECB_WIP_MORE_VIEWTYPE
  885. int32 ViewType = EAssetViewType::Tile;
  886. if ( GConfig->GetInt(*IniSection, *GetCurrentViewTypeSettingPath(SettingsString), ViewType, IniFilename) )
  887. {
  888. // Clamp value to normal range and update state
  889. if ( ViewType < 0 || ViewType >= EAssetViewType::MAX)
  890. {
  891. ViewType = EAssetViewType::Tile;
  892. }
  893. SetCurrentViewType( (EAssetViewType::Type)ViewType );
  894. }
  895. TArray<FString> LoadedHiddenColumnNames;
  896. GConfig->GetArray(*IniSection, *(SettingsString + TEXT(".HiddenColumns")), LoadedHiddenColumnNames, IniFilename);
  897. if (LoadedHiddenColumnNames.Num() > 0)
  898. {
  899. HiddenColumnNames = LoadedHiddenColumnNames;
  900. }
  901. #endif
  902. }
  903. #if ECB_TODO
  904. // Adjusts the selected asset by the selection delta, which should be +1 or -1)
  905. void SExtAssetView::AdjustActiveSelection(int32 SelectionDelta)
  906. {
  907. // Find the index of the first selected item
  908. TArray<TSharedPtr<FExtAssetViewItem>> SelectionSet = GetSelectedItems();
  909. int32 SelectedSuggestion = INDEX_NONE;
  910. if (SelectionSet.Num() > 0)
  911. {
  912. if (!FilteredAssetItems.Find(SelectionSet[0], /*out*/ SelectedSuggestion))
  913. {
  914. // Should never happen
  915. ensureMsgf(false, TEXT("SExtAssetView has a selected item that wasn't in the filtered list"));
  916. return;
  917. }
  918. }
  919. else
  920. {
  921. SelectedSuggestion = 0;
  922. SelectionDelta = 0;
  923. }
  924. if (FilteredAssetItems.Num() > 0)
  925. {
  926. // Move up or down one, wrapping around
  927. SelectedSuggestion = (SelectedSuggestion + SelectionDelta + FilteredAssetItems.Num()) % FilteredAssetItems.Num();
  928. // Pick the new asset
  929. const TSharedPtr<FExtAssetViewItem>& NewSelection = FilteredAssetItems[SelectedSuggestion];
  930. RequestScrollIntoView(NewSelection);
  931. SetSelection(NewSelection);
  932. }
  933. else
  934. {
  935. ClearSelection();
  936. }
  937. }
  938. #endif
  939. #if ECB_FEA_ASYNC_ASSET_DISCOVERY
  940. void SExtAssetView::ProcessRecentlyLoadedOrChangedAssets()
  941. {
  942. for (int32 AssetIdx = FilteredAssetItems.Num() - 1; AssetIdx >= 0 && RecentlyLoadedOrChangedAssets.Num() > 0; --AssetIdx)
  943. {
  944. if (FilteredAssetItems[AssetIdx]->GetType() != EExtAssetItemType::Folder)
  945. {
  946. const TSharedPtr<FExtAssetViewAsset>& ItemAsAsset = StaticCastSharedPtr<FExtAssetViewAsset>(FilteredAssetItems[AssetIdx]);
  947. // Find the updated version of the asset data from the set
  948. // This is the version of the data we should use to update our view
  949. FExtAssetData RecentlyLoadedOrChangedAsset;
  950. if (const FExtAssetData* RecentlyLoadedOrChangedAssetPtr = RecentlyLoadedOrChangedAssets.Find(ItemAsAsset->Data))
  951. {
  952. RecentlyLoadedOrChangedAsset = *RecentlyLoadedOrChangedAssetPtr;
  953. RecentlyLoadedOrChangedAssets.Remove(ItemAsAsset->Data);
  954. }
  955. if (RecentlyLoadedOrChangedAsset.IsValid() || RecentlyLoadedOrChangedAsset.IsParsed())
  956. {
  957. bool bShouldRemoveAsset = false;
  958. if (!PassesCurrentBackendFilter(RecentlyLoadedOrChangedAsset))
  959. {
  960. bShouldRemoveAsset = true;
  961. }
  962. if (!bShouldRemoveAsset && OnShouldFilterAsset.IsBound() && OnShouldFilterAsset.Execute(RecentlyLoadedOrChangedAsset))
  963. {
  964. bShouldRemoveAsset = true;
  965. }
  966. if (!bShouldRemoveAsset && (IsFrontendFilterActive() && !PassesCurrentFrontendFilter(RecentlyLoadedOrChangedAsset)))
  967. {
  968. bShouldRemoveAsset = true;
  969. }
  970. if (bShouldRemoveAsset)
  971. {
  972. FilteredAssetItems.RemoveAt(AssetIdx);
  973. }
  974. else
  975. {
  976. // Update the asset data on the item
  977. ItemAsAsset->SetAssetData(RecentlyLoadedOrChangedAsset);
  978. // Update the custom column data
  979. ItemAsAsset->CacheCustomColumns(CustomColumns, true, true, true);
  980. }
  981. RefreshList();
  982. }
  983. }
  984. }
  985. if (FilteredRecentlyAddedAssets.Num() == 0 && RecentlyAddedAssets.Num() == 0)
  986. {
  987. //No more assets coming in so if we haven't found them now we aren't going to
  988. RecentlyLoadedOrChangedAssets.Reset();
  989. }
  990. }
  991. #endif
  992. void SExtAssetView::Tick( const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime )
  993. {
  994. CalculateFillScale( AllottedGeometry );
  995. CurrentTime = InCurrentTime;
  996. static float WidthLastFrame = 0.f;
  997. if (WidthLastFrame != AllottedGeometry.Size.X)
  998. {
  999. ECB_LOG(Display, TEXT("AssetView:WidthLastFrame: %.2f"), WidthLastFrame);
  1000. WidthLastFrame = AllottedGeometry.Size.X;
  1001. }
  1002. {
  1003. #if ECB_FEA_ASYNC_ASSET_DISCOVERY
  1004. bool bIsGatheringAsset = FExtContentBrowserSingleton::GetAssetRegistry().IsGatheringAssets();
  1005. #else
  1006. bool bIsGatheringAsset = false;
  1007. #endif
  1008. ThumbnailScaleContainer->SetVisibility(WidthLastFrame < (bIsGatheringAsset ? 609.f : 372.f) ? EVisibility::Collapsed : EVisibility::Visible);
  1009. ViewOptionsComboButton->SetVisibility(WidthLastFrame < (bIsGatheringAsset ? 405.f : 150.f) ? EVisibility::Collapsed : EVisibility::Visible);
  1010. }
  1011. #if ECB_FEA_ASYNC_ASSET_DISCOVERY
  1012. if (FExtContentBrowserSingleton::GetAssetRegistry().GetAndTrimAssetGatherResult())
  1013. {
  1014. //bSlowFullListRefreshRequested = true;
  1015. }
  1016. // If there were any assets that were recently added via the asset registry, process them now
  1017. ProcessRecentlyAddedAssets();
  1018. // If there were any assets loaded since last frame that we are currently displaying thumbnails for, push them on the render stack now.
  1019. ProcessRecentlyLoadedOrChangedAssets();
  1020. #endif
  1021. CalculateThumbnailHintColorAndOpacity();
  1022. if (FSlateApplication::Get().GetActiveModalWindow().IsValid())
  1023. {
  1024. // If we're in a model window then we need to tick the thumbnail pool in order for thumbnails to render correctly.
  1025. AssetThumbnailPool->Tick(InDeltaTime);
  1026. }
  1027. if ( bPendingUpdateThumbnails )
  1028. {
  1029. UpdateThumbnails();
  1030. bPendingUpdateThumbnails = false;
  1031. }
  1032. if (bSlowFullListRefreshRequested)
  1033. {
  1034. RefreshSourceItems();
  1035. bSlowFullListRefreshRequested = false;
  1036. bQuickFrontendListRefreshRequested = true;
  1037. }
  1038. if (QueriedAssetItems.Num() > 0)
  1039. {
  1040. check(OnShouldFilterAsset.IsBound());
  1041. double TickStartTime = FPlatformTime::Seconds();
  1042. // Mark the first amortize time
  1043. if (AmortizeStartTime == 0)
  1044. {
  1045. AmortizeStartTime = FPlatformTime::Seconds();
  1046. bIsWorking = true;
  1047. }
  1048. ProcessQueriedItems(TickStartTime);
  1049. if (QueriedAssetItems.Num() == 0)
  1050. {
  1051. TotalAmortizeTime += FPlatformTime::Seconds() - AmortizeStartTime;
  1052. AmortizeStartTime = 0;
  1053. bIsWorking = false;
  1054. }
  1055. else
  1056. {
  1057. // Need to finish processing queried items before rest of function is safe
  1058. return;
  1059. }
  1060. }
  1061. if (bQuickFrontendListRefreshRequested)
  1062. {
  1063. //ResetQuickJump();
  1064. RefreshFilteredItems();
  1065. RefreshFolders();
  1066. SortList(!PendingSyncItems.Num()); // Don't sync to selection if we are just going to do it below
  1067. bQuickFrontendListRefreshRequested = false;
  1068. }
  1069. if ( PendingSyncItems.Num() > 0 )
  1070. {
  1071. if (bPendingSortFilteredItems)
  1072. {
  1073. // Don't sync to selection because we are just going to do it below
  1074. SortList(/*bSyncToSelection=*/false);
  1075. }
  1076. bBulkSelecting = true;
  1077. ClearSelection();
  1078. bool bFoundScrollIntoViewTarget = false;
  1079. for ( auto ItemIt = FilteredAssetItems.CreateConstIterator(); ItemIt; ++ItemIt )
  1080. {
  1081. const auto& Item = *ItemIt;
  1082. if(Item.IsValid())
  1083. {
  1084. if(Item->GetType() == EExtAssetItemType::Folder)
  1085. {
  1086. const TSharedPtr<FExtAssetViewFolder>& ItemAsFolder = StaticCastSharedPtr<FExtAssetViewFolder>(Item);
  1087. if ( PendingSyncItems.SelectedFolders.Contains(ItemAsFolder->FolderPath) )
  1088. {
  1089. SetItemSelection(*ItemIt, true, ESelectInfo::OnNavigation);
  1090. // Scroll the first item in the list that can be shown into view
  1091. if ( !bFoundScrollIntoViewTarget )
  1092. {
  1093. RequestScrollIntoView(Item);
  1094. bFoundScrollIntoViewTarget = true;
  1095. }
  1096. }
  1097. }
  1098. else
  1099. {
  1100. const TSharedPtr<FExtAssetViewAsset>& ItemAsAsset = StaticCastSharedPtr<FExtAssetViewAsset>(Item);
  1101. if ( PendingSyncItems.SelectedAssets.Contains(ItemAsAsset->Data.ObjectPath) )
  1102. {
  1103. SetItemSelection(*ItemIt, true, ESelectInfo::OnNavigation);
  1104. // Scroll the first item in the list that can be shown into view
  1105. if ( !bFoundScrollIntoViewTarget )
  1106. {
  1107. RequestScrollIntoView(Item);
  1108. bFoundScrollIntoViewTarget = true;
  1109. }
  1110. }
  1111. }
  1112. }
  1113. }
  1114. bBulkSelecting = false;
  1115. if (bShouldNotifyNextAssetSync && !bUserSearching)
  1116. {
  1117. AssetSelectionChanged(TSharedPtr<FExtAssetViewAsset>(), ESelectInfo::Direct);
  1118. }
  1119. // Default to always notifying
  1120. bShouldNotifyNextAssetSync = true;
  1121. PendingSyncItems.Reset();
  1122. if (bAllowFocusOnSync && bPendingFocusOnSync)
  1123. {
  1124. FocusList();
  1125. }
  1126. }
  1127. if ( IsHovered() )
  1128. {
  1129. // This prevents us from sorting the view immediately after the cursor leaves it
  1130. LastSortTime = CurrentTime;
  1131. }
  1132. else if ( bPendingSortFilteredItems && InCurrentTime > LastSortTime + SortDelaySeconds )
  1133. {
  1134. SortList();
  1135. }
  1136. #if ECB_WIP_BREADCRUMB
  1137. // Do quick-jump last as the Tick function might have canceled it
  1138. if(QuickJumpData.bHasChangedSinceLastTick)
  1139. {
  1140. QuickJumpData.bHasChangedSinceLastTick = false;
  1141. const bool bWasJumping = QuickJumpData.bIsJumping;
  1142. QuickJumpData.bIsJumping = true;
  1143. QuickJumpData.LastJumpTime = InCurrentTime;
  1144. QuickJumpData.bHasValidMatch = PerformQuickJump(bWasJumping);
  1145. }
  1146. else if(QuickJumpData.bIsJumping && InCurrentTime > QuickJumpData.LastJumpTime + JumpDelaySeconds)
  1147. {
  1148. ResetQuickJump();
  1149. }
  1150. TSharedPtr<FExtAssetViewItem> AssetAwaitingRename = AwaitingRename.Pin();
  1151. if (AssetAwaitingRename.IsValid())
  1152. {
  1153. TSharedPtr<SWindow> OwnerWindow = FSlateApplication::Get().FindWidgetWindow(AsShared());
  1154. if (!OwnerWindow.IsValid())
  1155. {
  1156. AssetAwaitingRename->bRenameWhenScrolledIntoview = false;
  1157. AwaitingRename = nullptr;
  1158. }
  1159. else if (OwnerWindow->HasAnyUserFocusOrFocusedDescendants())
  1160. {
  1161. AssetAwaitingRename->RenamedRequestEvent.ExecuteIfBound();
  1162. AssetAwaitingRename->bRenameWhenScrolledIntoview = false;
  1163. AwaitingRename = nullptr;
  1164. }
  1165. }
  1166. #endif
  1167. }
  1168. void SExtAssetView::CalculateFillScale( const FGeometry& AllottedGeometry )
  1169. {
  1170. if ( bFillEmptySpaceInTileView && CurrentViewType == EAssetViewType::Tile )
  1171. {
  1172. float ItemWidth = GetTileViewItemBaseWidth();
  1173. // Scrollbars are 16, but we add 1 to deal with half pixels.
  1174. const float ScrollbarWidth = 16 + 1;
  1175. float TotalWidth = AllottedGeometry.GetLocalSize().X - ( ScrollbarWidth / AllottedGeometry.Scale );
  1176. float Coverage = TotalWidth / ItemWidth;
  1177. int32 Items = (int)( TotalWidth / ItemWidth );
  1178. // If there isn't enough room to support even a single item, don't apply a fill scale.
  1179. if ( Items > 0 )
  1180. {
  1181. float GapSpace = ItemWidth * ( Coverage - Items );
  1182. float ExpandAmount = GapSpace / (float)Items;
  1183. FillScale = ( ItemWidth + ExpandAmount ) / ItemWidth;
  1184. FillScale = FMath::Max( 1.0f, FillScale );
  1185. }
  1186. else
  1187. {
  1188. FillScale = 1.0f;
  1189. }
  1190. }
  1191. else
  1192. {
  1193. FillScale = 1.0f;
  1194. }
  1195. }
  1196. void SExtAssetView::CalculateThumbnailHintColorAndOpacity()
  1197. {
  1198. if ( HighlightedText.Get().IsEmpty() )
  1199. {
  1200. if ( ThumbnailHintFadeInSequence.IsPlaying() )
  1201. {
  1202. if ( ThumbnailHintFadeInSequence.IsForward() )
  1203. {
  1204. ThumbnailHintFadeInSequence.Reverse();
  1205. }
  1206. }
  1207. else if ( ThumbnailHintFadeInSequence.IsAtEnd() )
  1208. {
  1209. ThumbnailHintFadeInSequence.PlayReverse(this->AsShared());
  1210. }
  1211. }
  1212. else
  1213. {
  1214. if ( ThumbnailHintFadeInSequence.IsPlaying() )
  1215. {
  1216. if ( ThumbnailHintFadeInSequence.IsInReverse() )
  1217. {
  1218. ThumbnailHintFadeInSequence.Reverse();
  1219. }
  1220. }
  1221. else if ( ThumbnailHintFadeInSequence.IsAtStart() )
  1222. {
  1223. ThumbnailHintFadeInSequence.Play(this->AsShared());
  1224. }
  1225. }
  1226. const float Opacity = ThumbnailHintFadeInSequence.GetLerp();
  1227. ThumbnailHintColorAndOpacity = FLinearColor( 1.0, 1.0, 1.0, Opacity );
  1228. }
  1229. void SExtAssetView::ProcessQueriedItems( const double TickStartTime )
  1230. {
  1231. const bool bFlushFullBuffer = TickStartTime < 0;
  1232. bool ListNeedsRefresh = false;
  1233. int32 AssetIndex = 0;
  1234. for ( AssetIndex = QueriedAssetItems.Num() - 1; AssetIndex >= 0 ; AssetIndex--)
  1235. {
  1236. if ( !OnShouldFilterAsset.Execute( QueriedAssetItems[AssetIndex] ) )
  1237. {
  1238. AssetItems.Add( QueriedAssetItems[AssetIndex] );
  1239. if ( !IsFrontendFilterActive() || PassesCurrentFrontendFilter(QueriedAssetItems[AssetIndex]))
  1240. {
  1241. const FExtAssetData& AssetData = QueriedAssetItems[AssetIndex];
  1242. FilteredAssetItems.Add(MakeShareable(new FExtAssetViewAsset(AssetData)));
  1243. ListNeedsRefresh = true;
  1244. bPendingSortFilteredItems = true;
  1245. }
  1246. }
  1247. // Check to see if we have run out of time in this tick
  1248. if ( !bFlushFullBuffer && (FPlatformTime::Seconds() - TickStartTime) > MaxSecondsPerFrame)
  1249. {
  1250. break;
  1251. }
  1252. }
  1253. // Trim the results array
  1254. if (AssetIndex > 0)
  1255. {
  1256. QueriedAssetItems.RemoveAt( AssetIndex, QueriedAssetItems.Num() - AssetIndex );
  1257. }
  1258. else
  1259. {
  1260. QueriedAssetItems.Reset();
  1261. }
  1262. if ( ListNeedsRefresh )
  1263. {
  1264. RefreshList();
  1265. }
  1266. }
  1267. #if ECB_FEA_ASSET_DRAG_DROP
  1268. void SExtAssetView::OnDragLeave( const FDragDropEvent& DragDropEvent )
  1269. {
  1270. #if ECB_LEGACY
  1271. TSharedPtr< FAssetDragDropOp > AssetDragDropOp = DragDropEvent.GetOperationAs< FAssetDragDropOp >();
  1272. if( AssetDragDropOp.IsValid() )
  1273. {
  1274. AssetDragDropOp->ResetToDefaultToolTip();
  1275. return;
  1276. }
  1277. TSharedPtr<FDragDropOperation> DragDropOp = DragDropEvent.GetOperation();
  1278. if (DragDropOp.IsValid())
  1279. {
  1280. // Do we have a custom handler for this drag event?
  1281. FContentBrowserModule& ContentBrowserModule = FModuleManager::GetModuleChecked<FContentBrowserModule>("ContentBrowser");
  1282. const TArray<FAssetViewDragAndDropExtender>& AssetViewDragAndDropExtenders = ContentBrowserModule.GetAssetViewDragAndDropExtenders();
  1283. for (const auto& AssetViewDragAndDropExtender : AssetViewDragAndDropExtenders)
  1284. {
  1285. if (AssetViewDragAndDropExtender.OnDragLeaveDelegate.IsBound() && AssetViewDragAndDropExtender.OnDragLeaveDelegate.Execute(FAssetViewDragAndDropExtender::FPayload(DragDropOp, SourcesData.PackagePaths, SourcesData.Collections)))
  1286. {
  1287. return;
  1288. }
  1289. }
  1290. }
  1291. #endif
  1292. }
  1293. FReply SExtAssetView::OnDragOver( const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent )
  1294. {
  1295. #if ECB_LEGACY
  1296. TSharedPtr<FDragDropOperation> DragDropOp = DragDropEvent.GetOperation();
  1297. if (DragDropOp.IsValid())
  1298. {
  1299. // Do we have a custom handler for this drag event?
  1300. FContentBrowserModule& ContentBrowserModule = FModuleManager::GetModuleChecked<FContentBrowserModule>("ContentBrowser");
  1301. const TArray<FAssetViewDragAndDropExtender>& AssetViewDragAndDropExtenders = ContentBrowserModule.GetAssetViewDragAndDropExtenders();
  1302. for (const auto& AssetViewDragAndDropExtender : AssetViewDragAndDropExtenders)
  1303. {
  1304. if (AssetViewDragAndDropExtender.OnDragOverDelegate.IsBound() && AssetViewDragAndDropExtender.OnDragOverDelegate.Execute(FAssetViewDragAndDropExtender::FPayload(DragDropOp, SourcesData.PackagePaths, SourcesData.Collections)))
  1305. {
  1306. return FReply::Handled();
  1307. }
  1308. }
  1309. }
  1310. if (SourcesData.HasPackagePaths())
  1311. {
  1312. // Note: We don't test IsAssetPathSelected here as we need to prevent dropping assets on class paths
  1313. const FString DestPath = SourcesData.PackagePaths[0].ToString();
  1314. bool bUnused = false;
  1315. DragDropHandler::ValidateDragDropOnAssetFolder(MyGeometry, DragDropEvent, DestPath, bUnused);
  1316. return FReply::Handled();
  1317. }
  1318. else if (HasSingleCollectionSource())
  1319. {
  1320. TArray< FExtAssetData > AssetDatas = AssetUtil::ExtractAssetDataFromDrag(DragDropEvent);
  1321. if (AssetDatas.Num() > 0)
  1322. {
  1323. TSharedPtr<FAssetDragDropOp> AssetDragDropOp = DragDropEvent.GetOperationAs< FAssetDragDropOp >();
  1324. if (AssetDragDropOp.IsValid())
  1325. {
  1326. TArray< FName > ObjectPaths;
  1327. FCollectionManagerModule& CollectionManagerModule = FCollectionManagerModule::GetModule();
  1328. const FCollectionNameType& Collection = SourcesData.Collections[0];
  1329. CollectionManagerModule.Get().GetObjectsInCollection(Collection.Name, Collection.Type, ObjectPaths);
  1330. bool IsValidDrop = false;
  1331. for (const auto& AssetData : AssetDatas)
  1332. {
  1333. if (AssetData.GetClass()->IsChildOf(UClass::StaticClass()))
  1334. {
  1335. continue;
  1336. }
  1337. if (!ObjectPaths.Contains(AssetData.ObjectPath))
  1338. {
  1339. IsValidDrop = true;
  1340. break;
  1341. }
  1342. }
  1343. if (IsValidDrop)
  1344. {
  1345. AssetDragDropOp->SetToolTip(NSLOCTEXT("AssetView", "OnDragOverCollection", "Add to Collection"), FAppStyle::GetBrush(TEXT("Graph.ConnectorFeedback.OK")));
  1346. }
  1347. }
  1348. return FReply::Handled();
  1349. }
  1350. }
  1351. #endif
  1352. return FReply::Unhandled();
  1353. }
  1354. FReply SExtAssetView::OnDrop( const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent )
  1355. {
  1356. #if ECB_LEGACY
  1357. TSharedPtr<FDragDropOperation> DragDropOp = DragDropEvent.GetOperation();
  1358. if (DragDropOp.IsValid())
  1359. {
  1360. // Do we have a custom handler for this drag event?
  1361. FContentBrowserModule& ContentBrowserModule = FModuleManager::GetModuleChecked<FContentBrowserModule>("ContentBrowser");
  1362. const TArray<FAssetViewDragAndDropExtender>& AssetViewDragAndDropExtenders = ContentBrowserModule.GetAssetViewDragAndDropExtenders();
  1363. for (const auto& AssetViewDragAndDropExtender : AssetViewDragAndDropExtenders)
  1364. {
  1365. if (AssetViewDragAndDropExtender.OnDropDelegate.IsBound() && AssetViewDragAndDropExtender.OnDropDelegate.Execute(FAssetViewDragAndDropExtender::FPayload(DragDropOp, SourcesData.PackagePaths, SourcesData.Collections)))
  1366. {
  1367. return FReply::Handled();
  1368. }
  1369. }
  1370. }
  1371. if (SourcesData.HasPackagePaths())
  1372. {
  1373. // Note: We don't test IsAssetPathSelected here as we need to prevent dropping assets on class paths
  1374. const FString DestPath = SourcesData.PackagePaths[0].ToString();
  1375. bool bUnused = false;
  1376. if (DragDropHandler::ValidateDragDropOnAssetFolder(MyGeometry, DragDropEvent, DestPath, bUnused))
  1377. {
  1378. // Handle drag drop for import
  1379. TSharedPtr<FExternalDragOperation> ExternalDragDropOp = DragDropEvent.GetOperationAs<FExternalDragOperation>();
  1380. if (ExternalDragDropOp.IsValid())
  1381. {
  1382. if (ExternalDragDropOp->HasFiles())
  1383. {
  1384. // Delay import until next tick to avoid blocking the process that files were dragged from
  1385. GEditor->GetEditorSubsystem<UImportSubsystem>()->ImportNextTick(ExternalDragDropOp->GetFiles(), SourcesData.PackagePaths[0].ToString());
  1386. }
  1387. }
  1388. TSharedPtr<FAssetDragDropOp> AssetDragDropOp = DragDropEvent.GetOperationAs<FAssetDragDropOp>();
  1389. if (AssetDragDropOp.IsValid())
  1390. {
  1391. OnAssetsOrPathsDragDropped(AssetDragDropOp->GetAssets(), AssetDragDropOp->GetAssetPaths(), DestPath);
  1392. }
  1393. }
  1394. return FReply::Handled();
  1395. }
  1396. else if (HasSingleCollectionSource())
  1397. {
  1398. TArray<FExtAssetData> SelectedAssetDatas = AssetUtil::ExtractAssetDataFromDrag(DragDropEvent);
  1399. if (SelectedAssetDatas.Num() > 0)
  1400. {
  1401. TSharedPtr<FAssetDragDropOp> AssetDragDropOp = DragDropEvent.GetOperationAs< FAssetDragDropOp >();
  1402. if (AssetDragDropOp.IsValid())
  1403. {
  1404. TArray<FName> ObjectPaths;
  1405. for (const auto& AssetData : SelectedAssetDatas)
  1406. {
  1407. if (!AssetData.GetClass()->IsChildOf(UClass::StaticClass()))
  1408. {
  1409. ObjectPaths.Add(AssetData.ObjectPath);
  1410. }
  1411. }
  1412. if (ObjectPaths.Num() > 0)
  1413. {
  1414. FCollectionManagerModule& CollectionManagerModule = FCollectionManagerModule::GetModule();
  1415. const FCollectionNameType& Collection = SourcesData.Collections[0];
  1416. CollectionManagerModule.Get().AddToCollection(Collection.Name, Collection.Type, ObjectPaths);
  1417. }
  1418. }
  1419. return FReply::Handled();
  1420. }
  1421. }
  1422. #endif
  1423. return FReply::Unhandled();
  1424. }
  1425. #endif
  1426. #if ECB_LEGACY
  1427. FReply SExtAssetView::OnKeyChar( const FGeometry& MyGeometry,const FCharacterEvent& InCharacterEvent )
  1428. {
  1429. const bool bIsControlOrCommandDown = InCharacterEvent.IsControlDown() || InCharacterEvent.IsCommandDown();
  1430. const bool bTestOnly = false;
  1431. if(HandleQuickJumpKeyDown(InCharacterEvent.GetCharacter(), bIsControlOrCommandDown, InCharacterEvent.IsAltDown(), bTestOnly).IsEventHandled())
  1432. {
  1433. return FReply::Handled();
  1434. }
  1435. // If the user pressed a key we couldn't handle, reset the quick-jump search
  1436. ResetQuickJump();
  1437. return FReply::Unhandled();
  1438. }
  1439. static bool IsValidObjectPath(const FString& Path)
  1440. {
  1441. int32 NameStartIndex = INDEX_NONE;
  1442. Path.FindChar(TCHAR('\''), NameStartIndex);
  1443. if (NameStartIndex != INDEX_NONE)
  1444. {
  1445. int32 NameEndIndex = INDEX_NONE;
  1446. Path.FindLastChar(TCHAR('\''), NameEndIndex);
  1447. if (NameEndIndex > NameStartIndex)
  1448. {
  1449. const FString ClassName = Path.Left(NameStartIndex);
  1450. const FString PathName = Path.Mid(NameStartIndex + 1, NameEndIndex - NameStartIndex - 1);
  1451. UClass* Class = FindObject<UClass>(ANY_PACKAGE, *ClassName, true);
  1452. if (Class)
  1453. {
  1454. return FPackageName::IsValidLongPackageName(FPackageName::ObjectPathToPackageName(PathName));
  1455. }
  1456. }
  1457. }
  1458. return false;
  1459. }
  1460. static bool ContainsT3D(const FString& ClipboardText)
  1461. {
  1462. return (ClipboardText.StartsWith(TEXT("Begin Object")) && ClipboardText.EndsWith(TEXT("End Object")))
  1463. || (ClipboardText.StartsWith(TEXT("Begin Map")) && ClipboardText.EndsWith(TEXT("End Map")));
  1464. }
  1465. #endif
  1466. FReply SExtAssetView::OnKeyDown( const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent )
  1467. {
  1468. #if ECB_LEGACY
  1469. const bool bIsControlOrCommandDown = InKeyEvent.IsControlDown() || InKeyEvent.IsCommandDown();
  1470. if (bIsControlOrCommandDown && InKeyEvent.GetCharacter() == 'V' && IsAssetPathSelected())
  1471. {
  1472. FString AssetPaths;
  1473. TArray<FString> AssetPathsSplit;
  1474. // Get the copied asset paths
  1475. FPlatformApplicationMisc::ClipboardPaste(AssetPaths);
  1476. // Make sure the clipboard does not contain T3D
  1477. AssetPaths.TrimEndInline();
  1478. if (!ContainsT3D(AssetPaths))
  1479. {
  1480. AssetPaths.ParseIntoArrayLines(AssetPathsSplit);
  1481. // Get assets and copy them
  1482. TArray<UObject*> AssetsToCopy;
  1483. for (const FString& AssetPath : AssetPathsSplit)
  1484. {
  1485. // Validate string
  1486. if (IsValidObjectPath(AssetPath))
  1487. {
  1488. UObject* ObjectToCopy = LoadObject<UObject>(nullptr, *AssetPath);
  1489. if (ObjectToCopy && !ObjectToCopy->IsA(UClass::StaticClass()))
  1490. {
  1491. AssetsToCopy.Add(ObjectToCopy);
  1492. }
  1493. }
  1494. }
  1495. if (AssetsToCopy.Num())
  1496. {
  1497. ContentBrowserUtils::CopyAssets(AssetsToCopy, SourcesData.PackagePaths[0].ToString());
  1498. }
  1499. }
  1500. return FReply::Handled();
  1501. }
  1502. // Swallow the key-presses used by the quick-jump in OnKeyChar to avoid other things (such as the viewport commands) getting them instead
  1503. // eg) Pressing "W" without this would set the viewport to "translate" mode
  1504. else if(HandleQuickJumpKeyDown(InKeyEvent.GetCharacter(), bIsControlOrCommandDown, InKeyEvent.IsAltDown(), /*bTestOnly*/true).IsEventHandled())
  1505. {
  1506. return FReply::Handled();
  1507. }
  1508. #endif
  1509. return FReply::Unhandled();
  1510. }
  1511. FReply SExtAssetView::OnMouseWheel( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
  1512. {
  1513. if( MouseEvent.IsControlDown() )
  1514. {
  1515. const float DesiredScale = FMath::Clamp<float>(GetThumbnailScale() + ( MouseEvent.GetWheelDelta() * 0.05f ), 0.0f, 1.0f);
  1516. if ( DesiredScale != GetThumbnailScale() )
  1517. {
  1518. SetThumbnailScale( DesiredScale );
  1519. }
  1520. return FReply::Handled();
  1521. }
  1522. return FReply::Unhandled();
  1523. }
  1524. #if ECB_WIP_BREADCRUMB
  1525. void SExtAssetView::OnFocusChanging( const FWeakWidgetPath& PreviousFocusPath, const FWidgetPath& NewWidgetPath, const FFocusEvent& InFocusEvent)
  1526. {
  1527. ResetQuickJump();
  1528. }
  1529. #endif
  1530. TSharedRef<SExtAssetTileView> SExtAssetView::CreateTileView()
  1531. {
  1532. return SNew(SExtAssetTileView)
  1533. .SelectionMode(SelectionMode)
  1534. .ListItemsSource(&FilteredAssetItems)
  1535. .OnGenerateTile(this, &SExtAssetView::MakeTileViewWidget)
  1536. .OnItemScrolledIntoView(this, &SExtAssetView::ItemScrolledIntoView)
  1537. .OnContextMenuOpening(this, &SExtAssetView::OnGetContextMenuContent)
  1538. .OnMouseButtonDoubleClick(this, &SExtAssetView::OnListMouseButtonDoubleClick)
  1539. .OnSelectionChanged(this, &SExtAssetView::AssetSelectionChanged)
  1540. .ItemHeight(this, &SExtAssetView::GetTileViewItemHeight)
  1541. .ItemWidth(this, &SExtAssetView::GetTileViewItemWidth);
  1542. }
  1543. TSharedRef<SExtAssetListView> SExtAssetView::CreateListView()
  1544. {
  1545. return SNew(SExtAssetListView)
  1546. .SelectionMode( SelectionMode )
  1547. .ListItemsSource(&FilteredAssetItems)
  1548. .OnGenerateRow(this, &SExtAssetView::MakeListViewWidget)
  1549. .OnItemScrolledIntoView(this, &SExtAssetView::ItemScrolledIntoView)
  1550. .OnContextMenuOpening(this, &SExtAssetView::OnGetContextMenuContent)
  1551. .OnMouseButtonDoubleClick(this, &SExtAssetView::OnListMouseButtonDoubleClick)
  1552. .OnSelectionChanged(this, &SExtAssetView::AssetSelectionChanged)
  1553. .ItemHeight(this, &SExtAssetView::GetListViewItemHeight);
  1554. }
  1555. TSharedRef<SExtAssetColumnView> SExtAssetView::CreateColumnView()
  1556. {
  1557. TSharedPtr<SExtAssetColumnView> NewColumnView = SNew(SExtAssetColumnView)
  1558. .SelectionMode( SelectionMode )
  1559. .ListItemsSource(&FilteredAssetItems)
  1560. .OnGenerateRow(this, &SExtAssetView::MakeColumnViewWidget)
  1561. .OnItemScrolledIntoView(this, &SExtAssetView::ItemScrolledIntoView)
  1562. .OnContextMenuOpening(this, &SExtAssetView::OnGetContextMenuContent)
  1563. .OnMouseButtonDoubleClick(this, &SExtAssetView::OnListMouseButtonDoubleClick)
  1564. .OnSelectionChanged(this, &SExtAssetView::AssetSelectionChanged)
  1565. .Visibility(this, &SExtAssetView::GetColumnViewVisibility)
  1566. .HeaderRow
  1567. (
  1568. SNew(SHeaderRow)
  1569. .ResizeMode(ESplitterResizeMode::FixedSize)
  1570. + SHeaderRow::Column(SortManager.NameColumnId)
  1571. .FillWidth(300)
  1572. .SortMode( TAttribute< EColumnSortMode::Type >::Create( TAttribute< EColumnSortMode::Type >::FGetter::CreateSP( this, &SExtAssetView::GetColumnSortMode, SortManager.NameColumnId ) ) )
  1573. .SortPriority(TAttribute< EColumnSortPriority::Type >::Create(TAttribute< EColumnSortPriority::Type >::FGetter::CreateSP(this, &SExtAssetView::GetColumnSortPriority, SortManager.NameColumnId)))
  1574. .OnSort( FOnSortModeChanged::CreateSP( this, &SExtAssetView::OnSortColumnHeader ) )
  1575. .DefaultLabel( LOCTEXT("Column_Name", "Name") )
  1576. .ShouldGenerateWidget(TAttribute<bool>::Create(TAttribute<bool>::FGetter::CreateSP(this, &SExtAssetView::ShouldColumnGenerateWidget, SortManager.NameColumnId.ToString())))
  1577. .MenuContent()
  1578. [
  1579. CreateRowHeaderMenuContent(SortManager.NameColumnId.ToString())
  1580. ]
  1581. );
  1582. NewColumnView->GetHeaderRow()->SetOnGetMaxRowSizeForColumn(FOnGetMaxRowSizeForColumn::CreateRaw(NewColumnView.Get(), &SExtAssetColumnView::GetMaxRowSizeForColumn));
  1583. NumVisibleColumns = HiddenColumnNames.Contains(SortManager.NameColumnId.ToString()) ? 0 : 1;
  1584. if(bShowTypeInColumnView)
  1585. {
  1586. NewColumnView->GetHeaderRow()->AddColumn(
  1587. SHeaderRow::Column(SortManager.ClassColumnId)
  1588. .FillWidth(160)
  1589. .SortMode(TAttribute< EColumnSortMode::Type >::Create(TAttribute< EColumnSortMode::Type >::FGetter::CreateSP(this, &SExtAssetView::GetColumnSortMode, SortManager.ClassColumnId)))
  1590. .SortPriority(TAttribute< EColumnSortPriority::Type >::Create(TAttribute< EColumnSortPriority::Type >::FGetter::CreateSP(this, &SExtAssetView::GetColumnSortPriority, SortManager.ClassColumnId)))
  1591. .OnSort(FOnSortModeChanged::CreateSP(this, &SExtAssetView::OnSortColumnHeader))
  1592. .DefaultLabel(LOCTEXT("Column_Class", "Type"))
  1593. .ShouldGenerateWidget(TAttribute<bool>::Create(TAttribute<bool>::FGetter::CreateSP(this, &SExtAssetView::ShouldColumnGenerateWidget, SortManager.ClassColumnId.ToString())))
  1594. .MenuContent()
  1595. [
  1596. CreateRowHeaderMenuContent(SortManager.ClassColumnId.ToString())
  1597. ]
  1598. );
  1599. NumVisibleColumns += HiddenColumnNames.Contains(SortManager.ClassColumnId.ToString()) ? 0 : 1;
  1600. }
  1601. if (bShowPathInColumnView)
  1602. {
  1603. NewColumnView->GetHeaderRow()->AddColumn(
  1604. SHeaderRow::Column(SortManager.PathColumnId)
  1605. .FillWidth(160)
  1606. .SortMode(TAttribute< EColumnSortMode::Type >::Create(TAttribute< EColumnSortMode::Type >::FGetter::CreateSP(this, &SExtAssetView::GetColumnSortMode, SortManager.PathColumnId)))
  1607. .SortPriority(TAttribute< EColumnSortPriority::Type >::Create(TAttribute< EColumnSortPriority::Type >::FGetter::CreateSP(this, &SExtAssetView::GetColumnSortPriority, SortManager.PathColumnId)))
  1608. .OnSort(FOnSortModeChanged::CreateSP(this, &SExtAssetView::OnSortColumnHeader))
  1609. .DefaultLabel(LOCTEXT("Column_Path", "Path"))
  1610. .ShouldGenerateWidget(TAttribute<bool>::Create(TAttribute<bool>::FGetter::CreateSP(this, &SExtAssetView::ShouldColumnGenerateWidget, SortManager.PathColumnId.ToString())))
  1611. .MenuContent()
  1612. [
  1613. CreateRowHeaderMenuContent(SortManager.PathColumnId.ToString())
  1614. ]
  1615. );
  1616. NumVisibleColumns += HiddenColumnNames.Contains(SortManager.PathColumnId.ToString()) ? 0 : 1;
  1617. }
  1618. return NewColumnView.ToSharedRef();
  1619. }
  1620. #if ECB_LEGACY
  1621. bool SExtAssetView::IsValidSearchToken(const FString& Token) const
  1622. {
  1623. if ( Token.Len() == 0 )
  1624. {
  1625. return false;
  1626. }
  1627. // A token may not be only apostrophe only, or it will match every asset because the text filter compares against the pattern Class'ObjectPath'
  1628. if ( Token.Len() == 1 && Token[0] == '\'' )
  1629. {
  1630. return false;
  1631. }
  1632. return true;
  1633. }
  1634. #endif
  1635. void SExtAssetView::RefreshSourceItems()
  1636. {
  1637. RecentlyLoadedOrChangedAssets.Reset();
  1638. RecentlyAddedAssets.Reset();
  1639. FilteredRecentlyAddedAssets.Reset();
  1640. QueriedAssetItems.Reset();
  1641. AssetItems.Reset();
  1642. FilteredAssetItems.Reset();
  1643. VisibleItems.Reset();
  1644. RelevantThumbnails.Reset();
  1645. Folders.Reset();
  1646. TArray<FExtAssetData>& Items = OnShouldFilterAsset.IsBound() ? QueriedAssetItems : AssetItems;
  1647. if (OnShouldFilterAsset.IsBound())
  1648. {
  1649. ECB_LOG(Display, TEXT("OnShouldFilterAsset.IsBound()"));
  1650. }
  1651. #if ECB_TODO // show all?
  1652. const bool bShowAll = SourcesData.IsEmpty() && BackendFilter.IsEmpty();
  1653. if ( bShowAll )
  1654. {
  1655. // Include assets in memory
  1656. TSet<FName> PackageNamesToSkip = AssetRegistryModule.Get().GetCachedEmptyPackages();
  1657. for (FObjectIterator ObjIt; ObjIt; ++ObjIt)
  1658. {
  1659. if (ObjIt->IsAsset())
  1660. {
  1661. if (!InitialAssetFilter.PassesPackagePathFilter(ObjIt->GetOutermost()->GetFName()))
  1662. {
  1663. continue;
  1664. }
  1665. int32 Index = Items.Emplace(*ObjIt);
  1666. const FExtAssetData& AssetData = Items[Index];
  1667. if (!InitialAssetFilter.PassesRedirectorMainAssetFilter(AssetData))
  1668. {
  1669. Items.RemoveAtSwap(Index, 1, false);
  1670. continue;
  1671. }
  1672. PackageNamesToSkip.Add(AssetData.PackageName);
  1673. }
  1674. }
  1675. // Include assets on disk
  1676. const TMap<FName, const FAssetData*>& AssetDataMap = AssetRegistryModule.Get().GetAssetRegistryState()->GetObjectPathToAssetDataMap();
  1677. for (const TPair<FName, const FAssetData*>& AssetDataPair : AssetDataMap)
  1678. {
  1679. const FAssetData* AssetData = AssetDataPair.Value;
  1680. if (AssetData == nullptr)
  1681. {
  1682. continue;
  1683. }
  1684. // Make sure the asset's package was not loaded then the object was deleted/renamed
  1685. if (PackageNamesToSkip.Contains(AssetData->PackageName))
  1686. {
  1687. continue;
  1688. }
  1689. if (!InitialAssetFilter.PassesFilter(*AssetData))
  1690. {
  1691. continue;
  1692. }
  1693. Items.Emplace(*AssetData);
  1694. }
  1695. bShowClasses = IsShowingCppContent();
  1696. bWereItemsRecursivelyFiltered = true;
  1697. }
  1698. else
  1699. #endif
  1700. {
  1701. // Assemble the filter using the current sources
  1702. // force recursion when the user is searching
  1703. const bool bRecurse = ShouldFilterRecursively();
  1704. const bool bUsingFolders = IsShowingFolders();
  1705. const bool bIsDynamicCollection = SourcesData.IsDynamicCollection();
  1706. FARFilter Filter = SourcesData.MakeFilter(bRecurse, bUsingFolders);
  1707. // Add the backend filters from the filter list
  1708. Filter.Append(BackendFilter);
  1709. bWereItemsRecursivelyFiltered = bRecurse;
  1710. #if ECB_WIP_COLLECTION
  1711. if ( SourcesData.HasCollections() && Filter.ObjectPaths.Num() == 0 && !bIsDynamicCollection )
  1712. {
  1713. // This is an empty collection, no asset will pass the check
  1714. }
  1715. else
  1716. #endif
  1717. {
  1718. #if ECB_FEA_ASYNC_ASSET_DISCOVERY
  1719. FExtContentBrowserSingleton::GetAssetRegistry().CacheAssetsAsync(Filter);
  1720. #endif
  1721. // Add assets found in the asset registry
  1722. FExtContentBrowserSingleton::GetAssetRegistry().GetAssets(Filter, Items);
  1723. }
  1724. #if ECB_WIP_INITIAL_ASSET
  1725. for (int32 AssetIdx = Items.Num() - 1; AssetIdx >= 0; --AssetIdx)
  1726. {
  1727. if (!InitialAssetFilter.PassesFilter(Items[AssetIdx]))
  1728. {
  1729. Items.RemoveAtSwap(AssetIdx);
  1730. }
  1731. }
  1732. }
  1733. #endif
  1734. }
  1735. }
  1736. bool SExtAssetView::IsFiltering() const
  1737. {
  1738. // In some cases we want to not filter recursively even if we have a backend filter (e.g. the open level window)
  1739. // Most of the time, bFilterRecursivelyWithBackendFilter is true
  1740. if (bFilterRecursivelyWithBackendFilter && !BackendFilter.IsEmpty())
  1741. {
  1742. return true;
  1743. }
  1744. // Otherwise, check if there are any non-inverse frontend filters selected
  1745. if (FrontendFilters.IsValid())
  1746. {
  1747. for (int32 FilterIndex = 0; FilterIndex < FrontendFilters->Num(); ++FilterIndex)
  1748. {
  1749. const auto* Filter = static_cast<FExtFrontendFilter*>(FrontendFilters->GetFilterAtIndex(FilterIndex).Get());
  1750. if (Filter)
  1751. {
  1752. if (!Filter->IsInverseFilter())
  1753. {
  1754. return true;
  1755. }
  1756. }
  1757. }
  1758. }
  1759. return false;
  1760. }
  1761. bool SExtAssetView::ShouldFilterRecursively() const
  1762. {
  1763. const bool bSearchAndFilterRecursively = IsSearchAndFilterRecursively();
  1764. // Quick check for conditions which force recursive filtering
  1765. if (bUserSearching && bSearchAndFilterRecursively)
  1766. {
  1767. return true;
  1768. }
  1769. if (IsFiltering() && bSearchAndFilterRecursively)
  1770. {
  1771. return true;
  1772. }
  1773. #if ECB_LEGACY
  1774. // In some cases we want to not filter recursively even if we have a backend filter (e.g. the open level window)
  1775. // Most of the time, bFilterRecursivelyWithBackendFilter is true
  1776. if ( bFilterRecursivelyWithBackendFilter && !BackendFilter.IsEmpty() && bSearchAndFilterRecursively)
  1777. {
  1778. return true;
  1779. }
  1780. // Otherwise, check if there are any non-inverse frontend filters selected
  1781. if (FrontendFilters.IsValid() && bSearchAndFilterRecursively)
  1782. {
  1783. for (int32 FilterIndex = 0; FilterIndex < FrontendFilters->Num(); ++FilterIndex)
  1784. {
  1785. const auto* Filter = static_cast<FExtFrontendFilter*>(FrontendFilters->GetFilterAtIndex(FilterIndex).Get());
  1786. if (Filter)
  1787. {
  1788. if (!Filter->IsInverseFilter())
  1789. {
  1790. return true;
  1791. }
  1792. }
  1793. }
  1794. }
  1795. #endif
  1796. // No filters, do not override folder view with recursive filtering
  1797. return false;
  1798. }
  1799. void SExtAssetView::RefreshFilteredItems()
  1800. {
  1801. //Build up a map of the existing AssetItems so we can preserve them while filtering
  1802. TMap< FName, TSharedPtr< FExtAssetViewAsset > > ItemToObjectPath;
  1803. for (int Index = 0; Index < FilteredAssetItems.Num(); Index++)
  1804. {
  1805. if(FilteredAssetItems[Index].IsValid() && FilteredAssetItems[Index]->GetType() != EExtAssetItemType::Folder)
  1806. {
  1807. TSharedPtr<FExtAssetViewAsset> Item = StaticCastSharedPtr<FExtAssetViewAsset>(FilteredAssetItems[Index]);
  1808. // Clear custom column data
  1809. Item->CustomColumnData.Reset();
  1810. Item->CustomColumnDisplayText.Reset();
  1811. ItemToObjectPath.Add( Item->Data.ObjectPath, Item );
  1812. }
  1813. }
  1814. // Empty all the filtered lists
  1815. FilteredAssetItems.Reset();
  1816. VisibleItems.Reset();
  1817. RelevantThumbnails.Reset();
  1818. Folders.Reset();
  1819. // true if the results from the asset registry query are filtered further by the content browser
  1820. const bool bIsFrontendFilterActive = IsFrontendFilterActive();
  1821. // true if we are looking at columns so we need to determine the majority asset type
  1822. const bool bGatherAssetTypeCount = CurrentViewType == EAssetViewType::Column;
  1823. TMap<FName, int32> AssetTypeCount;
  1824. if ( bIsFrontendFilterActive && FrontendFilters.IsValid() )
  1825. {
  1826. const bool bRecurse = ShouldFilterRecursively();
  1827. #if ECB_WIP_SEARCH_RECURSE_TOGGLE
  1828. const bool bShouldHideFolders = (bUserSearching || IsFiltering()) && !IsSearchAndFilterRecursively();
  1829. #else
  1830. const bool bShouldHideFolders = false;
  1831. #endif
  1832. const bool bUsingFolders = IsShowingFolders() && !bShouldHideFolders;
  1833. FARFilter CombinedFilter = SourcesData.MakeFilter(bRecurse, bUsingFolders);
  1834. CombinedFilter.Append(BackendFilter);
  1835. // Let the frontend filters know the currently used filter in case it is necessary to conditionally filter based on path or class filters
  1836. for ( int32 FilterIdx = 0; FilterIdx < FrontendFilters->Num(); ++FilterIdx )
  1837. {
  1838. // There are only FFrontendFilters in this collection
  1839. const TSharedPtr<FExtFrontendFilter>& Filter = StaticCastSharedPtr<FExtFrontendFilter>( FrontendFilters->GetFilterAtIndex(FilterIdx) );
  1840. if ( Filter.IsValid() )
  1841. {
  1842. Filter->SetCurrentFilter(CombinedFilter);
  1843. }
  1844. }
  1845. }
  1846. if ( bIsFrontendFilterActive && bGatherAssetTypeCount )
  1847. {
  1848. // Check the frontend filter for every asset and keep track of how many assets were found of each type
  1849. for (int32 AssetIdx = 0; AssetIdx < AssetItems.Num(); ++AssetIdx)
  1850. {
  1851. const FExtAssetData& AssetData = AssetItems[AssetIdx];
  1852. if ( PassesCurrentFrontendFilter(AssetData) )
  1853. {
  1854. const TSharedPtr< FExtAssetViewAsset >* AssetItem = ItemToObjectPath.Find( AssetData.ObjectPath );
  1855. if ( AssetItem != NULL )
  1856. {
  1857. FilteredAssetItems.Add(*AssetItem);
  1858. }
  1859. else
  1860. {
  1861. FilteredAssetItems.Add(MakeShareable(new FExtAssetViewAsset(AssetData)));
  1862. }
  1863. int32* TypeCount = AssetTypeCount.Find(AssetData.AssetClass);
  1864. if ( TypeCount )
  1865. {
  1866. (*TypeCount)++;
  1867. }
  1868. else
  1869. {
  1870. AssetTypeCount.Add(AssetData.AssetClass, 1);
  1871. }
  1872. }
  1873. }
  1874. }
  1875. else if ( bIsFrontendFilterActive && !bGatherAssetTypeCount )
  1876. {
  1877. // Check the frontend filter for every asset and don't worry about asset type counts
  1878. for (int32 AssetIdx = 0; AssetIdx < AssetItems.Num(); ++AssetIdx)
  1879. {
  1880. const FExtAssetData& AssetData = AssetItems[AssetIdx];
  1881. if ( PassesCurrentFrontendFilter(AssetData) )
  1882. {
  1883. const TSharedPtr< FExtAssetViewAsset >* AssetItem = ItemToObjectPath.Find( AssetData.ObjectPath );
  1884. if ( AssetItem != NULL )
  1885. {
  1886. FilteredAssetItems.Add(*AssetItem);
  1887. }
  1888. else
  1889. {
  1890. FilteredAssetItems.Add(MakeShareable(new FExtAssetViewAsset(AssetData)));
  1891. }
  1892. }
  1893. }
  1894. }
  1895. else if ( !bIsFrontendFilterActive && bGatherAssetTypeCount )
  1896. {
  1897. // Don't need to check the frontend filter for every asset but keep track of how many assets were found of each type
  1898. for (int32 AssetIdx = 0; AssetIdx < AssetItems.Num(); ++AssetIdx)
  1899. {
  1900. const FExtAssetData& AssetData = AssetItems[AssetIdx];
  1901. const TSharedPtr< FExtAssetViewAsset >* AssetItem = ItemToObjectPath.Find( AssetData.ObjectPath );
  1902. if ( AssetItem != NULL )
  1903. {
  1904. FilteredAssetItems.Add(*AssetItem);
  1905. }
  1906. else
  1907. {
  1908. FilteredAssetItems.Add(MakeShareable(new FExtAssetViewAsset(AssetData)));
  1909. }
  1910. int32* TypeCount = AssetTypeCount.Find(AssetData.AssetClass);
  1911. if ( TypeCount )
  1912. {
  1913. (*TypeCount)++;
  1914. }
  1915. else
  1916. {
  1917. AssetTypeCount.Add(AssetData.AssetClass, 1);
  1918. }
  1919. }
  1920. }
  1921. else if ( !bIsFrontendFilterActive && !bGatherAssetTypeCount )
  1922. {
  1923. // Don't check the frontend filter and don't count the number of assets of each type. Just add all assets.
  1924. for (int32 AssetIdx = 0; AssetIdx < AssetItems.Num(); ++AssetIdx)
  1925. {
  1926. const FExtAssetData& AssetData = AssetItems[AssetIdx];
  1927. const TSharedPtr< FExtAssetViewAsset >* AssetItem = ItemToObjectPath.Find( AssetData.ObjectPath );
  1928. if ( AssetItem != NULL )
  1929. {
  1930. FilteredAssetItems.Add(*AssetItem);
  1931. }
  1932. else
  1933. {
  1934. FilteredAssetItems.Add(MakeShareable(new FExtAssetViewAsset(AssetData)));
  1935. }
  1936. }
  1937. }
  1938. else
  1939. {
  1940. // The above cases should handle all combinations of bIsFrontendFilterActive and bGatherAssetTypeCount
  1941. ensure(0);
  1942. }
  1943. if ( bGatherAssetTypeCount )
  1944. {
  1945. int32 HighestCount = 0;
  1946. FName HighestType;
  1947. for ( auto TypeIt = AssetTypeCount.CreateConstIterator(); TypeIt; ++TypeIt )
  1948. {
  1949. if ( TypeIt.Value() > HighestCount )
  1950. {
  1951. HighestType = TypeIt.Key();
  1952. HighestCount = TypeIt.Value();
  1953. }
  1954. }
  1955. SetMajorityAssetType(HighestType);
  1956. }
  1957. }
  1958. void SExtAssetView::RefreshFolders()
  1959. {
  1960. if(!IsShowingFolders() || ShouldFilterRecursively())
  1961. {
  1962. return;
  1963. }
  1964. #if ECB_WIP_SEARCH_RECURSE_TOGGLE
  1965. const bool bShouldHideFolders = (bUserSearching || IsFiltering()) && !IsSearchAndFilterRecursively();
  1966. if (bShouldHideFolders)
  1967. {
  1968. return;
  1969. }
  1970. #endif
  1971. // Split the selected paths into asset and class paths
  1972. TArray<FName> AssetPathsToShow;
  1973. TArray<FName> ClassPathsToShow;
  1974. for(const FName& PackagePath : SourcesData.PackagePaths)
  1975. {
  1976. if(ExtContentBrowserUtils::IsClassPath(PackagePath.ToString()))
  1977. {
  1978. ClassPathsToShow.Add(PackagePath);
  1979. }
  1980. else
  1981. {
  1982. AssetPathsToShow.Add(PackagePath);
  1983. }
  1984. }
  1985. TArray<FString> FoldersToAdd;
  1986. const bool bDisplayEmpty = IsShowingEmptyFolders();
  1987. {
  1988. TSet<FName> SubPaths;
  1989. for(const FName& PackagePath : AssetPathsToShow)
  1990. {
  1991. SubPaths.Reset();
  1992. FExtContentBrowserSingleton::GetAssetRegistry().GetOrCacheSubPaths(PackagePath, SubPaths, false);
  1993. for(const FName& SubPath : SubPaths)
  1994. {
  1995. FString SubPathString = SubPath.ToString();
  1996. if (!bDisplayEmpty && FExtContentBrowserSingleton::GetAssetRegistry().IsEmptyFolder(SubPathString))
  1997. {
  1998. continue;
  1999. }
  2000. if(!Folders.Contains(SubPathString))
  2001. {
  2002. FoldersToAdd.Add(SubPathString);
  2003. }
  2004. }
  2005. }
  2006. }
  2007. // Add folders for any child collections of the currently selected collections
  2008. if(SourcesData.HasCollections())
  2009. {
  2010. FCollectionManagerModule& CollectionManagerModule = FCollectionManagerModule::GetModule();
  2011. TArray<FCollectionNameType> ChildCollections;
  2012. for(const FCollectionNameType& Collection : SourcesData.Collections)
  2013. {
  2014. ChildCollections.Reset();
  2015. CollectionManagerModule.Get().GetChildCollections(Collection.Name, Collection.Type, ChildCollections);
  2016. for(const FCollectionNameType& ChildCollection : ChildCollections)
  2017. {
  2018. // Use "Collections" as the root of the path to avoid this being confused with other asset view folders - see ContentBrowserUtils::IsCollectionPath
  2019. FoldersToAdd.Add(FString::Printf(TEXT("/Collections/%s/%s"), ECollectionShareType::ToString(ChildCollection.Type), *ChildCollection.Name.ToString()));
  2020. }
  2021. }
  2022. }
  2023. if(FoldersToAdd.Num() > 0)
  2024. {
  2025. for(const FString& FolderPath : FoldersToAdd)
  2026. {
  2027. FilteredAssetItems.Add(MakeShareable(new FExtAssetViewFolder(FolderPath)));
  2028. Folders.Add(FolderPath);
  2029. }
  2030. RefreshList();
  2031. bPendingSortFilteredItems = true;
  2032. }
  2033. }
  2034. void SExtAssetView::SetMajorityAssetType(FName NewMajorityAssetType)
  2035. {
  2036. auto IsFixedColumn = [this](FName InColumnId)
  2037. {
  2038. const bool bIsFixedNameColumn = InColumnId == SortManager.NameColumnId;
  2039. const bool bIsFixedClassColumn = bShowTypeInColumnView && InColumnId == SortManager.ClassColumnId;
  2040. const bool bIsFixedPathColumn = bShowPathInColumnView && InColumnId == SortManager.PathColumnId;
  2041. return bIsFixedNameColumn || bIsFixedClassColumn || bIsFixedPathColumn;
  2042. };
  2043. if ( NewMajorityAssetType != MajorityAssetType )
  2044. {
  2045. ECB_LOG(Display , TEXT("The majority of assets in the view are of type: %s"), *NewMajorityAssetType.ToString());
  2046. MajorityAssetType = NewMajorityAssetType;
  2047. TArray<FName> AddedColumns;
  2048. // Since the asset type has changed, remove all columns except name and class
  2049. const TIndirectArray<SHeaderRow::FColumn>& Columns = ColumnView->GetHeaderRow()->GetColumns();
  2050. for ( int32 ColumnIdx = Columns.Num() - 1; ColumnIdx >= 0; --ColumnIdx )
  2051. {
  2052. const FName ColumnId = Columns[ColumnIdx].ColumnId;
  2053. if ( ColumnId != NAME_None && !IsFixedColumn(ColumnId) )
  2054. {
  2055. ColumnView->GetHeaderRow()->RemoveColumn(ColumnId);
  2056. }
  2057. }
  2058. // Keep track of the current column name to see if we need to change it now that columns are being removed
  2059. // Name, Class, and Path are always relevant
  2060. struct FSortOrder
  2061. {
  2062. bool bSortRelevant;
  2063. FName SortColumn;
  2064. FSortOrder(bool bInSortRelevant, const FName& InSortColumn) : bSortRelevant(bInSortRelevant), SortColumn(InSortColumn) {}
  2065. };
  2066. TArray<FSortOrder> CurrentSortOrder;
  2067. for (int32 PriorityIdx = 0; PriorityIdx < EColumnSortPriority::Max; PriorityIdx++)
  2068. {
  2069. const FName SortColumn = SortManager.GetSortColumnId(static_cast<EColumnSortPriority::Type>(PriorityIdx));
  2070. if (SortColumn != NAME_None)
  2071. {
  2072. const bool bSortRelevant = SortColumn == FAssetViewSortManager::NameColumnId
  2073. || SortColumn == FAssetViewSortManager::ClassColumnId
  2074. || SortColumn == FAssetViewSortManager::PathColumnId;
  2075. CurrentSortOrder.Add(FSortOrder(bSortRelevant, SortColumn));
  2076. }
  2077. }
  2078. // Add custom columns
  2079. for (const FAssetViewCustomColumn& Column : CustomColumns)
  2080. {
  2081. FName TagName = Column.ColumnName;
  2082. if (AddedColumns.Contains(TagName))
  2083. {
  2084. continue;
  2085. }
  2086. AddedColumns.Add(TagName);
  2087. ColumnView->GetHeaderRow()->AddColumn(
  2088. SHeaderRow::Column(TagName)
  2089. .SortMode(TAttribute< EColumnSortMode::Type >::Create(TAttribute< EColumnSortMode::Type >::FGetter::CreateSP(this, &SExtAssetView::GetColumnSortMode, TagName)))
  2090. .SortPriority(TAttribute< EColumnSortPriority::Type >::Create(TAttribute< EColumnSortPriority::Type >::FGetter::CreateSP(this, &SExtAssetView::GetColumnSortPriority, TagName)))
  2091. .OnSort(FOnSortModeChanged::CreateSP(this, &SExtAssetView::OnSortColumnHeader))
  2092. .DefaultLabel(Column.DisplayName)
  2093. .DefaultTooltip(Column.TooltipText)
  2094. .FillWidth(180)
  2095. .ShouldGenerateWidget(TAttribute<bool>::Create(TAttribute<bool>::FGetter::CreateSP(this, &SExtAssetView::ShouldColumnGenerateWidget, TagName.ToString())))
  2096. .MenuContent()
  2097. [
  2098. CreateRowHeaderMenuContent(TagName.ToString())
  2099. ]);
  2100. NumVisibleColumns += HiddenColumnNames.Contains(TagName.ToString()) ? 0 : 1;
  2101. // If we found a tag the matches the column we are currently sorting on, there will be no need to change the column
  2102. for (int32 SortIdx = 0; SortIdx < CurrentSortOrder.Num(); SortIdx++)
  2103. {
  2104. if (TagName == CurrentSortOrder[SortIdx].SortColumn)
  2105. {
  2106. CurrentSortOrder[SortIdx].bSortRelevant = true;
  2107. }
  2108. }
  2109. }
  2110. // If we have a new majority type, add the new type's columns
  2111. if ( NewMajorityAssetType != NAME_None )
  2112. {
  2113. // Determine the columns by querying the CDO for the tag map
  2114. UClass* TypeClass = FindObject<UClass>(nullptr, *NewMajorityAssetType.ToString());
  2115. if ( TypeClass )
  2116. {
  2117. UObject* CDO = TypeClass->GetDefaultObject();
  2118. if ( CDO )
  2119. {
  2120. TArray<UObject::FAssetRegistryTag> AssetRegistryTags;
  2121. CDO->GetAssetRegistryTags(AssetRegistryTags);
  2122. // Add a column for every tag that isn't hidden or using a reserved name
  2123. for ( auto TagIt = AssetRegistryTags.CreateConstIterator(); TagIt; ++TagIt )
  2124. {
  2125. if ( TagIt->Type != UObject::FAssetRegistryTag::TT_Hidden )
  2126. {
  2127. const FName TagName = TagIt->Name;
  2128. if (IsFixedColumn(TagName))
  2129. {
  2130. // Reserved name
  2131. continue;
  2132. }
  2133. //if ( !OnAssetTagWantsToBeDisplayed.IsBound() || OnAssetTagWantsToBeDisplayed.Execute(NewMajorityAssetType, TagName) )
  2134. {
  2135. if (AddedColumns.Contains(TagName))
  2136. {
  2137. continue;
  2138. }
  2139. AddedColumns.Add(TagName);
  2140. // Get tag metadata
  2141. TMap<FName, UObject::FAssetRegistryTagMetadata> MetadataMap;
  2142. CDO->GetAssetRegistryTagMetadata(MetadataMap);
  2143. const UObject::FAssetRegistryTagMetadata* Metadata = MetadataMap.Find(TagName);
  2144. FText DisplayName;
  2145. if (Metadata != nullptr && !Metadata->DisplayName.IsEmpty())
  2146. {
  2147. DisplayName = Metadata->DisplayName;
  2148. }
  2149. else
  2150. {
  2151. DisplayName = FText::FromName(TagName);
  2152. }
  2153. FText TooltipText;
  2154. if (Metadata != nullptr && !Metadata->TooltipText.IsEmpty())
  2155. {
  2156. TooltipText = Metadata->TooltipText;
  2157. }
  2158. else
  2159. {
  2160. // If the tag name corresponds to a property name, use the property tooltip
  2161. FProperty* Property = FindFProperty<FProperty>(TypeClass, TagName);
  2162. TooltipText = (Property != nullptr) ? Property->GetToolTipText() : FText::FromString(FName::NameToDisplayString(TagName.ToString(), false));
  2163. }
  2164. ColumnView->GetHeaderRow()->AddColumn(
  2165. SHeaderRow::Column(TagName)
  2166. .SortMode(TAttribute< EColumnSortMode::Type >::Create(TAttribute< EColumnSortMode::Type >::FGetter::CreateSP(this, &SExtAssetView::GetColumnSortMode, TagName)))
  2167. .SortPriority(TAttribute< EColumnSortPriority::Type >::Create(TAttribute< EColumnSortPriority::Type >::FGetter::CreateSP(this, &SExtAssetView::GetColumnSortPriority, TagName)))
  2168. .OnSort(FOnSortModeChanged::CreateSP(this, &SExtAssetView::OnSortColumnHeader))
  2169. .DefaultLabel(DisplayName)
  2170. .DefaultTooltip(TooltipText)
  2171. .FillWidth(180)
  2172. .ShouldGenerateWidget(TAttribute<bool>::Create(TAttribute<bool>::FGetter::CreateSP(this, &SExtAssetView::ShouldColumnGenerateWidget, TagName.ToString())))
  2173. .MenuContent()
  2174. [
  2175. CreateRowHeaderMenuContent(TagName.ToString())
  2176. ]);
  2177. NumVisibleColumns += HiddenColumnNames.Contains(TagName.ToString()) ? 0 : 1;
  2178. // If we found a tag the matches the column we are currently sorting on, there will be no need to change the column
  2179. for (int32 SortIdx = 0; SortIdx < CurrentSortOrder.Num(); SortIdx++)
  2180. {
  2181. if (TagName == CurrentSortOrder[SortIdx].SortColumn)
  2182. {
  2183. CurrentSortOrder[SortIdx].bSortRelevant = true;
  2184. }
  2185. }
  2186. }
  2187. }
  2188. }
  2189. }
  2190. }
  2191. }
  2192. // Are any of the sort columns irrelevant now, if so remove them from the list
  2193. bool CurrentSortChanged = false;
  2194. for (int32 SortIdx = CurrentSortOrder.Num() - 1; SortIdx >= 0; SortIdx--)
  2195. {
  2196. if (!CurrentSortOrder[SortIdx].bSortRelevant)
  2197. {
  2198. CurrentSortOrder.RemoveAt(SortIdx);
  2199. CurrentSortChanged = true;
  2200. }
  2201. }
  2202. if (CurrentSortOrder.Num() > 0 && CurrentSortChanged)
  2203. {
  2204. // Sort order has changed, update the columns keeping those that are relevant
  2205. int32 PriorityNum = EColumnSortPriority::Primary;
  2206. for (int32 SortIdx = 0; SortIdx < CurrentSortOrder.Num(); SortIdx++)
  2207. {
  2208. check(CurrentSortOrder[SortIdx].bSortRelevant);
  2209. if (!SortManager.SetOrToggleSortColumn(static_cast<EColumnSortPriority::Type>(PriorityNum), CurrentSortOrder[SortIdx].SortColumn))
  2210. {
  2211. // Toggle twice so mode is preserved if this isn't a new column assignation
  2212. SortManager.SetOrToggleSortColumn(static_cast<EColumnSortPriority::Type>(PriorityNum), CurrentSortOrder[SortIdx].SortColumn);
  2213. }
  2214. bPendingSortFilteredItems = true;
  2215. PriorityNum++;
  2216. }
  2217. }
  2218. else if (CurrentSortOrder.Num() == 0)
  2219. {
  2220. // If the current sort column is no longer relevant, revert to "Name" and resort when convenient
  2221. SortManager.ResetSort();
  2222. bPendingSortFilteredItems = true;
  2223. }
  2224. }
  2225. }
  2226. #if ECB_WIP_COLLECTION
  2227. void SExtAssetView::OnAssetsAddedToCollection( const FCollectionNameType& Collection, const TArray< FName >& ObjectPaths )
  2228. {
  2229. if ( !SourcesData.Collections.Contains( Collection ) )
  2230. {
  2231. return;
  2232. }
  2233. FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
  2234. for (int Index = 0; Index < ObjectPaths.Num(); Index++)
  2235. {
  2236. OnAssetAdded( AssetRegistryModule.Get().GetAssetByObjectPath( ObjectPaths[Index] ) );
  2237. }
  2238. }
  2239. void SExtAssetView::OnAssetsRemovedFromCollection(const FCollectionNameType& Collection, const TArray< FName >& ObjectPaths)
  2240. {
  2241. if (!SourcesData.Collections.Contains(Collection))
  2242. {
  2243. return;
  2244. }
  2245. FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
  2246. for (int Index = 0; Index < ObjectPaths.Num(); Index++)
  2247. {
  2248. OnAssetRemoved(AssetRegistryModule.Get().GetAssetByObjectPath(ObjectPaths[Index]));
  2249. }
  2250. }
  2251. #endif
  2252. #if ECB_FEA_ASYNC_ASSET_DISCOVERY
  2253. void SExtAssetView::ProcessRecentlyAddedAssets()
  2254. {
  2255. if (
  2256. (RecentlyAddedAssets.Num() > 2048) ||
  2257. (RecentlyAddedAssets.Num() > 0 && FPlatformTime::Seconds() - LastProcessAddsTime >= TimeBetweenAddingNewAssets)
  2258. )
  2259. {
  2260. RunAssetsThroughBackendFilter(RecentlyAddedAssets);
  2261. FilteredRecentlyAddedAssets.Append(RecentlyAddedAssets);
  2262. RecentlyAddedAssets.Reset();
  2263. LastProcessAddsTime = FPlatformTime::Seconds();
  2264. }
  2265. if (FilteredRecentlyAddedAssets.Num() > 0)
  2266. {
  2267. double TickStartTime = FPlatformTime::Seconds();
  2268. bool bNeedsRefresh = false;
  2269. TSet<FName> ExistingObjectPaths;
  2270. for ( auto AssetIt = AssetItems.CreateConstIterator(); AssetIt; ++AssetIt )
  2271. {
  2272. ExistingObjectPaths.Add((*AssetIt).ObjectPath);
  2273. }
  2274. for ( auto AssetIt = QueriedAssetItems.CreateConstIterator(); AssetIt; ++AssetIt )
  2275. {
  2276. ExistingObjectPaths.Add((*AssetIt).ObjectPath);
  2277. }
  2278. int32 AssetIdx = 0;
  2279. for ( ; AssetIdx < FilteredRecentlyAddedAssets.Num(); ++AssetIdx )
  2280. {
  2281. const FExtAssetData& AssetData = FilteredRecentlyAddedAssets[AssetIdx];
  2282. if ( !ExistingObjectPaths.Contains(AssetData.ObjectPath) )
  2283. {
  2284. if ( AssetData.AssetClass != UObjectRedirector::StaticClass()->GetFName() || AssetData.IsUAsset() )
  2285. {
  2286. if ( !OnShouldFilterAsset.IsBound() || !OnShouldFilterAsset.Execute(AssetData) )
  2287. {
  2288. // Add the asset to the list
  2289. int32 AddedAssetIdx = AssetItems.Add(AssetData);
  2290. ExistingObjectPaths.Add(AssetData.ObjectPath);
  2291. if (!IsFrontendFilterActive() || PassesCurrentFrontendFilter(AssetData))
  2292. {
  2293. FilteredAssetItems.Add(MakeShareable(new FExtAssetViewAsset(AssetData)));
  2294. bNeedsRefresh = true;
  2295. bPendingSortFilteredItems = true;
  2296. }
  2297. }
  2298. }
  2299. }
  2300. if ( (FPlatformTime::Seconds() - TickStartTime) > MaxSecondsPerFrame)
  2301. {
  2302. // Increment the index to properly trim the buffer below
  2303. ++AssetIdx;
  2304. break;
  2305. }
  2306. }
  2307. // Trim the results array
  2308. if (AssetIdx > 0)
  2309. {
  2310. FilteredRecentlyAddedAssets.RemoveAt(0, AssetIdx);
  2311. }
  2312. if (bNeedsRefresh)
  2313. {
  2314. RefreshList();
  2315. }
  2316. }
  2317. }
  2318. #endif
  2319. #if ECB_LEGACY
  2320. void SExtAssetView::OnAssetAdded(const FExtAssetData& AssetData)
  2321. {
  2322. RecentlyAddedAssets.Add(AssetData);
  2323. }
  2324. void SExtAssetView::OnAssetRemoved(const FAssetData& AssetData)
  2325. {
  2326. RemoveAssetByPath( AssetData.ObjectPath );
  2327. RecentlyAddedAssets.RemoveSingleSwap(AssetData);
  2328. }
  2329. void SExtAssetView::OnAssetRegistryPathAdded(const FString& Path)
  2330. {
  2331. if(IsShowingFolders() && !ShouldFilterRecursively())
  2332. {
  2333. TSharedRef<FEmptyFolderVisibilityManager> EmptyFolderVisibilityManager = FContentBrowserSingleton::Get().GetEmptyFolderVisibilityManager();
  2334. // If this isn't a developer folder or we want to show them, continue
  2335. const bool bDisplayEmpty = IsShowingEmptyFolders();
  2336. const bool bDisplayL10N = IsShowingLocalizedContent();
  2337. if ((bDisplayEmpty || EmptyFolderVisibilityManager->ShouldShowPath(Path)) &&
  2338. (bDisplayL10N || !ContentBrowserUtils::IsLocalizationFolder(Path))
  2339. )
  2340. {
  2341. for (const FName& SourcePathName : SourcesData.PackagePaths)
  2342. {
  2343. // Ensure that /Folder2 is not considered a subfolder of /Folder by appending /
  2344. FString SourcePath = SourcePathName.ToString() / TEXT("");
  2345. if(Path.StartsWith(SourcePath))
  2346. {
  2347. const FString SubPath = Path.RightChop(SourcePath.Len());
  2348. TArray<FString> SubPathItemList;
  2349. SubPath.ParseIntoArray(SubPathItemList, TEXT("/"), /*InCullEmpty=*/true);
  2350. if (SubPathItemList.Num() > 0)
  2351. {
  2352. const FString NewSubFolder = SourcePath / SubPathItemList[0];
  2353. if (!Folders.Contains(NewSubFolder))
  2354. {
  2355. FilteredAssetItems.Add(MakeShareable(new FAssetViewFolder(NewSubFolder)));
  2356. RefreshList();
  2357. Folders.Add(NewSubFolder);
  2358. bPendingSortFilteredItems = true;
  2359. }
  2360. }
  2361. }
  2362. }
  2363. }
  2364. }
  2365. }
  2366. void SExtAssetView::OnAssetRegistryPathRemoved(const FString& Path)
  2367. {
  2368. FString* Folder = Folders.Find(Path);
  2369. if(Folder != NULL)
  2370. {
  2371. Folders.Remove(Path);
  2372. for (int32 AssetIdx = 0; AssetIdx < FilteredAssetItems.Num(); ++AssetIdx)
  2373. {
  2374. if(FilteredAssetItems[AssetIdx]->GetType() == EAssetItemType::Folder)
  2375. {
  2376. if ( StaticCastSharedPtr<FAssetViewFolder>(FilteredAssetItems[AssetIdx])->FolderPath == Path )
  2377. {
  2378. // Found the folder in the filtered items list, remove it
  2379. FilteredAssetItems.RemoveAt(AssetIdx);
  2380. RefreshList();
  2381. break;
  2382. }
  2383. }
  2384. }
  2385. }
  2386. }
  2387. void SExtAssetView::OnFolderPopulated(const FString& Path)
  2388. {
  2389. OnAssetRegistryPathAdded(Path);
  2390. }
  2391. void SExtAssetView::RemoveAssetByPath( const FName& ObjectPath )
  2392. {
  2393. bool bFoundAsset = false;
  2394. for (int32 AssetIdx = 0; AssetIdx < AssetItems.Num(); ++AssetIdx)
  2395. {
  2396. if ( AssetItems[AssetIdx].ObjectPath == ObjectPath )
  2397. {
  2398. // Found the asset in the cached list, remove it
  2399. AssetItems.RemoveAt(AssetIdx);
  2400. bFoundAsset = true;
  2401. break;
  2402. }
  2403. }
  2404. if ( bFoundAsset )
  2405. {
  2406. // If it was in the AssetItems list, see if it is also in the FilteredAssetItems list
  2407. for (int32 AssetIdx = 0; AssetIdx < FilteredAssetItems.Num(); ++AssetIdx)
  2408. {
  2409. if(FilteredAssetItems[AssetIdx].IsValid() && FilteredAssetItems[AssetIdx]->GetType() != EAssetItemType::Folder)
  2410. {
  2411. if ( StaticCastSharedPtr<FExtAssetViewAsset>(FilteredAssetItems[AssetIdx])->Data.ObjectPath == ObjectPath && !FilteredAssetItems[AssetIdx]->IsTemporaryItem() )
  2412. {
  2413. // Found the asset in the filtered items list, remove it
  2414. FilteredAssetItems.RemoveAt(AssetIdx);
  2415. RefreshList();
  2416. break;
  2417. }
  2418. }
  2419. }
  2420. }
  2421. else
  2422. {
  2423. //Make sure we don't have the item still queued up for processing
  2424. for (int32 AssetIdx = 0; AssetIdx < QueriedAssetItems.Num(); ++AssetIdx)
  2425. {
  2426. if ( QueriedAssetItems[AssetIdx].ObjectPath == ObjectPath )
  2427. {
  2428. // Found the asset in the cached list, remove it
  2429. QueriedAssetItems.RemoveAt(AssetIdx);
  2430. bFoundAsset = true;
  2431. break;
  2432. }
  2433. }
  2434. }
  2435. }
  2436. void SExtAssetView::OnCollectionRenamed( const FCollectionNameType& OriginalCollection, const FCollectionNameType& NewCollection )
  2437. {
  2438. int32 FoundIndex = INDEX_NONE;
  2439. if ( SourcesData.Collections.Find( OriginalCollection, FoundIndex ) )
  2440. {
  2441. SourcesData.Collections[ FoundIndex ] = NewCollection;
  2442. }
  2443. }
  2444. void SExtAssetView::OnCollectionUpdated( const FCollectionNameType& Collection )
  2445. {
  2446. // A collection has changed in some way, so we need to refresh our backend list
  2447. RequestSlowFullListRefresh();
  2448. }
  2449. void SExtAssetView::OnAssetRenamed(const FAssetData& AssetData, const FString& OldObjectPath)
  2450. {
  2451. // Remove the old asset, if it exists
  2452. FName OldObjectPackageName = *OldObjectPath;
  2453. RemoveAssetByPath( OldObjectPackageName );
  2454. RecentlyAddedAssets.RemoveAllSwap( [&](const FAssetData& Other) { return Other.ObjectPath == OldObjectPackageName; } );
  2455. // Add the new asset, if it should be in the cached list
  2456. OnAssetAdded( AssetData );
  2457. // Force an update of the recently added asset next frame
  2458. RequestAddNewAssetsNextFrame();
  2459. }
  2460. void SExtAssetView::OnAssetLoaded(UObject* Asset)
  2461. {
  2462. if (Asset == nullptr)
  2463. {
  2464. return;
  2465. }
  2466. FName AssetPathName = FName(*Asset->GetPathName());
  2467. RecentlyLoadedOrChangedAssets.Add( FAssetData(Asset) );
  2468. UTexture2D* Texture2D = Cast<UTexture2D>(Asset);
  2469. UMaterial* Material = Texture2D ? nullptr : Cast<UMaterial>(Asset);
  2470. if ((Texture2D && !Texture2D->bForceMiplevelsToBeResident) || Material)
  2471. {
  2472. bool bHasWidgetForAsset = false;
  2473. switch (GetCurrentViewType())
  2474. {
  2475. case EAssetViewType::List:
  2476. bHasWidgetForAsset = ListView->HasWidgetForAsset(AssetPathName);
  2477. break;
  2478. case EAssetViewType::Tile:
  2479. bHasWidgetForAsset = TileView->HasWidgetForAsset(AssetPathName);
  2480. break;
  2481. default:
  2482. bHasWidgetForAsset = false;
  2483. break;
  2484. }
  2485. if (bHasWidgetForAsset)
  2486. {
  2487. if (Texture2D)
  2488. {
  2489. Texture2D->bForceMiplevelsToBeResident = true;
  2490. }
  2491. else if (Material)
  2492. {
  2493. Material->SetForceMipLevelsToBeResident(true, true, -1.0f);
  2494. }
  2495. }
  2496. };
  2497. }
  2498. void SExtAssetView::OnObjectPropertyChanged(UObject* Object, FPropertyChangedEvent& PropertyChangedEvent)
  2499. {
  2500. if (Object != nullptr && Object->IsAsset())
  2501. {
  2502. RecentlyLoadedOrChangedAssets.Add(FAssetData(Object));
  2503. }
  2504. }
  2505. void SExtAssetView::OnClassHierarchyUpdated()
  2506. {
  2507. // The class hierarchy has changed in some way, so we need to refresh our backend list
  2508. RequestSlowFullListRefresh();
  2509. }
  2510. #endif
  2511. void SExtAssetView::OnAssetUpdated(const FExtAssetData& AssetData)
  2512. {
  2513. RecentlyLoadedOrChangedAssets.Add(AssetData);
  2514. }
  2515. void SExtAssetView::OnFrontendFiltersChanged()
  2516. {
  2517. RequestQuickFrontendListRefresh();
  2518. // If we're not operating on recursively filtered data, we need to ensure a full slow
  2519. // refresh is performed.
  2520. if ( ShouldFilterRecursively() && !bWereItemsRecursivelyFiltered )
  2521. {
  2522. RequestSlowFullListRefresh();
  2523. }
  2524. }
  2525. bool SExtAssetView::IsFrontendFilterActive() const
  2526. {
  2527. return ( FrontendFilters.IsValid() && FrontendFilters->Num() > 0 );
  2528. }
  2529. bool SExtAssetView::PassesCurrentFrontendFilter(const FExtAssetData& Item) const
  2530. {
  2531. // Check the frontend filters list
  2532. if ( FrontendFilters.IsValid() && !FrontendFilters->PassesAllFilters(Item) )
  2533. {
  2534. return false;
  2535. }
  2536. return true;
  2537. }
  2538. #if ECB_FEA_ASYNC_ASSET_DISCOVERY
  2539. bool SExtAssetView::PassesCurrentBackendFilter(const FExtAssetData& Item) const
  2540. {
  2541. TArray<FExtAssetData> AssetDataList;
  2542. AssetDataList.Add(Item);
  2543. RunAssetsThroughBackendFilter(AssetDataList);
  2544. return AssetDataList.Num() == 1;
  2545. }
  2546. void SExtAssetView::RunAssetsThroughBackendFilter(TArray<FExtAssetData>& InOutAssetDataList) const
  2547. {
  2548. const bool bRecurse = ShouldFilterRecursively();
  2549. const bool bUsingFolders = IsShowingFolders();
  2550. const bool bIsDynamicCollection = SourcesData.IsDynamicCollection();
  2551. FARFilter Filter = SourcesData.MakeFilter(bRecurse, bUsingFolders);
  2552. if ( SourcesData.HasCollections() && Filter.SoftObjectPaths.Num() == 0 && !bIsDynamicCollection )
  2553. {
  2554. // This is an empty collection, no asset will pass the check
  2555. InOutAssetDataList.Reset();
  2556. }
  2557. else
  2558. {
  2559. // Actually append the backend filter
  2560. Filter.Append(BackendFilter);
  2561. FExtContentBrowserSingleton::GetAssetRegistry().RunAssetsThroughFilter(InOutAssetDataList, Filter);
  2562. #if ECB_LEGACY
  2563. if ( SourcesData.HasCollections() && !bIsDynamicCollection )
  2564. {
  2565. // Include objects from child collections if we're recursing
  2566. const ECollectionRecursionFlags::Flags CollectionRecursionMode = (Filter.bRecursivePaths) ? ECollectionRecursionFlags::SelfAndChildren : ECollectionRecursionFlags::Self;
  2567. FCollectionManagerModule& CollectionManagerModule = FCollectionManagerModule::GetModule();
  2568. TArray< FName > CollectionObjectPaths;
  2569. for (const FCollectionNameType& Collection : SourcesData.Collections)
  2570. {
  2571. CollectionManagerModule.Get().GetObjectsInCollection(Collection.Name, Collection.Type, CollectionObjectPaths, CollectionRecursionMode);
  2572. }
  2573. for ( int32 AssetDataIdx = InOutAssetDataList.Num() - 1; AssetDataIdx >= 0; --AssetDataIdx )
  2574. {
  2575. const FAssetData& AssetData = InOutAssetDataList[AssetDataIdx];
  2576. if ( !CollectionObjectPaths.Contains( AssetData.ObjectPath ) )
  2577. {
  2578. InOutAssetDataList.RemoveAtSwap(AssetDataIdx);
  2579. }
  2580. }
  2581. }
  2582. #endif
  2583. }
  2584. }
  2585. #endif
  2586. void SExtAssetView::SortList(bool bSyncToSelection)
  2587. {
  2588. SortManager.SortList(FilteredAssetItems, MajorityAssetType, CustomColumns);
  2589. // Update the thumbnails we were using since the order has changed
  2590. bPendingUpdateThumbnails = true;
  2591. if (bSyncToSelection)
  2592. {
  2593. // Make sure the selection is in view
  2594. const bool bFocusOnSync = false;
  2595. SyncToSelection(bFocusOnSync);
  2596. }
  2597. RefreshList();
  2598. bPendingSortFilteredItems = false;
  2599. LastSortTime = CurrentTime;
  2600. }
  2601. FLinearColor SExtAssetView::GetThumbnailHintColorAndOpacity() const
  2602. {
  2603. //We update this color in tick instead of here as an optimization
  2604. return ThumbnailHintColorAndOpacity;
  2605. }
  2606. FSlateColor SExtAssetView::GetViewButtonForegroundColor() const
  2607. {
  2608. static const FName InvertedForegroundName("InvertedForeground");
  2609. static const FName DefaultForegroundName("DefaultForeground");
  2610. return ViewOptionsComboButton->IsHovered() ? FAppStyle::GetSlateColor(InvertedForegroundName) : FAppStyle::GetSlateColor(DefaultForegroundName);
  2611. }
  2612. TSharedRef<SWidget> SExtAssetView::GetViewButtonContent()
  2613. {
  2614. UExtContentBrowserSettings* ExtContentBrowserSetting = GetMutableDefault<UExtContentBrowserSettings>();
  2615. // Get all menu extenders for this context menu from the content browser module
  2616. FExtContentBrowserModule& ExtContentBrowserModule = FModuleManager::GetModuleChecked<FExtContentBrowserModule>( TEXT("ExtContentBrowser") );
  2617. TArray<FExtContentBrowserModule::FExtContentBrowserMenuExtender> MenuExtenderDelegates = ExtContentBrowserModule.GetAllAssetViewViewMenuExtenders();
  2618. TArray<TSharedPtr<FExtender>> Extenders;
  2619. for (int32 i = 0; i < MenuExtenderDelegates.Num(); ++i)
  2620. {
  2621. if (MenuExtenderDelegates[i].IsBound())
  2622. {
  2623. Extenders.Add(MenuExtenderDelegates[i].Execute());
  2624. }
  2625. }
  2626. TSharedPtr<FExtender> MenuExtender = FExtender::Combine(Extenders);
  2627. FMenuBuilder MenuBuilder(/*bInShouldCloseWindowAfterMenuSelection=*/true, NULL, MenuExtender, /*bCloseSelfOnly=*/ true);
  2628. MenuBuilder.BeginSection("AssetViewType", LOCTEXT("ViewTypeHeading", "View Type"));
  2629. {
  2630. MenuBuilder.AddMenuEntry(
  2631. LOCTEXT("TileViewOption", "Tiles"),
  2632. LOCTEXT("TileViewOptionToolTip", "View assets as tiles in a grid."),
  2633. FSlateIcon(),
  2634. FUIAction(
  2635. FExecuteAction::CreateSP( this, &SExtAssetView::SetCurrentViewTypeFromMenu, EAssetViewType::Tile ),
  2636. FCanExecuteAction(),
  2637. FIsActionChecked::CreateSP( this, &SExtAssetView::IsCurrentViewType, EAssetViewType::Tile )
  2638. ),
  2639. NAME_None,
  2640. EUserInterfaceActionType::RadioButton
  2641. );
  2642. MenuBuilder.AddMenuEntry(
  2643. LOCTEXT("ListViewOption", "List"),
  2644. LOCTEXT("ListViewOptionToolTip", "View assets in a list with thumbnails."),
  2645. FSlateIcon(),
  2646. FUIAction(
  2647. FExecuteAction::CreateSP( this, &SExtAssetView::SetCurrentViewTypeFromMenu, EAssetViewType::List ),
  2648. FCanExecuteAction(),
  2649. FIsActionChecked::CreateSP( this, &SExtAssetView::IsCurrentViewType, EAssetViewType::List )
  2650. ),
  2651. NAME_None,
  2652. EUserInterfaceActionType::RadioButton
  2653. );
  2654. MenuBuilder.AddMenuEntry(
  2655. LOCTEXT("ColumnViewOption", "Columns"),
  2656. LOCTEXT("ColumnViewOptionToolTip", "View assets in a list with columns of details."),
  2657. FSlateIcon(),
  2658. FUIAction(
  2659. FExecuteAction::CreateSP( this, &SExtAssetView::SetCurrentViewTypeFromMenu, EAssetViewType::Column ),
  2660. FCanExecuteAction(),
  2661. FIsActionChecked::CreateSP( this, &SExtAssetView::IsCurrentViewType, EAssetViewType::Column )
  2662. ),
  2663. NAME_None,
  2664. EUserInterfaceActionType::RadioButton
  2665. );
  2666. }
  2667. MenuBuilder.EndSection();
  2668. if (GetColumnViewVisibility() == EVisibility::Visible)
  2669. {
  2670. MenuBuilder.BeginSection("AssetColumns", LOCTEXT("ToggleColumnsHeading", "Columns"));
  2671. {
  2672. MenuBuilder.AddMenuEntry(
  2673. LOCTEXT("ShowAssetTypeColumns", "Show Asset Type Columns"),
  2674. LOCTEXT("ShowAssetTypeColumnsTooltip", "Show or hide major asset type columns."),
  2675. FSlateIcon(),
  2676. FUIAction(
  2677. FExecuteAction::CreateSP(this, &SExtAssetView::ToggleMajorAssetTypeColumns),
  2678. FCanExecuteAction(),
  2679. FIsActionChecked::CreateSP(this, &SExtAssetView::IsShowingMajorAssetTypeColumns)
  2680. ),
  2681. NAME_None,
  2682. EUserInterfaceActionType::ToggleButton
  2683. );
  2684. MenuBuilder.AddSubMenu(
  2685. LOCTEXT("ToggleColumnsMenu", "Toggle Columns"),
  2686. LOCTEXT("ToggleColumnsMenuTooltip", "Show or hide specific columns."),
  2687. FNewMenuDelegate::CreateSP(this, &SExtAssetView::FillToggleColumnsMenu),
  2688. false,
  2689. FSlateIcon(),
  2690. false
  2691. );
  2692. MenuBuilder.AddMenuEntry(
  2693. LOCTEXT("ResetColumns", "Reset Columns"),
  2694. LOCTEXT("ResetColumnsToolTip", "Reset all columns to be visible again."),
  2695. FSlateIcon(),
  2696. FUIAction(FExecuteAction::CreateSP(this, &SExtAssetView::ResetColumns)),
  2697. NAME_None,
  2698. EUserInterfaceActionType::Button
  2699. );
  2700. #if ECB_WIP_MORE_VIEWTYPE
  2701. MenuBuilder.AddMenuEntry(
  2702. LOCTEXT("ExportColumns", "Export to CSV"),
  2703. LOCTEXT("ExportColumnsToolTip", "Export column data to CSV."),
  2704. FSlateIcon(),
  2705. FUIAction(FExecuteAction::CreateSP(this, &SExtAssetView::ExportColumns)),
  2706. NAME_None,
  2707. EUserInterfaceActionType::Button
  2708. );
  2709. #endif
  2710. }
  2711. MenuBuilder.EndSection();
  2712. }
  2713. MenuBuilder.BeginSection("View", LOCTEXT("ViewHeading", "View"));
  2714. {
  2715. #if ECB_FEA_ENGINE_VERSION_OVERLAY
  2716. MenuBuilder.AddMenuEntry(
  2717. LOCTEXT("ShowEngineVersionOverlayOption", "Show Engine Version Overlay"),
  2718. LOCTEXT("ShowEngineVersionOverlayToolTip", "Show saved engine version on asset thumbnail?"),
  2719. FSlateIcon(),
  2720. FUIAction(
  2721. FExecuteAction::CreateSP(this, &SExtAssetView::ToggleShowEngineVersionOverlayButton),
  2722. FCanExecuteAction(),
  2723. FIsActionChecked::CreateSP(this, &SExtAssetView::IsShowingEngineVersionOverlayButton)
  2724. ),
  2725. NAME_None,
  2726. EUserInterfaceActionType::ToggleButton
  2727. );
  2728. #endif
  2729. #if ECB_FEA_VALIDATE_OVERLAY
  2730. MenuBuilder.AddMenuEntry(
  2731. LOCTEXT("ShowValidationOverlayOption", "Show Validation Status Overlay"),
  2732. LOCTEXT("ShowValidationOverlayToolTip", "Show if an uasset file's validation status as overlay on asset thumbnail?"),
  2733. FSlateIcon(),
  2734. FUIAction(
  2735. FExecuteAction::CreateSP(this, &SExtAssetView::ToggleShowValidationStatusOverlayButton),
  2736. FCanExecuteAction(),
  2737. FIsActionChecked::CreateSP(this, &SExtAssetView::IsShowingValidationStatusOverlayButton)
  2738. ),
  2739. NAME_None,
  2740. EUserInterfaceActionType::ToggleButton
  2741. );
  2742. #endif
  2743. #if ECB_WIP_CONTENT_TYPE_OVERLAY
  2744. MenuBuilder.AddMenuEntry(
  2745. LOCTEXT("ShowContentTypeOverlayOption", "Show Content Type Overlay"),
  2746. LOCTEXT("ShowContentTypeOverlayToolTip", "Show project/plugin/orphan content type as overlay"),
  2747. FSlateIcon(),
  2748. FUIAction(
  2749. FExecuteAction::CreateSP(this, &SExtAssetView::ToggleShowContentTypeOverlayButton),
  2750. FCanExecuteAction(),
  2751. FIsActionChecked::CreateSP(this, &SExtAssetView::IsShowingContentTypeOverlayButton)
  2752. ),
  2753. NAME_None,
  2754. EUserInterfaceActionType::ToggleButton
  2755. );
  2756. #endif
  2757. #if ECB_FEA_SHOW_INVALID
  2758. MenuBuilder.AddMenuEntry(
  2759. LOCTEXT("ShowInvalidAssets", "Show Invalid Assets"),
  2760. LOCTEXT("ShowInvalidAssetsToolTip", "Display invalid assets in the asset view?"),
  2761. FSlateIcon(),
  2762. FUIAction(
  2763. FExecuteAction::CreateSP(this, &SExtAssetView::ToggleShowInvalidAssets),
  2764. FCanExecuteAction(),
  2765. FIsActionChecked::CreateSP(this, &SExtAssetView::IsShowingInvalidAssets)
  2766. ),
  2767. NAME_None,
  2768. EUserInterfaceActionType::ToggleButton
  2769. );
  2770. #endif
  2771. #if ECB_WIP_TOGGLE_TOOLBAR_BUTTON
  2772. MenuBuilder.AddMenuEntry(
  2773. LOCTEXT("ShowToolbarButtonTooltipOption", "Show UAsset Toolbar Button"),
  2774. LOCTEXT("ShowToolbarButtonOptionToolTip", "Show Open UAsset Browser button in level editor toolbar?"),
  2775. FSlateIcon(),
  2776. FUIAction(
  2777. FExecuteAction::CreateSP(this, &SExtAssetView::ToggleShowToolbarButton),
  2778. FCanExecuteAction(),
  2779. FIsActionChecked::CreateSP(this, &SExtAssetView::IsShowingToolbarButton)
  2780. ),
  2781. NAME_None,
  2782. EUserInterfaceActionType::ToggleButton
  2783. );
  2784. #endif
  2785. auto CreateShowFoldersSubMenu = [this](FMenuBuilder& SubMenuBuilder)
  2786. {
  2787. SubMenuBuilder.AddMenuEntry(
  2788. LOCTEXT("ShowEmptyFoldersOption", "Show Empty Folders"),
  2789. LOCTEXT("ShowEmptyFoldersOptionToolTip", "Show empty folders in the view as well as assets?"),
  2790. FSlateIcon(),
  2791. FUIAction(
  2792. FExecuteAction::CreateSP( this, &SExtAssetView::ToggleShowEmptyFolders ),
  2793. FCanExecuteAction::CreateSP( this, &SExtAssetView::IsToggleShowEmptyFoldersAllowed ),
  2794. FIsActionChecked::CreateSP( this, &SExtAssetView::IsShowingEmptyFolders )
  2795. ),
  2796. NAME_None,
  2797. EUserInterfaceActionType::ToggleButton
  2798. );
  2799. };
  2800. MenuBuilder.AddSubMenu(
  2801. LOCTEXT("ShowFoldersOption", "Show Folders"),
  2802. LOCTEXT("ShowFoldersOptionToolTip", "Show folders in the view as well as assets?"),
  2803. FNewMenuDelegate::CreateLambda(CreateShowFoldersSubMenu),
  2804. FUIAction(
  2805. FExecuteAction::CreateSP( this, &SExtAssetView::ToggleShowFolders ),
  2806. FCanExecuteAction::CreateSP( this, &SExtAssetView::IsToggleShowFoldersAllowed ),
  2807. FIsActionChecked::CreateSP( this, &SExtAssetView::IsShowingFolders )
  2808. ),
  2809. NAME_None,
  2810. EUserInterfaceActionType::ToggleButton
  2811. );
  2812. #if ECB_FEA_IGNORE_FOLDERS
  2813. MenuBuilder.AddMenuEntry(
  2814. LOCTEXT("IgnoreFoldersStartWithDot", "Ignore Folders Start With Dot"),
  2815. LOCTEXT("IgnoreFoldersStartWithDotTooltip", "All Folders Start with Dot will be ignored in folder scan process"),
  2816. FSlateIcon(),
  2817. FUIAction(
  2818. FExecuteAction::CreateLambda([this, ExtContentBrowserSetting] { ExtContentBrowserSetting->bIgnoreFoldersStartWithDot = !ExtContentBrowserSetting->bIgnoreFoldersStartWithDot; ExtContentBrowserSetting->PostEditChange(); }),
  2819. FCanExecuteAction(),
  2820. FIsActionChecked::CreateLambda([this, ExtContentBrowserSetting] { return ExtContentBrowserSetting->bIgnoreFoldersStartWithDot; })
  2821. ),
  2822. NAME_None,
  2823. EUserInterfaceActionType::ToggleButton
  2824. );
  2825. MenuBuilder.AddMenuEntry(
  2826. LOCTEXT("IgnoreCommonNonContentFolders", "Ignore Common Non-Content Folders"),
  2827. LOCTEXT("IgnoreCommonNonContentFoldersTooltip", "Common Non-Content Folders (Binaries, Config,DerivedDataCache, Intermediate, Resources, Saved, Source) will be ignored."),
  2828. FSlateIcon(),
  2829. FUIAction(
  2830. FExecuteAction::CreateLambda([this, ExtContentBrowserSetting] { ExtContentBrowserSetting->bIgnoreCommonNonContentFolders = !ExtContentBrowserSetting->bIgnoreCommonNonContentFolders; ExtContentBrowserSetting->PostEditChange(); }),
  2831. FCanExecuteAction(),
  2832. FIsActionChecked::CreateLambda([this, ExtContentBrowserSetting] { return ExtContentBrowserSetting->bIgnoreCommonNonContentFolders; })
  2833. ),
  2834. NAME_None,
  2835. EUserInterfaceActionType::ToggleButton
  2836. );
  2837. MenuBuilder.AddMenuEntry(
  2838. LOCTEXT("IgnoreExternalContentFolders", "Ignore External Package Content Folders"),
  2839. LOCTEXT("IgnoreExternalContentFoldersTooltip", "Common External Package Folders (__ExternalActors__, __ExternalObjects__) will be ignored."),
  2840. FSlateIcon(),
  2841. FUIAction(
  2842. FExecuteAction::CreateLambda([this, ExtContentBrowserSetting] { ExtContentBrowserSetting->bIgnoreExternalContentFolders = !ExtContentBrowserSetting->bIgnoreExternalContentFolders; ExtContentBrowserSetting->PostEditChange(); }),
  2843. FCanExecuteAction(),
  2844. FIsActionChecked::CreateLambda([this, ExtContentBrowserSetting] { return ExtContentBrowserSetting->bIgnoreExternalContentFolders; })
  2845. ),
  2846. NAME_None,
  2847. EUserInterfaceActionType::ToggleButton
  2848. );
  2849. MenuBuilder.AddMenuEntry(
  2850. LOCTEXT("MoreIgnoreFolders", "More Ignore Folders"),
  2851. LOCTEXT("MoreIgnoreFoldersTooltip", "Add more ignore folders..."),
  2852. FSlateIcon(),
  2853. FUIAction(
  2854. FExecuteAction::CreateLambda([this, ExtContentBrowserSetting] { ExtContentBrowserSetting->bIgnoreMoreFolders = !ExtContentBrowserSetting->bIgnoreMoreFolders; ExtContentBrowserSetting->PostEditChange(); }),
  2855. FCanExecuteAction(),
  2856. FIsActionChecked::CreateLambda([this, ExtContentBrowserSetting] { return ExtContentBrowserSetting->bIgnoreMoreFolders; })
  2857. ),
  2858. NAME_None,
  2859. EUserInterfaceActionType::ToggleButton
  2860. );
  2861. TSharedRef<SWidget> IgnoreFoldersWidget = SNew(SEditableTextBox)
  2862. .Text_Lambda([this, ExtContentBrowserSetting]()
  2863. {
  2864. FString IgnoreFolders;
  2865. for (int32 Index = 0; Index < ExtContentBrowserSetting->IgnoreFolders.Num(); ++Index)
  2866. {
  2867. if (Index != 0)
  2868. {
  2869. IgnoreFolders.Append(TEXT(","));
  2870. }
  2871. IgnoreFolders += ExtContentBrowserSetting->IgnoreFolders[Index];
  2872. }
  2873. return FText::FromString(IgnoreFolders);
  2874. })
  2875. .IsEnabled_Lambda([this, ExtContentBrowserSetting]()
  2876. {
  2877. return ExtContentBrowserSetting->bIgnoreMoreFolders;
  2878. })
  2879. //.OnTextChanged_Lambda([this](const FText& InText) {})
  2880. .OnTextCommitted_Lambda([this, ExtContentBrowserSetting](const FText& InText, ETextCommit::Type)
  2881. {
  2882. FString InputText = InText.ToString().TrimStartAndEnd();
  2883. if (!InputText.IsEmpty())
  2884. {
  2885. TArray<FString> Candidates;
  2886. InText.ToString().ParseIntoArray(Candidates, TEXT(","));
  2887. for (const FString& Candidate : Candidates)
  2888. {
  2889. FString Trimmed = Candidate.TrimStartAndEnd();
  2890. if (!Trimmed.IsEmpty())
  2891. {
  2892. ExtContentBrowserSetting->IgnoreFolders.AddUnique(Trimmed);
  2893. }
  2894. }
  2895. }
  2896. else
  2897. {
  2898. ExtContentBrowserSetting->IgnoreFolders.Empty();
  2899. }
  2900. ExtContentBrowserSetting->PostEditChange();
  2901. });
  2902. MenuBuilder.AddWidget(IgnoreFoldersWidget, FText::GetEmpty());
  2903. #endif
  2904. MenuBuilder.AddMenuEntry(
  2905. LOCTEXT("ShowAssetTooltipOption", "Show Tooltip"),
  2906. LOCTEXT("ShowAssetTooltipOptionToolTip", "Show the asset tooltip?"),
  2907. FSlateIcon(),
  2908. FUIAction(
  2909. FExecuteAction::CreateSP(this, &SExtAssetView::ToggleShowAssetTooltip),
  2910. FCanExecuteAction(),
  2911. FIsActionChecked::CreateSP(this, &SExtAssetView::IsShowingAssetTooltip)
  2912. ),
  2913. NAME_None,
  2914. EUserInterfaceActionType::ToggleButton
  2915. );
  2916. #if ECB_WIP_COLLECTION
  2917. MenuBuilder.AddMenuEntry(
  2918. LOCTEXT("ShowCollectionOption", "Show Collections"),
  2919. LOCTEXT("ShowCollectionOptionToolTip", "Show the collections list in the view?"),
  2920. FSlateIcon(),
  2921. FUIAction(
  2922. FExecuteAction::CreateSP( this, &SExtAssetView::ToggleShowCollections ),
  2923. FCanExecuteAction::CreateSP( this, &SExtAssetView::IsToggleShowCollectionsAllowed ),
  2924. FIsActionChecked::CreateSP( this, &SExtAssetView::IsShowingCollections )
  2925. ),
  2926. NAME_None,
  2927. EUserInterfaceActionType::ToggleButton
  2928. );
  2929. #endif
  2930. #if ECB_WIP_FAVORITE
  2931. MenuBuilder.AddMenuEntry(
  2932. LOCTEXT("ShowFavoriteOptions", "Show Favorites"),
  2933. LOCTEXT("ShowFavoriteOptionToolTip", "Show the favorite folders in the view?"),
  2934. FSlateIcon(),
  2935. FUIAction(
  2936. FExecuteAction::CreateSP(this, &SExtAssetView::ToggleShowFavorites),
  2937. FCanExecuteAction::CreateSP(this, &SExtAssetView::IsToggleShowFavoritesAllowed),
  2938. FIsActionChecked::CreateSP(this, &SExtAssetView::IsShowingFavorites)
  2939. ),
  2940. NAME_None,
  2941. EUserInterfaceActionType::ToggleButton
  2942. );
  2943. #endif
  2944. MenuBuilder.AddMenuEntry(
  2945. LOCTEXT("Reset", "Reset"),
  2946. LOCTEXT("ResetOptionsTooltip", "Reset view options to default"),
  2947. FSlateIcon(),
  2948. FUIAction(
  2949. FExecuteAction::CreateLambda([this, ExtContentBrowserSetting] { ExtContentBrowserSetting->ResetViewSettings(); ExtContentBrowserSetting->PostEditChange(); })
  2950. //FCanExecuteAction(),
  2951. //FIsActionChecked::CreateLambda([this] { return false; })
  2952. ),
  2953. NAME_None,
  2954. EUserInterfaceActionType::Button
  2955. );
  2956. }
  2957. MenuBuilder.EndSection(); // Section: View
  2958. #if ECB_DEBUG
  2959. MenuBuilder.BeginSection("Debug", LOCTEXT("DebugHeading", "Debug"));
  2960. {
  2961. MenuBuilder.AddWidget(
  2962. SNew(SGridPanel)
  2963. + SGridPanel::Slot(0, 0).Padding(3, 0, 0, 0)
  2964. [WidgetHelpers::CreateColorWidget(&FExtContentBrowserStyle::CustomContentBrowserBorderBackgroundColor)]
  2965. + SGridPanel::Slot(1, 0).Padding(3, 0, 0, 0)
  2966. [WidgetHelpers::CreateColorWidget(&FExtContentBrowserStyle::CustomToolbarBackgroundColor)]
  2967. + SGridPanel::Slot(2, 0).Padding(3, 0, 0, 0)
  2968. [WidgetHelpers::CreateColorWidget(&FExtContentBrowserStyle::CustomSourceViewBackgroundColor)]
  2969. + SGridPanel::Slot(3, 0).Padding(3, 0, 0, 0)
  2970. [WidgetHelpers::CreateColorWidget(&FExtContentBrowserStyle::CustomAssetViewBackgroundColor)]
  2971. , LOCTEXT("Color", "Color")
  2972. ,/*bNoIndent=*/true
  2973. );
  2974. }
  2975. MenuBuilder.EndSection();
  2976. #endif
  2977. #if ECB_TODO
  2978. MenuBuilder.BeginSection("Content", LOCTEXT("ContentHeading", "Content"));
  2979. {
  2980. MenuBuilder.AddMenuEntry(
  2981. LOCTEXT("ShowEngineFolderOption", "Show Engine Content"),
  2982. LOCTEXT("ShowEngineFolderOptionToolTip", "Show engine content in the view?"),
  2983. FSlateIcon(),
  2984. FUIAction(
  2985. FExecuteAction::CreateSP( this, &SExtAssetView::ToggleShowEngineContent ),
  2986. FCanExecuteAction(),
  2987. FIsActionChecked::CreateSP( this, &SExtAssetView::IsShowingEngineContent )
  2988. ),
  2989. NAME_None,
  2990. EUserInterfaceActionType::ToggleButton
  2991. );
  2992. }
  2993. MenuBuilder.EndSection();
  2994. #endif
  2995. #if ECB_WIP_SEARCH_RECURSE_TOGGLE
  2996. MenuBuilder.BeginSection("Search", LOCTEXT("SearchHeading", "Search"));
  2997. {
  2998. MenuBuilder.AddMenuEntry(
  2999. LOCTEXT("SearchFilterRecursivelyOption", "Search and Filter Recursively"),
  3000. LOCTEXT("SearchFilterRecursivelyOptionTooltip", "Search and filter recursively or only in current folder?"),
  3001. FSlateIcon(),
  3002. FUIAction(
  3003. FExecuteAction::CreateSP(this, &SExtAssetView::ToggleSearchAndFilterRecursively),
  3004. FCanExecuteAction(),
  3005. FIsActionChecked::CreateSP(this, &SExtAssetView::IsSearchAndFilterRecursively)
  3006. ),
  3007. NAME_None,
  3008. EUserInterfaceActionType::ToggleButton
  3009. );
  3010. #if ECB_LEGACY
  3011. MenuBuilder.AddMenuEntry(
  3012. LOCTEXT("IncludeClassNameOption", "Search Asset Class Names"),
  3013. LOCTEXT("IncludeClassesNameOptionTooltip", "Include asset type names in search criteria? (e.g. Blueprint, Texture, Sound)"),
  3014. FSlateIcon(),
  3015. FUIAction(
  3016. FExecuteAction::CreateSP(this, &SExtAssetView::ToggleIncludeClassNames),
  3017. FCanExecuteAction::CreateSP(this, &SExtAssetView::IsToggleIncludeClassNamesAllowed),
  3018. FIsActionChecked::CreateSP(this, &SExtAssetView::IsIncludingClassNames)
  3019. ),
  3020. NAME_None,
  3021. EUserInterfaceActionType::ToggleButton
  3022. );
  3023. MenuBuilder.AddMenuEntry(
  3024. LOCTEXT("IncludeAssetPathOption", "Search Asset Path"),
  3025. LOCTEXT("IncludeAssetPathOptionTooltip", "Include entire asset path in search criteria?"),
  3026. FSlateIcon(),
  3027. FUIAction(
  3028. FExecuteAction::CreateSP(this, &SExtAssetView::ToggleIncludeAssetPaths),
  3029. FCanExecuteAction::CreateSP(this, &SExtAssetView::IsToggleIncludeAssetPathsAllowed),
  3030. FIsActionChecked::CreateSP(this, &SExtAssetView::IsIncludingAssetPaths)
  3031. ),
  3032. NAME_None,
  3033. EUserInterfaceActionType::ToggleButton
  3034. );
  3035. MenuBuilder.AddMenuEntry(
  3036. LOCTEXT("IncludeCollectionNameOption", "Search Collection Names"),
  3037. LOCTEXT("IncludeCollectionNameOptionTooltip", "Include Collection names in search criteria?"),
  3038. FSlateIcon(),
  3039. FUIAction(
  3040. FExecuteAction::CreateSP(this, &SExtAssetView::ToggleIncludeCollectionNames),
  3041. FCanExecuteAction::CreateSP(this, &SExtAssetView::IsToggleIncludeCollectionNamesAllowed),
  3042. FIsActionChecked::CreateSP(this, &SExtAssetView::IsIncludingCollectionNames)
  3043. ),
  3044. NAME_None,
  3045. EUserInterfaceActionType::ToggleButton
  3046. );
  3047. #endif
  3048. }
  3049. MenuBuilder.EndSection();
  3050. #endif
  3051. #if ECB_LEGACY // Move outside
  3052. MenuBuilder.BeginSection("AssetThumbnails", LOCTEXT("ThumbnailsHeading", "Thumbnails"));
  3053. {
  3054. MenuBuilder.AddWidget(
  3055. SNew(SSlider)
  3056. .ToolTipText( LOCTEXT("ThumbnailScaleToolTip", "Adjust the size of thumbnails.") )
  3057. .Value( this, &SExtAssetView::GetThumbnailScale )
  3058. .OnValueChanged( this, &SExtAssetView::SetThumbnailScale )
  3059. .Locked( this, &SExtAssetView::IsThumbnailScalingLocked ),
  3060. LOCTEXT("ThumbnailScaleLabel", "Scale"),
  3061. /*bNoIndent=*/true
  3062. );
  3063. }
  3064. MenuBuilder.EndSection();
  3065. #endif
  3066. const auto PluginDescriptor = IPluginManager::Get().FindPlugin(TEXT("UAssetBrowser"))->GetDescriptor();
  3067. const FText VersionName = FText::FromString(PluginDescriptor.VersionName);
  3068. const FText PluginVersion = FText::Format(LOCTEXT("UAssetBrowserVersion", "UAsset Browser {0}"), VersionName);
  3069. MenuBuilder.BeginSection("About", LOCTEXT("AboutHeading", "About"));
  3070. {
  3071. MenuBuilder.AddMenuEntry(
  3072. LOCTEXT("Documentation...", "Documentation..."),
  3073. LOCTEXT("DocumentationToolTip", "Show documentation in a browser"),
  3074. FSlateIcon(FExtContentBrowserStyle::GetStyleSetName(), "UAssetBrowser.Help"),
  3075. FUIAction(
  3076. FExecuteAction::CreateSP(this, &SExtAssetView::ShowDocumentation)
  3077. ),
  3078. NAME_None,
  3079. EUserInterfaceActionType::Button
  3080. );
  3081. MenuBuilder.AddMenuEntry(
  3082. PluginVersion,
  3083. LOCTEXT("ShowChangeLogToolTip", "Show change log"),
  3084. FSlateIcon(FExtContentBrowserStyle::GetStyleSetName(), "UAssetBrowser.Icon16x"),
  3085. FUIAction(
  3086. FExecuteAction::CreateSP(this, &SExtAssetView::ShowPluginVersionChangeLog)
  3087. ),
  3088. NAME_None,
  3089. EUserInterfaceActionType::Button
  3090. );
  3091. }
  3092. MenuBuilder.EndSection();
  3093. return MenuBuilder.MakeWidget();
  3094. }
  3095. void SExtAssetView::ToggleShowFolders()
  3096. {
  3097. check( IsToggleShowFoldersAllowed() );
  3098. GetMutableDefault<UExtContentBrowserSettings>()->DisplayFolders = !GetDefault<UExtContentBrowserSettings>()->DisplayFolders;
  3099. GetMutableDefault<UExtContentBrowserSettings>()->PostEditChange();
  3100. }
  3101. bool SExtAssetView::IsToggleShowFoldersAllowed() const
  3102. {
  3103. return bCanShowFolders;
  3104. }
  3105. bool SExtAssetView::IsShowingFolders() const
  3106. {
  3107. return IsToggleShowFoldersAllowed() && GetDefault<UExtContentBrowserSettings>()->DisplayFolders;
  3108. }
  3109. void SExtAssetView::ToggleShowEmptyFolders()
  3110. {
  3111. check( IsToggleShowEmptyFoldersAllowed() );
  3112. GetMutableDefault<UExtContentBrowserSettings>()->DisplayEmptyFolders = !GetDefault<UExtContentBrowserSettings>()->DisplayEmptyFolders;
  3113. GetMutableDefault<UExtContentBrowserSettings>()->PostEditChange();
  3114. }
  3115. bool SExtAssetView::IsToggleShowEmptyFoldersAllowed() const
  3116. {
  3117. return bCanShowFolders;
  3118. }
  3119. bool SExtAssetView::IsShowingEmptyFolders() const
  3120. {
  3121. return IsToggleShowEmptyFoldersAllowed() && GetDefault<UExtContentBrowserSettings>()->DisplayEmptyFolders;
  3122. }
  3123. void SExtAssetView::ToggleShowAssetTooltip()
  3124. {
  3125. GetMutableDefault<UExtContentBrowserSettings>()->DisplayAssetTooltip = !GetDefault<UExtContentBrowserSettings>()->DisplayAssetTooltip;
  3126. }
  3127. bool SExtAssetView::IsShowingAssetTooltip() const
  3128. {
  3129. return GetDefault<UExtContentBrowserSettings>()->DisplayAssetTooltip;
  3130. }
  3131. void SExtAssetView::ShowDocumentation()
  3132. {
  3133. FString Link(TEXT("https://marynate.github.io/uasset-browser/"));
  3134. FPlatformProcess::LaunchURL(*Link, nullptr, nullptr);
  3135. }
  3136. void SExtAssetView::ShowPluginVersionChangeLog()
  3137. {
  3138. OnRequestShowChangeLog.ExecuteIfBound();
  3139. }
  3140. void SExtAssetView::ToggleShowEngineVersionOverlayButton()
  3141. {
  3142. GetMutableDefault<UExtContentBrowserSettings>()->DisplayEngineVersionOverlay = !GetDefault<UExtContentBrowserSettings>()->DisplayEngineVersionOverlay;
  3143. GetMutableDefault<UExtContentBrowserSettings>()->PostEditChange();
  3144. }
  3145. bool SExtAssetView::IsShowingEngineVersionOverlayButton() const
  3146. {
  3147. return GetDefault<UExtContentBrowserSettings>()->DisplayEngineVersionOverlay;
  3148. }
  3149. void SExtAssetView::ToggleShowContentTypeOverlayButton()
  3150. {
  3151. GetMutableDefault<UExtContentBrowserSettings>()->DisplayContentTypeOverlay = !GetDefault<UExtContentBrowserSettings>()->DisplayContentTypeOverlay;
  3152. GetMutableDefault<UExtContentBrowserSettings>()->PostEditChange();
  3153. }
  3154. bool SExtAssetView::IsShowingContentTypeOverlayButton() const
  3155. {
  3156. return GetDefault<UExtContentBrowserSettings>()->DisplayContentTypeOverlay;
  3157. }
  3158. void SExtAssetView::ToggleShowValidationStatusOverlayButton()
  3159. {
  3160. GetMutableDefault<UExtContentBrowserSettings>()->DisplayValidationStatusOverlay = !GetDefault<UExtContentBrowserSettings>()->DisplayValidationStatusOverlay;
  3161. GetMutableDefault<UExtContentBrowserSettings>()->PostEditChange();
  3162. }
  3163. bool SExtAssetView::IsShowingValidationStatusOverlayButton() const
  3164. {
  3165. return GetDefault<UExtContentBrowserSettings>()->DisplayValidationStatusOverlay;
  3166. }
  3167. void SExtAssetView::ToggleShowInvalidAssets()
  3168. {
  3169. GetMutableDefault<UExtContentBrowserSettings>()->DisplayInvalidAssets = !GetDefault<UExtContentBrowserSettings>()->DisplayInvalidAssets;
  3170. GetMutableDefault<UExtContentBrowserSettings>()->PostEditChange();
  3171. }
  3172. bool SExtAssetView::IsShowingInvalidAssets() const
  3173. {
  3174. return GetDefault<UExtContentBrowserSettings>()->DisplayInvalidAssets;
  3175. }
  3176. void SExtAssetView::ToggleShowToolbarButton()
  3177. {
  3178. FExtContentBrowserSingleton::Get().ToggleShowToolbarButton();
  3179. }
  3180. bool SExtAssetView::IsShowingToolbarButton() const
  3181. {
  3182. return GetDefault<UExtContentBrowserSettings>()->DisplayToolbarButton;
  3183. }
  3184. #if ECB_LEGACY
  3185. void SExtAssetView::ToggleShowEngineContent()
  3186. {
  3187. bool bDisplayEngine = GetDefault<UExtContentBrowserSettings>()->GetDisplayEngineFolder();
  3188. bool bRawDisplayEngine = GetDefault<UExtContentBrowserSettings>()->GetDisplayEngineFolder( true );
  3189. // Only if both these flags are false when toggling we want to enable the flag, otherwise we're toggling off
  3190. if ( !bDisplayEngine && !bRawDisplayEngine )
  3191. {
  3192. GetMutableDefault<UExtContentBrowserSettings>()->SetDisplayEngineFolder( true );
  3193. }
  3194. else
  3195. {
  3196. GetMutableDefault<UExtContentBrowserSettings>()->SetDisplayEngineFolder( false );
  3197. GetMutableDefault<UExtContentBrowserSettings>()->SetDisplayEngineFolder( false, true );
  3198. }
  3199. GetMutableDefault<UExtContentBrowserSettings>()->PostEditChange();
  3200. }
  3201. bool SExtAssetView::IsShowingEngineContent() const
  3202. {
  3203. return GetDefault<UExtContentBrowserSettings>()->GetDisplayEngineFolder();
  3204. }
  3205. #endif
  3206. void SExtAssetView::ToggleShowCollections()
  3207. {
  3208. const bool bDisplayCollections = GetDefault<UExtContentBrowserSettings>()->GetDisplayCollections();
  3209. GetMutableDefault<UExtContentBrowserSettings>()->SetDisplayCollections( !bDisplayCollections );
  3210. GetMutableDefault<UExtContentBrowserSettings>()->PostEditChange();
  3211. }
  3212. bool SExtAssetView::IsToggleShowCollectionsAllowed() const
  3213. {
  3214. return bCanShowCollections;
  3215. }
  3216. bool SExtAssetView::IsShowingCollections() const
  3217. {
  3218. return IsToggleShowCollectionsAllowed() && GetDefault<UExtContentBrowserSettings>()->GetDisplayCollections();
  3219. }
  3220. void SExtAssetView::ToggleShowFavorites()
  3221. {
  3222. const bool bShowingFavorites = GetDefault<UExtContentBrowserSettings>()->GetDisplayFavorites();
  3223. GetMutableDefault<UExtContentBrowserSettings>()->SetDisplayFavorites(!bShowingFavorites);
  3224. GetMutableDefault<UExtContentBrowserSettings>()->PostEditChange();
  3225. }
  3226. bool SExtAssetView::IsToggleShowFavoritesAllowed() const
  3227. {
  3228. return bCanShowFavorites;
  3229. }
  3230. bool SExtAssetView::IsShowingFavorites() const
  3231. {
  3232. return IsToggleShowFavoritesAllowed() && GetDefault<UExtContentBrowserSettings>()->GetDisplayFavorites();
  3233. }
  3234. void SExtAssetView::ToggleSearchAndFilterRecursively()
  3235. {
  3236. GetMutableDefault<UExtContentBrowserSettings>()->SearchAndFilterRecursively = !GetDefault<UExtContentBrowserSettings>()->SearchAndFilterRecursively;
  3237. GetMutableDefault<UExtContentBrowserSettings>()->PostEditChange();
  3238. }
  3239. bool SExtAssetView::IsSearchAndFilterRecursively() const
  3240. {
  3241. #if ECB_WIP_SEARCH_RECURSE_TOGGLE
  3242. return GetDefault<UExtContentBrowserSettings>()->SearchAndFilterRecursively;
  3243. #else
  3244. return true;
  3245. #endif
  3246. }
  3247. #if ECB_LEGACY
  3248. void SExtAssetView::ToggleIncludeClassNames()
  3249. {
  3250. const bool bIncludeClassNames = GetDefault<UExtContentBrowserSettings>()->GetIncludeClassNames();
  3251. GetMutableDefault<UExtContentBrowserSettings>()->SetIncludeClassNames(!bIncludeClassNames);
  3252. GetMutableDefault<UExtContentBrowserSettings>()->PostEditChange();
  3253. OnSearchOptionsChanged.ExecuteIfBound();
  3254. }
  3255. bool SExtAssetView::IsToggleIncludeClassNamesAllowed() const
  3256. {
  3257. return true;
  3258. }
  3259. bool SExtAssetView::IsIncludingClassNames() const
  3260. {
  3261. return IsToggleIncludeClassNamesAllowed() && GetDefault<UExtContentBrowserSettings>()->GetIncludeClassNames();
  3262. }
  3263. void SExtAssetView::ToggleIncludeAssetPaths()
  3264. {
  3265. const bool bIncludeAssetPaths = GetDefault<UExtContentBrowserSettings>()->GetIncludeAssetPaths();
  3266. GetMutableDefault<UExtContentBrowserSettings>()->SetIncludeAssetPaths(!bIncludeAssetPaths);
  3267. GetMutableDefault<UExtContentBrowserSettings>()->PostEditChange();
  3268. OnSearchOptionsChanged.ExecuteIfBound();
  3269. }
  3270. bool SExtAssetView::IsToggleIncludeAssetPathsAllowed() const
  3271. {
  3272. return true;
  3273. }
  3274. bool SExtAssetView::IsIncludingAssetPaths() const
  3275. {
  3276. return IsToggleIncludeAssetPathsAllowed() && GetDefault<UExtContentBrowserSettings>()->GetIncludeAssetPaths();
  3277. }
  3278. void SExtAssetView::ToggleIncludeCollectionNames()
  3279. {
  3280. const bool bIncludeCollectionNames = GetDefault<UExtContentBrowserSettings>()->GetIncludeCollectionNames();
  3281. GetMutableDefault<UExtContentBrowserSettings>()->SetIncludeCollectionNames(!bIncludeCollectionNames);
  3282. GetMutableDefault<UExtContentBrowserSettings>()->PostEditChange();
  3283. OnSearchOptionsChanged.ExecuteIfBound();
  3284. }
  3285. bool SExtAssetView::IsToggleIncludeCollectionNamesAllowed() const
  3286. {
  3287. return true;
  3288. }
  3289. bool SExtAssetView::IsIncludingCollectionNames() const
  3290. {
  3291. return IsToggleIncludeCollectionNamesAllowed() && GetDefault<UExtContentBrowserSettings>()->GetIncludeCollectionNames();
  3292. }
  3293. #endif
  3294. void SExtAssetView::SetCurrentViewType(EAssetViewType::Type NewType)
  3295. {
  3296. if ( ensure(NewType != EAssetViewType::MAX) && NewType != CurrentViewType )
  3297. {
  3298. //ResetQuickJump();
  3299. CurrentViewType = NewType;
  3300. CreateCurrentView();
  3301. SyncToSelection();
  3302. // Clear relevant thumbnails to render fresh ones in the new view if needed
  3303. RelevantThumbnails.Reset();
  3304. VisibleItems.Reset();
  3305. if ( NewType == EAssetViewType::Tile )
  3306. {
  3307. CurrentThumbnailSize = TileViewThumbnailSize;
  3308. bPendingUpdateThumbnails = true;
  3309. }
  3310. else if ( NewType == EAssetViewType::List )
  3311. {
  3312. CurrentThumbnailSize = ListViewThumbnailSize;
  3313. bPendingUpdateThumbnails = true;
  3314. }
  3315. else if ( NewType == EAssetViewType::Column )
  3316. {
  3317. // No thumbnails, but we do need to refresh filtered items to determine a majority asset type
  3318. MajorityAssetType = NAME_None;
  3319. RefreshFilteredItems();
  3320. RefreshFolders();
  3321. SortList();
  3322. }
  3323. }
  3324. }
  3325. void SExtAssetView::SetCurrentViewTypeFromMenu(EAssetViewType::Type NewType)
  3326. {
  3327. if (NewType != CurrentViewType)
  3328. {
  3329. SetCurrentViewType(NewType);
  3330. FSlateApplication::Get().DismissAllMenus();
  3331. }
  3332. }
  3333. void SExtAssetView::CreateCurrentView()
  3334. {
  3335. TileView.Reset();
  3336. ListView.Reset();
  3337. ColumnView.Reset();
  3338. TSharedRef<SWidget> NewView = SNullWidget::NullWidget;
  3339. switch (CurrentViewType)
  3340. {
  3341. case EAssetViewType::Tile:
  3342. TileView = CreateTileView();
  3343. NewView = CreateShadowOverlay(TileView.ToSharedRef());
  3344. break;
  3345. case EAssetViewType::List:
  3346. ListView = CreateListView();
  3347. NewView = CreateShadowOverlay(ListView.ToSharedRef());
  3348. break;
  3349. case EAssetViewType::Column:
  3350. ColumnView = CreateColumnView();
  3351. NewView = CreateShadowOverlay(ColumnView.ToSharedRef());
  3352. break;
  3353. }
  3354. ViewContainer->SetContent( NewView );
  3355. }
  3356. TSharedRef<SWidget> SExtAssetView::CreateShadowOverlay( TSharedRef<STableViewBase> Table )
  3357. {
  3358. return SNew(SScrollBorder, Table)
  3359. [
  3360. Table
  3361. ];
  3362. }
  3363. EAssetViewType::Type SExtAssetView::GetCurrentViewType() const
  3364. {
  3365. return CurrentViewType;
  3366. }
  3367. bool SExtAssetView::IsCurrentViewType(EAssetViewType::Type ViewType) const
  3368. {
  3369. return GetCurrentViewType() == ViewType;
  3370. }
  3371. void SExtAssetView::FocusList() const
  3372. {
  3373. switch ( GetCurrentViewType() )
  3374. {
  3375. case EAssetViewType::List: FSlateApplication::Get().SetKeyboardFocus(ListView, EFocusCause::SetDirectly); break;
  3376. case EAssetViewType::Tile: FSlateApplication::Get().SetKeyboardFocus(TileView, EFocusCause::SetDirectly); break;
  3377. case EAssetViewType::Column: FSlateApplication::Get().SetKeyboardFocus(ColumnView, EFocusCause::SetDirectly); break;
  3378. }
  3379. }
  3380. void SExtAssetView::RefreshList()
  3381. {
  3382. switch ( GetCurrentViewType() )
  3383. {
  3384. case EAssetViewType::List: ListView->RequestListRefresh(); break;
  3385. case EAssetViewType::Tile: TileView->RequestListRefresh(); break;
  3386. case EAssetViewType::Column: ColumnView->RequestListRefresh(); break;
  3387. }
  3388. }
  3389. void SExtAssetView::SetSelection(const TSharedPtr<FExtAssetViewItem>& Item)
  3390. {
  3391. switch ( GetCurrentViewType() )
  3392. {
  3393. case EAssetViewType::List: ListView->SetSelection(Item); break;
  3394. case EAssetViewType::Tile: TileView->SetSelection(Item); break;
  3395. case EAssetViewType::Column: ColumnView->SetSelection(Item); break;
  3396. }
  3397. }
  3398. void SExtAssetView::SetItemSelection(const TSharedPtr<FExtAssetViewItem>& Item, bool bSelected, const ESelectInfo::Type SelectInfo)
  3399. {
  3400. switch ( GetCurrentViewType() )
  3401. {
  3402. case EAssetViewType::List: ListView->SetItemSelection(Item, bSelected, SelectInfo); break;
  3403. case EAssetViewType::Tile: TileView->SetItemSelection(Item, bSelected, SelectInfo); break;
  3404. case EAssetViewType::Column: ColumnView->SetItemSelection(Item, bSelected, SelectInfo); break;
  3405. }
  3406. }
  3407. void SExtAssetView::RequestScrollIntoView(const TSharedPtr<FExtAssetViewItem>& Item)
  3408. {
  3409. switch ( GetCurrentViewType() )
  3410. {
  3411. case EAssetViewType::List: ListView->RequestScrollIntoView(Item); break;
  3412. case EAssetViewType::Tile: TileView->RequestScrollIntoView(Item); break;
  3413. case EAssetViewType::Column: ColumnView->RequestScrollIntoView(Item); break;
  3414. }
  3415. }
  3416. #if ECB_TODO
  3417. void SExtAssetView::OnOpenAssetsOrFolders()
  3418. {
  3419. TArray<FAssetData> SelectedAssets = GetSelectedAssets();
  3420. TArray<FString> SelectedFolders = GetSelectedFolders();
  3421. if (SelectedAssets.Num() > 0 && SelectedFolders.Num() == 0)
  3422. {
  3423. OnAssetsActivated.ExecuteIfBound(SelectedAssets, EAssetTypeActivationMethod::Opened);
  3424. }
  3425. else if (SelectedAssets.Num() == 0 && SelectedFolders.Num() > 0)
  3426. {
  3427. OnPathSelected.ExecuteIfBound(SelectedFolders[0]);
  3428. }
  3429. }
  3430. void SExtAssetView::OnPreviewAssets()
  3431. {
  3432. OnAssetsActivated.ExecuteIfBound(GetSelectedAssets(), EAssetTypeActivationMethod::Previewed);
  3433. }
  3434. #endif
  3435. void SExtAssetView::ClearSelection(bool bForceSilent)
  3436. {
  3437. const bool bTempBulkSelectingValue = bForceSilent ? true : bBulkSelecting;
  3438. TGuardValue<bool>(bBulkSelecting, bTempBulkSelectingValue);
  3439. switch ( GetCurrentViewType() )
  3440. {
  3441. case EAssetViewType::List: ListView->ClearSelection(); break;
  3442. case EAssetViewType::Tile: TileView->ClearSelection(); break;
  3443. case EAssetViewType::Column: ColumnView->ClearSelection(); break;
  3444. }
  3445. }
  3446. TSharedRef<ITableRow> SExtAssetView::MakeListViewWidget(TSharedPtr<FExtAssetViewItem> AssetItem, const TSharedRef<STableViewBase>& OwnerTable)
  3447. {
  3448. if ( !ensure(AssetItem.IsValid()) )
  3449. {
  3450. return SNew( STableRow<TSharedPtr<FExtAssetViewAsset>>, OwnerTable );
  3451. }
  3452. VisibleItems.Add(AssetItem);
  3453. bPendingUpdateThumbnails = true;
  3454. if(AssetItem->GetType() == EExtAssetItemType::Folder)
  3455. {
  3456. TSharedPtr< STableRow<TSharedPtr<FExtAssetViewItem>> > TableRowWidget;
  3457. SAssignNew( TableRowWidget, STableRow<TSharedPtr<FExtAssetViewItem>>, OwnerTable )
  3458. .Style(FAppStyle::Get(), "ContentBrowser.AssetListView.ColumnListTableRow")
  3459. .Cursor( bAllowDragging ? EMouseCursor::GrabHand : EMouseCursor::Default )
  3460. .OnDragDetected( this, &SExtAssetView::OnDraggingAssetItem );
  3461. TSharedRef<SExtAssetListItem> Item =
  3462. SNew(SExtAssetListItem)
  3463. .AssetItem(AssetItem)
  3464. .ItemHeight(this, &SExtAssetView::GetListViewItemHeight)
  3465. .OnItemDestroyed(this, &SExtAssetView::AssetItemWidgetDestroyed)
  3466. .ShouldAllowToolTip(this, &SExtAssetView::ShouldAllowToolTips)
  3467. .HighlightText(HighlightedText)
  3468. .IsSelected(FIsSelected::CreateSP(TableRowWidget.Get(), &STableRow<TSharedPtr<FExtAssetViewItem>>::IsSelectedExclusively));
  3469. //.OnAssetsOrPathsDragDropped(this, &SExtAssetView::OnAssetsOrPathsDragDropped)
  3470. //.OnFilesDragDropped(this, &SExtAssetView::OnFilesDragDropped);
  3471. TableRowWidget->SetContent(Item);
  3472. return TableRowWidget.ToSharedRef();
  3473. }
  3474. else
  3475. {
  3476. TSharedPtr<FExtAssetViewAsset> AssetItemAsAsset = StaticCastSharedPtr<FExtAssetViewAsset>(AssetItem);
  3477. TSharedPtr<FExtAssetThumbnail>* AssetThumbnailPtr = RelevantThumbnails.Find(AssetItemAsAsset);
  3478. TSharedPtr<FExtAssetThumbnail> AssetThumbnail;
  3479. if ( AssetThumbnailPtr )
  3480. {
  3481. AssetThumbnail = *AssetThumbnailPtr;
  3482. }
  3483. else
  3484. {
  3485. const float ThumbnailResolution = ListViewThumbnailResolution;
  3486. AssetThumbnail = MakeShareable( new FExtAssetThumbnail( AssetItemAsAsset->Data, ThumbnailResolution, ThumbnailResolution, AssetThumbnailPool ) );
  3487. RelevantThumbnails.Add( AssetItemAsAsset, AssetThumbnail );
  3488. AssetThumbnail->GetViewportRenderTargetTexture(); // Access the texture once to trigger it to render
  3489. }
  3490. TSharedPtr< STableRow<TSharedPtr<FExtAssetViewItem>> > TableRowWidget;
  3491. SAssignNew( TableRowWidget, STableRow<TSharedPtr<FExtAssetViewItem>>, OwnerTable )
  3492. .Style(FAppStyle::Get(), "ContentBrowser.AssetListView.ColumnListTableRow")
  3493. .Cursor( bAllowDragging ? EMouseCursor::GrabHand : EMouseCursor::Default )
  3494. .OnDragDetected( this, &SExtAssetView::OnDraggingAssetItem );
  3495. TSharedRef<SExtAssetListItem> Item =
  3496. SNew(SExtAssetListItem)
  3497. .AssetThumbnail(AssetThumbnail)
  3498. .AssetItem(AssetItem)
  3499. .ThumbnailPadding(ListViewThumbnailPadding)
  3500. .ItemHeight(this, &SExtAssetView::GetListViewItemHeight)
  3501. .OnItemDestroyed(this, &SExtAssetView::AssetItemWidgetDestroyed)
  3502. .ShouldAllowToolTip(this, &SExtAssetView::ShouldAllowToolTips)
  3503. .HighlightText(HighlightedText)
  3504. .ThumbnailLabel(ThumbnailLabel)
  3505. .ThumbnailHintColorAndOpacity(this, &SExtAssetView::GetThumbnailHintColorAndOpacity)
  3506. .AllowThumbnailHintLabel(AllowThumbnailHintLabel)
  3507. .IsSelected(FIsSelected::CreateSP(TableRowWidget.Get(), &STableRow<TSharedPtr<FExtAssetViewItem>>::IsSelectedExclusively));
  3508. //.OnIsAssetValidForCustomToolTip(OnIsAssetValidForCustomToolTip)
  3509. //.OnGetCustomAssetToolTip(OnGetCustomAssetToolTip)
  3510. //.OnVisualizeAssetToolTip(OnVisualizeAssetToolTip)
  3511. //.OnAssetToolTipClosing(OnAssetToolTipClosing);
  3512. TableRowWidget->SetContent(Item);
  3513. return TableRowWidget.ToSharedRef();
  3514. }
  3515. }
  3516. TSharedRef<ITableRow> SExtAssetView::MakeTileViewWidget(TSharedPtr<FExtAssetViewItem> AssetItem, const TSharedRef<STableViewBase>& OwnerTable)
  3517. {
  3518. if ( !ensure(AssetItem.IsValid()) )
  3519. {
  3520. return SNew( STableRow<TSharedPtr<FExtAssetViewAsset>>, OwnerTable );
  3521. }
  3522. VisibleItems.Add(AssetItem);
  3523. bPendingUpdateThumbnails = true;
  3524. if(AssetItem->GetType() == EExtAssetItemType::Folder)
  3525. {
  3526. TSharedPtr< STableRow<TSharedPtr<FExtAssetViewItem>> > TableRowWidget;
  3527. SAssignNew( TableRowWidget, STableRow<TSharedPtr<FExtAssetViewItem>>, OwnerTable )
  3528. .Style( FAppStyle::Get(), "ContentBrowser.AssetListView.ColumnListTableRow" )
  3529. .Cursor( bAllowDragging ? EMouseCursor::GrabHand : EMouseCursor::Default )
  3530. .OnDragDetected( this, &SExtAssetView::OnDraggingAssetItem );
  3531. TSharedRef<SExtAssetTileItem> Item =
  3532. SNew(SExtAssetTileItem)
  3533. .AssetItem(AssetItem)
  3534. .ItemWidth(this, &SExtAssetView::GetTileViewItemWidth)
  3535. .OnItemDestroyed(this, &SExtAssetView::AssetItemWidgetDestroyed)
  3536. .ShouldAllowToolTip(this, &SExtAssetView::ShouldAllowToolTips)
  3537. .HighlightText(HighlightedText)
  3538. .IsSelected(FIsSelected::CreateSP(TableRowWidget.Get(), &STableRow<TSharedPtr<FExtAssetViewItem>>::IsSelectedExclusively));
  3539. // .OnAssetsOrPathsDragDropped(this, &SExtAssetView::OnAssetsOrPathsDragDropped)
  3540. // .OnFilesDragDropped(this, &SExtAssetView::OnFilesDragDropped);
  3541. TableRowWidget->SetContent(Item);
  3542. return TableRowWidget.ToSharedRef();
  3543. }
  3544. else
  3545. {
  3546. TSharedPtr<FExtAssetViewAsset> AssetItemAsAsset = StaticCastSharedPtr<FExtAssetViewAsset>(AssetItem);
  3547. TSharedPtr<FExtAssetThumbnail>* AssetThumbnailPtr = RelevantThumbnails.Find(AssetItemAsAsset);
  3548. TSharedPtr<FExtAssetThumbnail> AssetThumbnail;
  3549. if ( AssetThumbnailPtr )
  3550. {
  3551. AssetThumbnail = *AssetThumbnailPtr;
  3552. }
  3553. else
  3554. {
  3555. const float ThumbnailResolution = TileViewThumbnailResolution;
  3556. AssetThumbnail = MakeShareable( new FExtAssetThumbnail( AssetItemAsAsset->Data, ThumbnailResolution, ThumbnailResolution, AssetThumbnailPool ) );
  3557. RelevantThumbnails.Add( AssetItemAsAsset, AssetThumbnail );
  3558. AssetThumbnail->GetViewportRenderTargetTexture(); // Access the texture once to trigger it to render
  3559. }
  3560. TSharedPtr< STableRow<TSharedPtr<FExtAssetViewItem>> > TableRowWidget;
  3561. SAssignNew( TableRowWidget, STableRow<TSharedPtr<FExtAssetViewItem>>, OwnerTable )
  3562. .Style(FAppStyle::Get(), "ContentBrowser.AssetListView.ColumnListTableRow")
  3563. .Cursor( bAllowDragging ? EMouseCursor::GrabHand : EMouseCursor::Default )
  3564. .OnDragDetected( this, &SExtAssetView::OnDraggingAssetItem );
  3565. TSharedRef<SExtAssetTileItem> Item =
  3566. SNew(SExtAssetTileItem)
  3567. .AssetThumbnail(AssetThumbnail)
  3568. .AssetItem(AssetItem)
  3569. .ThumbnailPadding(TileViewThumbnailPadding)
  3570. .ItemWidth(this, &SExtAssetView::GetTileViewItemWidth)
  3571. .OnItemDestroyed(this, &SExtAssetView::AssetItemWidgetDestroyed)
  3572. .ShouldAllowToolTip(this, &SExtAssetView::ShouldAllowToolTips)
  3573. .HighlightText(HighlightedText)
  3574. .ThumbnailLabel(ThumbnailLabel)
  3575. .ThumbnailHintColorAndOpacity(this, &SExtAssetView::GetThumbnailHintColorAndOpacity)
  3576. .AllowThumbnailHintLabel(AllowThumbnailHintLabel)
  3577. .IsSelected(FIsSelected::CreateSP(TableRowWidget.Get(), &STableRow<TSharedPtr<FExtAssetViewItem>>::IsSelectedExclusively));
  3578. //.OnIsAssetValidForCustomToolTip(OnIsAssetValidForCustomToolTip)
  3579. //.OnGetCustomAssetToolTip(OnGetCustomAssetToolTip)
  3580. //.OnVisualizeAssetToolTip( OnVisualizeAssetToolTip )
  3581. //.OnAssetToolTipClosing( OnAssetToolTipClosing );
  3582. TableRowWidget->SetContent(Item);
  3583. return TableRowWidget.ToSharedRef();
  3584. }
  3585. }
  3586. TSharedRef<ITableRow> SExtAssetView::MakeColumnViewWidget(TSharedPtr<FExtAssetViewItem> AssetItem, const TSharedRef<STableViewBase>& OwnerTable)
  3587. {
  3588. if ( !ensure(AssetItem.IsValid()) )
  3589. {
  3590. return SNew( STableRow<TSharedPtr<FExtAssetViewItem>>, OwnerTable )
  3591. .Style(FAppStyle::Get(), "ContentBrowser.AssetListView.ColumnListTableRow");
  3592. }
  3593. // Update the cached custom data
  3594. AssetItem->CacheCustomColumns(CustomColumns, false, true, false);
  3595. return
  3596. SNew( SExtAssetColumnViewRow, OwnerTable )
  3597. .OnDragDetected( this, &SExtAssetView::OnDraggingAssetItem )
  3598. .Cursor( bAllowDragging ? EMouseCursor::GrabHand : EMouseCursor::Default )
  3599. .AssetColumnItem(
  3600. SNew(SExtAssetColumnItem)
  3601. .AssetItem(AssetItem)
  3602. .OnItemDestroyed(this, &SExtAssetView::AssetItemWidgetDestroyed)
  3603. .HighlightText( HighlightedText )
  3604. //.OnAssetsOrPathsDragDropped(this, &SExtAssetView::OnAssetsOrPathsDragDropped)
  3605. //.OnFilesDragDropped(this, &SExtAssetView::OnFilesDragDropped)
  3606. //.OnIsAssetValidForCustomToolTip(OnIsAssetValidForCustomToolTip)
  3607. //.OnGetCustomAssetToolTip(OnGetCustomAssetToolTip)
  3608. //.OnVisualizeAssetToolTip( OnVisualizeAssetToolTip )
  3609. //.OnAssetToolTipClosing( OnAssetToolTipClosing )
  3610. );
  3611. }
  3612. void SExtAssetView::AssetItemWidgetDestroyed(const TSharedPtr<FExtAssetViewItem>& Item)
  3613. {
  3614. if ( VisibleItems.Remove(Item) != INDEX_NONE )
  3615. {
  3616. bPendingUpdateThumbnails = true;
  3617. }
  3618. }
  3619. void SExtAssetView::UpdateThumbnails()
  3620. {
  3621. int32 MinItemIdx = INDEX_NONE;
  3622. int32 MaxItemIdx = INDEX_NONE;
  3623. int32 MinVisibleItemIdx = INDEX_NONE;
  3624. int32 MaxVisibleItemIdx = INDEX_NONE;
  3625. const int32 HalfNumOffscreenThumbnails = NumOffscreenThumbnails * 0.5;
  3626. for ( auto ItemIt = VisibleItems.CreateConstIterator(); ItemIt; ++ItemIt )
  3627. {
  3628. int32 ItemIdx = FilteredAssetItems.Find(*ItemIt);
  3629. if ( ItemIdx != INDEX_NONE )
  3630. {
  3631. const int32 ItemIdxLow = FMath::Max<int32>(0, ItemIdx - HalfNumOffscreenThumbnails);
  3632. const int32 ItemIdxHigh = FMath::Min<int32>(FilteredAssetItems.Num() - 1, ItemIdx + HalfNumOffscreenThumbnails);
  3633. if ( MinItemIdx == INDEX_NONE || ItemIdxLow < MinItemIdx )
  3634. {
  3635. MinItemIdx = ItemIdxLow;
  3636. }
  3637. if ( MaxItemIdx == INDEX_NONE || ItemIdxHigh > MaxItemIdx )
  3638. {
  3639. MaxItemIdx = ItemIdxHigh;
  3640. }
  3641. if ( MinVisibleItemIdx == INDEX_NONE || ItemIdx < MinVisibleItemIdx )
  3642. {
  3643. MinVisibleItemIdx = ItemIdx;
  3644. }
  3645. if ( MaxVisibleItemIdx == INDEX_NONE || ItemIdx > MaxVisibleItemIdx )
  3646. {
  3647. MaxVisibleItemIdx = ItemIdx;
  3648. }
  3649. }
  3650. }
  3651. if ( MinItemIdx != INDEX_NONE && MaxItemIdx != INDEX_NONE && MinVisibleItemIdx != INDEX_NONE && MaxVisibleItemIdx != INDEX_NONE )
  3652. {
  3653. // We have a new min and a new max, compare it to the old min and max so we can create new thumbnails
  3654. // when appropriate and remove old thumbnails that are far away from the view area.
  3655. TMap< TSharedPtr<FExtAssetViewAsset>, TSharedPtr<FExtAssetThumbnail> > NewRelevantThumbnails;
  3656. // Operate on offscreen items that are furthest away from the visible items first since the thumbnail pool processes render requests in a LIFO order.
  3657. while (MinItemIdx < MinVisibleItemIdx || MaxItemIdx > MaxVisibleItemIdx)
  3658. {
  3659. const int32 LowEndDistance = MinVisibleItemIdx - MinItemIdx;
  3660. const int32 HighEndDistance = MaxItemIdx - MaxVisibleItemIdx;
  3661. if ( HighEndDistance > LowEndDistance )
  3662. {
  3663. if(FilteredAssetItems.IsValidIndex(MaxItemIdx) && FilteredAssetItems[MaxItemIdx]->GetType() != EExtAssetItemType::Folder)
  3664. {
  3665. AddItemToNewThumbnailRelevancyMap( StaticCastSharedPtr<FExtAssetViewAsset>(FilteredAssetItems[MaxItemIdx]), NewRelevantThumbnails );
  3666. }
  3667. MaxItemIdx--;
  3668. }
  3669. else
  3670. {
  3671. if(FilteredAssetItems.IsValidIndex(MinItemIdx) && FilteredAssetItems[MinItemIdx]->GetType() != EExtAssetItemType::Folder)
  3672. {
  3673. AddItemToNewThumbnailRelevancyMap( StaticCastSharedPtr<FExtAssetViewAsset>(FilteredAssetItems[MinItemIdx]), NewRelevantThumbnails );
  3674. }
  3675. MinItemIdx++;
  3676. }
  3677. }
  3678. // Now operate on VISIBLE items then prioritize them so they are rendered first
  3679. TArray< TSharedPtr<FExtAssetThumbnail> > ThumbnailsToPrioritize;
  3680. for ( int32 ItemIdx = MinVisibleItemIdx; ItemIdx <= MaxVisibleItemIdx; ++ItemIdx )
  3681. {
  3682. if(FilteredAssetItems.IsValidIndex(ItemIdx) && FilteredAssetItems[ItemIdx]->GetType() != EExtAssetItemType::Folder)
  3683. {
  3684. TSharedPtr<FExtAssetThumbnail> Thumbnail = AddItemToNewThumbnailRelevancyMap( StaticCastSharedPtr<FExtAssetViewAsset>(FilteredAssetItems[ItemIdx]), NewRelevantThumbnails );
  3685. if ( Thumbnail.IsValid() )
  3686. {
  3687. ThumbnailsToPrioritize.Add(Thumbnail);
  3688. }
  3689. }
  3690. }
  3691. // Now prioritize all thumbnails there were in the visible range
  3692. if ( ThumbnailsToPrioritize.Num() > 0 )
  3693. {
  3694. AssetThumbnailPool->PrioritizeThumbnails(ThumbnailsToPrioritize, CurrentThumbnailSize, CurrentThumbnailSize);
  3695. }
  3696. // Assign the new map of relevant thumbnails. This will remove any entries that were no longer relevant.
  3697. RelevantThumbnails = NewRelevantThumbnails;
  3698. }
  3699. }
  3700. TSharedPtr<FExtAssetThumbnail> SExtAssetView::AddItemToNewThumbnailRelevancyMap(const TSharedPtr<FExtAssetViewAsset>& Item, TMap< TSharedPtr<FExtAssetViewAsset>, TSharedPtr<FExtAssetThumbnail> >& NewRelevantThumbnails)
  3701. {
  3702. const TSharedPtr<FExtAssetThumbnail>* Thumbnail = RelevantThumbnails.Find(Item);
  3703. if ( Thumbnail )
  3704. {
  3705. // The thumbnail is still relevant, add it to the new list
  3706. NewRelevantThumbnails.Add(Item, *Thumbnail);
  3707. return *Thumbnail;
  3708. }
  3709. else
  3710. {
  3711. if ( !ensure(CurrentThumbnailSize > 0 && CurrentThumbnailSize <= MAX_THUMBNAIL_SIZE) )
  3712. {
  3713. // Thumbnail size must be in a sane range
  3714. CurrentThumbnailSize = 64;
  3715. }
  3716. // The thumbnail newly relevant, create a new thumbnail
  3717. const float ThumbnailResolution = CurrentThumbnailSize * MaxThumbnailScale;
  3718. TSharedPtr<FExtAssetThumbnail> NewThumbnail = MakeShareable( new FExtAssetThumbnail( Item->Data, ThumbnailResolution, ThumbnailResolution, AssetThumbnailPool ) );
  3719. NewRelevantThumbnails.Add( Item, NewThumbnail );
  3720. NewThumbnail->GetViewportRenderTargetTexture(); // Access the texture once to trigger it to render
  3721. return NewThumbnail;
  3722. }
  3723. }
  3724. void SExtAssetView::AssetSelectionChanged( TSharedPtr< struct FExtAssetViewItem > AssetItem, ESelectInfo::Type SelectInfo )
  3725. {
  3726. if ( !bBulkSelecting )
  3727. {
  3728. if ( AssetItem.IsValid() && AssetItem->GetType() != EExtAssetItemType::Folder )
  3729. {
  3730. OnAssetSelected.ExecuteIfBound(StaticCastSharedPtr<FExtAssetViewAsset>(AssetItem)->Data);
  3731. }
  3732. else
  3733. {
  3734. OnAssetSelected.ExecuteIfBound(FExtAssetData());
  3735. }
  3736. }
  3737. }
  3738. void SExtAssetView::ItemScrolledIntoView(TSharedPtr<struct FExtAssetViewItem> AssetItem, const TSharedPtr<ITableRow>& Widget )
  3739. {
  3740. const bool bTryRestoreFocus = false; //if ( AssetItem->bRenameWhenScrolledIntoview )
  3741. if (bTryRestoreFocus)
  3742. {
  3743. // Make sure we have window focus to avoid the inline text editor from canceling itself if we try to click on it
  3744. // This can happen if creating an asset opens an intermediary window which steals our focus,
  3745. // eg, the blueprint and slate widget style class windows (TTP# 314240)
  3746. TSharedPtr<SWindow> OwnerWindow = FSlateApplication::Get().FindWidgetWindow(AsShared());
  3747. if(OwnerWindow.IsValid())
  3748. {
  3749. OwnerWindow->BringToFront();
  3750. }
  3751. //AwaitingRename = AssetItem;
  3752. }
  3753. }
  3754. TSharedPtr<SWidget> SExtAssetView::OnGetContextMenuContent()
  3755. {
  3756. if ( CanOpenContextMenu() )
  3757. {
  3758. const TArray<FString> SelectedFolders = GetSelectedFolders();
  3759. if(SelectedFolders.Num() > 0)
  3760. {
  3761. return NULL;// OnGetFolderContextMenu.Execute(SelectedFolders, OnGetPathContextMenuExtender);
  3762. }
  3763. else
  3764. {
  3765. return OnGetAssetContextMenu.Execute(GetSelectedAssets());
  3766. }
  3767. }
  3768. return NULL;
  3769. }
  3770. bool SExtAssetView::CanOpenContextMenu() const
  3771. {
  3772. #if ECB_LEGACY
  3773. if ( !OnGetAssetContextMenu.IsBound() )
  3774. {
  3775. // You can only a summon a context menu if one is set up
  3776. return false;
  3777. }
  3778. #endif
  3779. TArray<FExtAssetData> SelectedAssets = GetSelectedAssets();
  3780. #if ECB_LEGACY
  3781. // Detect if at least one temporary item was selected. If there were no valid assets selected and a temporary one was, then deny the context menu.
  3782. TArray<TSharedPtr<FExtAssetViewItem>> SelectedItems = GetSelectedItems();
  3783. bool bAtLeastOneTemporaryItemFound = false;
  3784. for ( auto ItemIt = SelectedItems.CreateConstIterator(); ItemIt; ++ItemIt )
  3785. {
  3786. const TSharedPtr<FExtAssetViewItem>& Item = *ItemIt;
  3787. if ( Item->IsTemporaryItem() )
  3788. {
  3789. bAtLeastOneTemporaryItemFound = true;
  3790. }
  3791. }
  3792. // If there were no valid assets found, but some invalid assets were found, deny the context menu
  3793. if ( SelectedAssets.Num() == 0 && bAtLeastOneTemporaryItemFound )
  3794. {
  3795. return false;
  3796. }
  3797. if ( SelectedAssets.Num() == 0 && SourcesData.HasCollections() )
  3798. {
  3799. // Don't allow a context menu when we're viewing a collection and have no assets selected
  3800. return false;
  3801. }
  3802. // Build a list of selected object paths
  3803. TArray<FString> ObjectPaths;
  3804. for(auto AssetIt = SelectedAssets.CreateConstIterator(); AssetIt; ++AssetIt)
  3805. {
  3806. ObjectPaths.Add( AssetIt->ObjectPath.ToString() );
  3807. }
  3808. bool bLoadSuccessful = true;
  3809. if ( bPreloadAssetsForContextMenu )
  3810. {
  3811. TArray<UObject*> LoadedObjects;
  3812. const bool bAllowedToPrompt = false;
  3813. bLoadSuccessful = ContentBrowserUtils::LoadAssetsIfNeeded(ObjectPaths, LoadedObjects, bAllowedToPrompt);
  3814. }
  3815. // Do not show the context menu if the load failed
  3816. return bLoadSuccessful;
  3817. #endif
  3818. return SelectedAssets.Num() > 0;
  3819. }
  3820. void SExtAssetView::OnListMouseButtonDoubleClick(TSharedPtr<FExtAssetViewItem> AssetItem)
  3821. {
  3822. if ( !ensure(AssetItem.IsValid()) )
  3823. {
  3824. return;
  3825. }
  3826. if ( AssetItem->GetType() == EExtAssetItemType::Folder )
  3827. {
  3828. OnPathSelected.ExecuteIfBound(StaticCastSharedPtr<FExtAssetViewFolder>(AssetItem)->FolderPath);
  3829. return;
  3830. }
  3831. if ( AssetItem->IsTemporaryItem() )
  3832. {
  3833. // You may not activate temporary items, they are just for display.
  3834. return;
  3835. }
  3836. #if ECB_LEGACY
  3837. TArray<FExtAssetData> ActivatedAssets;
  3838. ActivatedAssets.Add(StaticCastSharedPtr<FExtAssetViewAsset>(AssetItem)->Data);
  3839. OnAssetsActivated.ExecuteIfBound( ActivatedAssets, EAssetTypeActivationMethod::DoubleClicked );
  3840. #endif
  3841. }
  3842. FReply SExtAssetView::OnDraggingAssetItem( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
  3843. {
  3844. if (bAllowDragging)
  3845. {
  3846. TArray<FExtAssetData> DraggedAssets;
  3847. TArray<FString> DraggedAssetPaths;
  3848. //TArray<FString> DraggedAssetFilePaths;
  3849. TArray<FAssetData> FakeDraggedAssets;
  3850. // Work out which assets to drag
  3851. {
  3852. TArray<FExtAssetData> AssetDataList = GetSelectedAssets();
  3853. for (const FExtAssetData& AssetData : AssetDataList)
  3854. {
  3855. // Skip invalid assets and redirectors
  3856. if (AssetData.IsValid() && AssetData.AssetClass != UObjectRedirector::StaticClass()->GetFName())
  3857. {
  3858. //DraggedAssets.Add(AssetData.AssetData);
  3859. if (!FExtContentBrowserSingleton::GetAssetRegistry().IsCachedDependencyInfoInValid(AssetData))
  3860. {
  3861. DraggedAssets.Add(AssetData);
  3862. //DraggedAssetFilePaths.Add(AssetData.PackageFilePath.ToString());
  3863. FakeDraggedAssets.Add(AssetData.AssetData);
  3864. }
  3865. }
  3866. }
  3867. }
  3868. #if ECB_DISABLE // no support of dragging a whole external folder around, yet
  3869. // Work out which asset paths to drag
  3870. {
  3871. TArray<FString> SelectedFolders = GetSelectedFolders();
  3872. if (SelectedFolders.Num() > 0 && !SourcesData.HasCollections())
  3873. {
  3874. DraggedAssetPaths = MoveTemp(SelectedFolders);
  3875. }
  3876. }
  3877. #endif
  3878. #if ECB_DISABLE
  3879. // Use the custom drag handler?
  3880. if (DraggedAssets.Num() > 0 && FEditorDelegates::OnAssetDragStarted.IsBound())
  3881. {
  3882. FEditorDelegates::OnAssetDragStarted.Broadcast(DraggedAssets, nullptr);
  3883. return FReply::Handled();
  3884. }
  3885. #endif
  3886. // Use the standard drag handler?
  3887. if ((DraggedAssets.Num() > 0 || DraggedAssetPaths.Num() > 0) && MouseEvent.IsMouseButtonDown(EKeys::LeftMouseButton))
  3888. {
  3889. if (MouseEvent.IsControlDown())
  3890. {
  3891. //return FReply::Handled().BeginDragDrop(FAssetDragDropOp::New(MoveTemp(FakeDraggedAssets), MoveTemp(DraggedAssetPaths)));
  3892. return FReply::Handled().BeginDragDrop(FExtAssetDragDropOp::New(MoveTemp(DraggedAssets), MoveTemp(DraggedAssetPaths)));
  3893. }
  3894. else
  3895. {
  3896. return FReply::Handled().BeginDragDrop(FExtAssetDragDropOp::New(MoveTemp(DraggedAssets), MoveTemp(DraggedAssetPaths)));
  3897. }
  3898. }
  3899. }
  3900. return FReply::Unhandled();
  3901. }
  3902. bool SExtAssetView::ShouldAllowToolTips() const
  3903. {
  3904. if (!IsShowingAssetTooltip())
  3905. {
  3906. return false;
  3907. }
  3908. bool bIsRightClickScrolling = false;
  3909. switch( CurrentViewType )
  3910. {
  3911. case EAssetViewType::List:
  3912. bIsRightClickScrolling = ListView->IsRightClickScrolling();
  3913. break;
  3914. case EAssetViewType::Tile:
  3915. bIsRightClickScrolling = TileView->IsRightClickScrolling();
  3916. break;
  3917. case EAssetViewType::Column:
  3918. bIsRightClickScrolling = ColumnView->IsRightClickScrolling();
  3919. break;
  3920. default:
  3921. bIsRightClickScrolling = false;
  3922. break;
  3923. }
  3924. return !bIsRightClickScrolling;
  3925. }
  3926. FText SExtAssetView::GetAssetCountText() const
  3927. {
  3928. const int32 NumAssets = FilteredAssetItems.Num();
  3929. const int32 NumSelectedAssets = GetSelectedItems().Num();
  3930. FText AssetCount = FText::GetEmpty();
  3931. if ( NumSelectedAssets == 0 )
  3932. {
  3933. if ( NumAssets == 1 )
  3934. {
  3935. AssetCount = LOCTEXT("AssetCountLabelSingular", "1 item");
  3936. }
  3937. else
  3938. {
  3939. AssetCount = FText::Format( LOCTEXT("AssetCountLabelPlural", "{0} items"), FText::AsNumber(NumAssets) );
  3940. }
  3941. }
  3942. else
  3943. {
  3944. if ( NumAssets == 1 )
  3945. {
  3946. AssetCount = FText::Format( LOCTEXT("AssetCountLabelSingularPlusSelection", "1 item ({0} selected)"), FText::AsNumber(NumSelectedAssets) );
  3947. }
  3948. else
  3949. {
  3950. AssetCount = FText::Format( LOCTEXT("AssetCountLabelPluralPlusSelection", "{0} items ({1} selected)"), FText::AsNumber(NumAssets), FText::AsNumber(NumSelectedAssets) );
  3951. }
  3952. }
  3953. return AssetCount;
  3954. }
  3955. EVisibility SExtAssetView::GetListViewVisibility() const
  3956. {
  3957. return GetCurrentViewType() == EAssetViewType::List ? EVisibility::Visible : EVisibility::Collapsed;
  3958. }
  3959. EVisibility SExtAssetView::GetTileViewVisibility() const
  3960. {
  3961. return GetCurrentViewType() == EAssetViewType::Tile ? EVisibility::Visible : EVisibility::Collapsed;
  3962. }
  3963. EVisibility SExtAssetView::GetColumnViewVisibility() const
  3964. {
  3965. return GetCurrentViewType() == EAssetViewType::Column ? EVisibility::Visible : EVisibility::Collapsed;
  3966. }
  3967. #if ECB_LEGACY
  3968. void SExtAssetView::ToggleThumbnailEditMode()
  3969. {
  3970. bThumbnailEditMode = !bThumbnailEditMode;
  3971. }
  3972. #endif
  3973. float SExtAssetView::GetThumbnailScale() const
  3974. {
  3975. return ThumbnailScaleSliderValue.Get();
  3976. }
  3977. void SExtAssetView::SetThumbnailScale( float NewValue )
  3978. {
  3979. ThumbnailScaleSliderValue = NewValue;
  3980. RefreshList();
  3981. }
  3982. bool SExtAssetView::IsThumbnailScalingLocked() const
  3983. {
  3984. return GetCurrentViewType() == EAssetViewType::Column;
  3985. }
  3986. float SExtAssetView::GetListViewItemHeight() const
  3987. {
  3988. return (ListViewThumbnailSize + ListViewThumbnailPadding * 2) * FMath::Lerp(MinThumbnailScale, MaxThumbnailScale, GetThumbnailScale());
  3989. }
  3990. float SExtAssetView::GetTileViewItemHeight() const
  3991. {
  3992. return TileViewNameHeight + GetTileViewItemBaseHeight() * FillScale;
  3993. }
  3994. float SExtAssetView::GetTileViewItemBaseHeight() const
  3995. {
  3996. return (TileViewThumbnailSize + TileViewThumbnailPadding * 2) * FMath::Lerp(MinThumbnailScale, MaxThumbnailScale, GetThumbnailScale());
  3997. }
  3998. float SExtAssetView::GetTileViewItemWidth() const
  3999. {
  4000. return GetTileViewItemBaseWidth() * FillScale;
  4001. }
  4002. float SExtAssetView::GetTileViewItemBaseWidth() const //-V524
  4003. {
  4004. return ( TileViewThumbnailSize + TileViewThumbnailPadding * 2 ) * FMath::Lerp( MinThumbnailScale, MaxThumbnailScale, GetThumbnailScale() );
  4005. }
  4006. EColumnSortMode::Type SExtAssetView::GetColumnSortMode(const FName ColumnId) const
  4007. {
  4008. for (int32 PriorityIdx = 0; PriorityIdx < EColumnSortPriority::Max; PriorityIdx++)
  4009. {
  4010. const EColumnSortPriority::Type SortPriority = static_cast<EColumnSortPriority::Type>(PriorityIdx);
  4011. if (ColumnId == SortManager.GetSortColumnId(SortPriority))
  4012. {
  4013. return SortManager.GetSortMode(SortPriority);
  4014. }
  4015. }
  4016. return EColumnSortMode::None;
  4017. }
  4018. EColumnSortPriority::Type SExtAssetView::GetColumnSortPriority(const FName ColumnId) const
  4019. {
  4020. for (int32 PriorityIdx = 0; PriorityIdx < EColumnSortPriority::Max; PriorityIdx++)
  4021. {
  4022. const EColumnSortPriority::Type SortPriority = static_cast<EColumnSortPriority::Type>(PriorityIdx);
  4023. if (ColumnId == SortManager.GetSortColumnId(SortPriority))
  4024. {
  4025. return SortPriority;
  4026. }
  4027. }
  4028. return EColumnSortPriority::Primary;
  4029. }
  4030. void SExtAssetView::OnSortColumnHeader(const EColumnSortPriority::Type SortPriority, const FName& ColumnId, const EColumnSortMode::Type NewSortMode)
  4031. {
  4032. SortManager.SetSortColumnId(SortPriority, ColumnId);
  4033. SortManager.SetSortMode(SortPriority, NewSortMode);
  4034. SortList();
  4035. }
  4036. EVisibility SExtAssetView::IsAssetShowWarningTextVisible() const
  4037. {
  4038. return (FilteredAssetItems.Num() > 0 || bQuickFrontendListRefreshRequested) ? EVisibility::Collapsed : EVisibility::HitTestInvisible;
  4039. }
  4040. FText SExtAssetView::GetAssetShowWarningText() const
  4041. {
  4042. if (AssetShowWarningText.IsSet())
  4043. {
  4044. return AssetShowWarningText.Get();
  4045. }
  4046. FText NothingToShowText, DropText;
  4047. if (ShouldFilterRecursively())
  4048. {
  4049. NothingToShowText = LOCTEXT( "NothingToShowCheckFilter", "No results, check your filter." );
  4050. }
  4051. #if ECB_WIP_COLLECTION
  4052. if ( SourcesData.HasCollections() && !SourcesData.IsDynamicCollection() )
  4053. {
  4054. DropText = LOCTEXT( "DragAssetsHere", "Drag and drop assets here to add them to the collection." );
  4055. }
  4056. else if ( OnGetAssetContextMenu.IsBound() )
  4057. {
  4058. DropText = LOCTEXT( "DropFilesOrRightClick", "Drop files here or right click to create content." );
  4059. }
  4060. #endif
  4061. return NothingToShowText.IsEmpty() ? DropText : FText::Format(LOCTEXT("NothingToShowPattern", "{0}\n\n{1}"), NothingToShowText, DropText);
  4062. }
  4063. #if ECB_FEA_ASSET_DRAG_DROP
  4064. bool SExtAssetView::OnDropAndDropToAssetView(const FAssetViewDragAndDropExtender::FPayload& InPayLoad)
  4065. {
  4066. ECB_LOG(Display, TEXT("FAssetViewDragAndDropExtenderHelper::OnDrop"));
  4067. TSharedPtr<FDragDropOperation> DragDropOp = InPayLoad.DragDropOp;
  4068. if (DragDropOp->IsOfType<FExtAssetDragDropOp>() && InPayLoad.PackagePaths.Num() > 0)
  4069. {
  4070. TSharedPtr<FExtAssetDragDropOp> AssetDragDropOp = StaticCastSharedPtr<FExtAssetDragDropOp>(DragDropOp);
  4071. const FString DestPath = InPayLoad.PackagePaths[0].ToString();
  4072. OnAssetsOrPathsDragDroppedToContentBrowser(AssetDragDropOp->GetAssets(), AssetDragDropOp->GetAssetPaths(), DestPath);
  4073. return true;
  4074. }
  4075. return false;
  4076. }
  4077. TSharedRef<FExtender> SExtAssetView::OnExtendLevelViewportMenu(const TSharedRef<FUICommandList> CommandList, const TArray<AActor*> InActors)
  4078. {
  4079. TSharedRef<FExtender> Extender(new FExtender());
  4080. int32 NumSelected = GetNumSelectedAssets();
  4081. if (NumSelected > 0)
  4082. {
  4083. FLevelEditorModule& LevelEditor = FModuleManager::GetModuleChecked<FLevelEditorModule>(TEXT("LevelEditor"));
  4084. TSharedRef<FUICommandList> LevelEditorCommandBindings = LevelEditor.GetGlobalLevelEditorActions();
  4085. Extender->AddMenuExtension("ActorControl", EExtensionHook::After, LevelEditorCommandBindings, FMenuExtensionDelegate::CreateLambda(
  4086. [this, NumSelected](FMenuBuilder& MenuBuilder) {
  4087. MenuBuilder.BeginSection("UAssetBrowser", LOCTEXT("UAssetBrowser", "UAsset Browser"));
  4088. //MenuBuilder.AddMenuEntry(FExtContentBrowserCommands::Get().ImportSelectedUAsset, NAME_None, FText::Format(LOCTEXT("ImportSelectedUAsset", "Import {0} UAsset Files"), FText::AsNumber(NumSelected)));
  4089. MenuBuilder.AddMenuEntry(
  4090. FText::Format(LOCTEXT("ImportAndPlaceSelectedUAsset", "Import and place {0} asset(s) here"), FText::AsNumber(NumSelected))
  4091. , LOCTEXT("ImportAndPlaceSelectedUAssetTooltip", "Import selected UAsset Files to Content Browser and place them to current level."),
  4092. FSlateIcon(),
  4093. FUIAction(
  4094. FExecuteAction::CreateSP(this, &SExtAssetView::ExecuteImportAndPlaceSelecteUAssetFiles),
  4095. FCanExecuteAction::CreateLambda([this]() {return GetNumSelectedAssets() > 0; })
  4096. )
  4097. );
  4098. MenuBuilder.EndSection();
  4099. }
  4100. ));
  4101. }
  4102. return Extender;
  4103. }
  4104. void SExtAssetView::OnAssetsOrPathsDragDroppedToContentBrowser(const TArray<FExtAssetData>& AssetList, const TArray<FString>& AssetPaths, const FString& DestinationPath)
  4105. {
  4106. DragDropHandler::HandleDropOnAssetFolderOfContentBrowser(
  4107. SharedThis(this),
  4108. AssetList,
  4109. AssetPaths,
  4110. DestinationPath,
  4111. FText::FromString(FPaths::GetCleanFilename(DestinationPath)),
  4112. DragDropHandler::FExecuteDropToImport::CreateSP(this, &SExtAssetView::ExecuteDropToContentBrowserToImport),
  4113. DragDropHandler::FExecuteDropToImport::CreateSP(this, &SExtAssetView::ExecuteDropToContentBrowserToImportFlat)
  4114. );
  4115. }
  4116. void SExtAssetView::ExecuteImportAndPlaceSelecteUAssetFiles()
  4117. {
  4118. TArray<FExtAssetData> SelectedAssets = GetSelectedAssets();
  4119. if (SelectedAssets.Num() > 0)
  4120. {
  4121. FUAssetImportSetting ImportSetting = FUAssetImportSetting::GetSavedImportSetting();
  4122. ImportSetting.bPlaceImportedAssets = true;
  4123. FExtAssetImporter::ImportAssets(SelectedAssets, ImportSetting);
  4124. }
  4125. }
  4126. void SExtAssetView::ExecuteDropToContentBrowserToImport(TArray<FExtAssetData> AssetList, TArray<FString> AssetPaths, FString DestinationPath)
  4127. {
  4128. FExtAssetImporter::ImportAssets(AssetList, FUAssetImportSetting::GetSavedImportSetting());
  4129. #if ECB_LEGACY
  4130. int32 NumItemsCopied = 0;
  4131. if (AssetList.Num() > 0)
  4132. {
  4133. TArray<UObject*> DroppedObjects;
  4134. ContentBrowserUtils::GetObjectsInAssetData(AssetList, DroppedObjects);
  4135. TArray<UObject*> NewObjects;
  4136. ObjectTools::DuplicateObjects(DroppedObjects, TEXT(""), DestinationPath, /*bOpenDialog=*/false, &NewObjects);
  4137. NumItemsCopied += NewObjects.Num();
  4138. }
  4139. if (AssetPaths.Num() > 0)
  4140. {
  4141. if (ContentBrowserUtils::CopyFolders(AssetPaths, DestinationPath))
  4142. {
  4143. NumItemsCopied += AssetPaths.Num();
  4144. }
  4145. }
  4146. // If any items were duplicated, report the success
  4147. if (NumItemsCopied > 0)
  4148. {
  4149. const FText Message = FText::Format(LOCTEXT("AssetItemsDroppedCopy", "{0} {0}|plural(one=item,other=items) copied"), NumItemsCopied);
  4150. const FVector2D& CursorPos = FSlateApplication::Get().GetCursorPos();
  4151. FSlateRect MessageAnchor(CursorPos.X, CursorPos.Y, CursorPos.X, CursorPos.Y);
  4152. ContentBrowserUtils::DisplayMessage(Message, MessageAnchor, SharedThis(this));
  4153. }
  4154. #endif
  4155. }
  4156. void SExtAssetView::ExecuteDropToContentBrowserToImportFlat(TArray<FExtAssetData> AssetList, TArray<FString> AssetPaths, FString DestinationPath)
  4157. {
  4158. FExtAssetImporter::ImportAssetsToFolderPackagePath(AssetList, FUAssetImportSetting::GetFlatModeImportSetting(), DestinationPath);
  4159. #if ECB_LEGACY
  4160. if (AssetList.Num() > 0)
  4161. {
  4162. TArray<UObject*> DroppedObjects;
  4163. ContentBrowserUtils::GetObjectsInAssetData(AssetList, DroppedObjects);
  4164. ContentBrowserUtils::MoveAssets(DroppedObjects, DestinationPath);
  4165. }
  4166. // Prepare to fixup any asset paths that are favorites
  4167. TArray<FMovedContentFolder> MovedFolders;
  4168. for (const FString& OldPath : AssetPaths)
  4169. {
  4170. const FString SubFolderName = FPackageName::GetLongPackageAssetName(OldPath);
  4171. const FString NewPath = DestinationPath + TEXT("/") + SubFolderName;
  4172. MovedFolders.Add(FMovedContentFolder(OldPath, NewPath));
  4173. }
  4174. if (AssetPaths.Num() > 0)
  4175. {
  4176. ContentBrowserUtils::MoveFolders(AssetPaths, DestinationPath);
  4177. }
  4178. OnFolderPathChanged.ExecuteIfBound(MovedFolders);
  4179. #endif
  4180. }
  4181. #endif
  4182. #if ECB_LEGACY
  4183. bool SExtAssetView::HasSingleCollectionSource() const
  4184. {
  4185. return ( SourcesData.Collections.Num() == 1 && SourcesData.PackagePaths.Num() == 0 );
  4186. }
  4187. void SExtAssetView::OnAssetsOrPathsDragDropped(const TArray<FAssetData>& AssetList, const TArray<FString>& AssetPaths, const FString& DestinationPath)
  4188. {
  4189. DragDropHandler::HandleDropOnAssetFolder(
  4190. SharedThis(this),
  4191. AssetList,
  4192. AssetPaths,
  4193. DestinationPath,
  4194. FText::FromString(FPaths::GetCleanFilename(DestinationPath)),
  4195. DragDropHandler::FExecuteCopyOrMove::CreateSP(this, &SExtAssetView::ExecuteDropCopy),
  4196. DragDropHandler::FExecuteCopyOrMove::CreateSP(this, &SExtAssetView::ExecuteDropMove),
  4197. DragDropHandler::FExecuteCopyOrMove::CreateSP(this, &SExtAssetView::ExecuteDropAdvancedCopy)
  4198. );
  4199. }
  4200. void SExtAssetView::OnFilesDragDropped(const TArray<FString>& AssetList, const FString& DestinationPath)
  4201. {
  4202. FAssetToolsModule& AssetToolsModule = FModuleManager::Get().LoadModuleChecked<FAssetToolsModule>("AssetTools");
  4203. AssetToolsModule.Get().ImportAssets( AssetList, DestinationPath );
  4204. }
  4205. void SExtAssetView::ExecuteDropCopy(TArray<FAssetData> AssetList, TArray<FString> AssetPaths, FString DestinationPath)
  4206. {
  4207. int32 NumItemsCopied = 0;
  4208. if (AssetList.Num() > 0)
  4209. {
  4210. TArray<UObject*> DroppedObjects;
  4211. ContentBrowserUtils::GetObjectsInAssetData(AssetList, DroppedObjects);
  4212. TArray<UObject*> NewObjects;
  4213. ObjectTools::DuplicateObjects(DroppedObjects, TEXT(""), DestinationPath, /*bOpenDialog=*/false, &NewObjects);
  4214. NumItemsCopied += NewObjects.Num();
  4215. }
  4216. if (AssetPaths.Num() > 0)
  4217. {
  4218. if (ContentBrowserUtils::CopyFolders(AssetPaths, DestinationPath))
  4219. {
  4220. NumItemsCopied += AssetPaths.Num();
  4221. }
  4222. }
  4223. // If any items were duplicated, report the success
  4224. if (NumItemsCopied > 0)
  4225. {
  4226. const FText Message = FText::Format(LOCTEXT("AssetItemsDroppedCopy", "{0} {0}|plural(one=item,other=items) copied"), NumItemsCopied);
  4227. const FVector2D& CursorPos = FSlateApplication::Get().GetCursorPos();
  4228. FSlateRect MessageAnchor(CursorPos.X, CursorPos.Y, CursorPos.X, CursorPos.Y);
  4229. ContentBrowserUtils::DisplayMessage(Message, MessageAnchor, SharedThis(this));
  4230. }
  4231. }
  4232. void SExtAssetView::ExecuteDropMove(TArray<FAssetData> AssetList, TArray<FString> AssetPaths, FString DestinationPath)
  4233. {
  4234. if (AssetList.Num() > 0)
  4235. {
  4236. TArray<UObject*> DroppedObjects;
  4237. ContentBrowserUtils::GetObjectsInAssetData(AssetList, DroppedObjects);
  4238. ContentBrowserUtils::MoveAssets(DroppedObjects, DestinationPath);
  4239. }
  4240. // Prepare to fixup any asset paths that are favorites
  4241. TArray<FMovedContentFolder> MovedFolders;
  4242. for (const FString& OldPath : AssetPaths)
  4243. {
  4244. const FString SubFolderName = FPackageName::GetLongPackageAssetName(OldPath);
  4245. const FString NewPath = DestinationPath + TEXT("/") + SubFolderName;
  4246. MovedFolders.Add(FMovedContentFolder(OldPath, NewPath));
  4247. }
  4248. if (AssetPaths.Num() > 0)
  4249. {
  4250. ContentBrowserUtils::MoveFolders(AssetPaths, DestinationPath);
  4251. }
  4252. OnFolderPathChanged.ExecuteIfBound(MovedFolders);
  4253. }
  4254. void SExtAssetView::ExecuteDropAdvancedCopy(TArray<FAssetData> AssetList, TArray<FString> AssetPaths, FString DestinationPath)
  4255. {
  4256. ContentBrowserUtils::BeginAdvancedCopyPackages(AssetList, AssetPaths, DestinationPath);
  4257. }
  4258. #endif
  4259. #if ECB_FEA_SEARCH
  4260. void SExtAssetView::SetUserSearching(bool bInSearching)
  4261. {
  4262. if(bUserSearching != bInSearching)
  4263. {
  4264. RequestSlowFullListRefresh();
  4265. }
  4266. bUserSearching = bInSearching;
  4267. }
  4268. #endif
  4269. void SExtAssetView::HandleSettingChanged(FName PropertyName)
  4270. {
  4271. if ((PropertyName == GET_MEMBER_NAME_CHECKED(UExtContentBrowserSettings, DisplayFolders)) ||
  4272. (PropertyName == GET_MEMBER_NAME_CHECKED(UExtContentBrowserSettings, DisplayEmptyFolders)) ||
  4273. (PropertyName == "DisplayDevelopersFolder") ||
  4274. (PropertyName == "DisplayEngineFolder") ||
  4275. (PropertyName == NAME_None)) // @todo: Needed if PostEditChange was called manually, for now
  4276. {
  4277. RequestSlowFullListRefresh();
  4278. }
  4279. }
  4280. void SExtAssetView::OnAssetRegistryAssetGathered(const FExtAssetData& AssetData, int32 Left)
  4281. {
  4282. RecentlyAddedAssets.Add(AssetData);
  4283. }
  4284. void SExtAssetView::OnAssetRegistryRootPathAdded(const FString& Path)
  4285. {
  4286. }
  4287. void SExtAssetView::OnAssetRegistryRootPathRemoved(const FString& Path)
  4288. {
  4289. // Clear all
  4290. SetSourcesData(FSourcesData());
  4291. }
  4292. #if ECB_WIP_BREADCRUMB
  4293. FText SExtAssetView::GetQuickJumpTerm() const
  4294. {
  4295. return FText::FromString(QuickJumpData.JumpTerm);
  4296. }
  4297. EVisibility SExtAssetView::IsQuickJumpVisible() const
  4298. {
  4299. return (QuickJumpData.JumpTerm.IsEmpty()) ? EVisibility::Collapsed : EVisibility::HitTestInvisible;
  4300. }
  4301. FSlateColor SExtAssetView::GetQuickJumpColor() const
  4302. {
  4303. return FAppStyle::GetColor((QuickJumpData.bHasValidMatch) ? "InfoReporting.BackgroundColor" : "ErrorReporting.BackgroundColor");
  4304. }
  4305. void SExtAssetView::ResetQuickJump()
  4306. {
  4307. QuickJumpData.JumpTerm.Empty();
  4308. QuickJumpData.bIsJumping = false;
  4309. QuickJumpData.bHasChangedSinceLastTick = false;
  4310. QuickJumpData.bHasValidMatch = false;
  4311. }
  4312. FReply SExtAssetView::HandleQuickJumpKeyDown(const TCHAR InCharacter, const bool bIsControlDown, const bool bIsAltDown, const bool bTestOnly)
  4313. {
  4314. // Check for special characters
  4315. if(bIsControlDown || bIsAltDown)
  4316. {
  4317. return FReply::Unhandled();
  4318. }
  4319. // Check for invalid characters
  4320. for(int InvalidCharIndex = 0; InvalidCharIndex < UE_ARRAY_COUNT(INVALID_OBJECTNAME_CHARACTERS) - 1; ++InvalidCharIndex)
  4321. {
  4322. if(InCharacter == INVALID_OBJECTNAME_CHARACTERS[InvalidCharIndex])
  4323. {
  4324. return FReply::Unhandled();
  4325. }
  4326. }
  4327. switch(InCharacter)
  4328. {
  4329. // Ignore some other special characters that we don't want to be entered into the buffer
  4330. case 0: // Any non-character key press, e.g. f1-f12, Delete, Pause/Break, etc.
  4331. // These should be explicitly not handled so that their input bindings are handled higher up the chain.
  4332. case 8: // Backspace
  4333. case 13: // Enter
  4334. case 27: // Esc
  4335. return FReply::Unhandled();
  4336. default:
  4337. break;
  4338. }
  4339. // Any other character!
  4340. if(!bTestOnly)
  4341. {
  4342. QuickJumpData.JumpTerm.AppendChar(InCharacter);
  4343. QuickJumpData.bHasChangedSinceLastTick = true;
  4344. }
  4345. return FReply::Handled();
  4346. }
  4347. bool SExtAssetView::PerformQuickJump(const bool bWasJumping)
  4348. {
  4349. auto GetAssetViewItemName = [](const TSharedPtr<FExtAssetViewItem> &Item) -> FString
  4350. {
  4351. switch(Item->GetType())
  4352. {
  4353. case EAssetItemType::Normal:
  4354. {
  4355. const TSharedPtr<FExtAssetViewAsset>& ItemAsAsset = StaticCastSharedPtr<FExtAssetViewAsset>(Item);
  4356. return ItemAsAsset->Data.AssetName.ToString();
  4357. }
  4358. case EAssetItemType::Folder:
  4359. {
  4360. const TSharedPtr<FAssetViewFolder>& ItemAsFolder = StaticCastSharedPtr<FAssetViewFolder>(Item);
  4361. return ItemAsFolder->FolderName.ToString();
  4362. }
  4363. default:
  4364. return FString();
  4365. }
  4366. };
  4367. auto JumpToNextMatch = [this, &GetAssetViewItemName](const int StartIndex, const int EndIndex) -> bool
  4368. {
  4369. check(StartIndex >= 0);
  4370. check(EndIndex <= FilteredAssetItems.Num());
  4371. for(int NewSelectedItemIndex = StartIndex; NewSelectedItemIndex < EndIndex; ++NewSelectedItemIndex)
  4372. {
  4373. TSharedPtr<FExtAssetViewItem>& NewSelectedItem = FilteredAssetItems[NewSelectedItemIndex];
  4374. const FString NewSelectedItemName = GetAssetViewItemName(NewSelectedItem);
  4375. if(NewSelectedItemName.StartsWith(QuickJumpData.JumpTerm, ESearchCase::IgnoreCase))
  4376. {
  4377. SetSelection(NewSelectedItem);
  4378. RequestScrollIntoView(NewSelectedItem);
  4379. return true;
  4380. }
  4381. }
  4382. return false;
  4383. };
  4384. TArray<TSharedPtr<FExtAssetViewItem>> SelectedItems = GetSelectedItems();
  4385. TSharedPtr<FExtAssetViewItem> SelectedItem = (SelectedItems.Num()) ? SelectedItems[0] : nullptr;
  4386. // If we have a selection, and we were already jumping, first check to see whether
  4387. // the current selection still matches the quick-jump term; if it does, we do nothing
  4388. if(bWasJumping && SelectedItem.IsValid())
  4389. {
  4390. const FString SelectedItemName = GetAssetViewItemName(SelectedItem);
  4391. if(SelectedItemName.StartsWith(QuickJumpData.JumpTerm, ESearchCase::IgnoreCase))
  4392. {
  4393. return true;
  4394. }
  4395. }
  4396. // We need to move on to the next match in FilteredAssetItems that starts with the given quick-jump term
  4397. const int SelectedItemIndex = (SelectedItem.IsValid()) ? FilteredAssetItems.Find(SelectedItem) : INDEX_NONE;
  4398. const int StartIndex = (SelectedItemIndex == INDEX_NONE) ? 0 : SelectedItemIndex + 1;
  4399. bool ValidMatch = JumpToNextMatch(StartIndex, FilteredAssetItems.Num());
  4400. if(!ValidMatch && StartIndex > 0)
  4401. {
  4402. // If we didn't find a match, we need to loop around and look again from the start (assuming we weren't already)
  4403. return JumpToNextMatch(0, StartIndex);
  4404. }
  4405. return ValidMatch;
  4406. }
  4407. #endif
  4408. void SExtAssetView::ToggleMajorAssetTypeColumns()
  4409. {
  4410. bShowMajorAssetTypeColumnsInColumnView = !bShowMajorAssetTypeColumnsInColumnView;
  4411. ColumnView->GetHeaderRow()->RefreshColumns();
  4412. ColumnView->RebuildList();
  4413. }
  4414. bool SExtAssetView::IsShowingMajorAssetTypeColumns() const
  4415. {
  4416. return bShowMajorAssetTypeColumnsInColumnView;
  4417. }
  4418. void SExtAssetView::FillToggleColumnsMenu(FMenuBuilder& MenuBuilder)
  4419. {
  4420. // Column view may not be valid if we toggled off columns view while the columns menu was open
  4421. if(ColumnView.IsValid())
  4422. {
  4423. const TIndirectArray<SHeaderRow::FColumn> Columns = ColumnView->GetHeaderRow()->GetColumns();
  4424. for (int32 ColumnIndex = 0; ColumnIndex < Columns.Num(); ++ColumnIndex)
  4425. {
  4426. const FString ColumnName = Columns[ColumnIndex].ColumnId.ToString();
  4427. MenuBuilder.AddMenuEntry(
  4428. Columns[ColumnIndex].DefaultText,
  4429. LOCTEXT("ShowHideColumnTooltip", "Show or hide column"),
  4430. FSlateIcon(),
  4431. FUIAction(
  4432. FExecuteAction::CreateSP(this, &SExtAssetView::ToggleColumn, ColumnName),
  4433. FCanExecuteAction::CreateSP(this, &SExtAssetView::CanToggleColumn, ColumnName),
  4434. FIsActionChecked::CreateSP(this, &SExtAssetView::IsColumnVisible, ColumnName),
  4435. EUIActionRepeatMode::RepeatEnabled
  4436. ),
  4437. NAME_None,
  4438. EUserInterfaceActionType::Check
  4439. );
  4440. }
  4441. }
  4442. }
  4443. void SExtAssetView::ResetColumns()
  4444. {
  4445. HiddenColumnNames.Empty();
  4446. NumVisibleColumns = ColumnView->GetHeaderRow()->GetColumns().Num();
  4447. ColumnView->GetHeaderRow()->RefreshColumns();
  4448. ColumnView->RebuildList();
  4449. }
  4450. void SExtAssetView::ExportColumns()
  4451. {
  4452. IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get();
  4453. const void* ParentWindowWindowHandle = FSlateApplication::Get().FindBestParentWindowHandleForDialogs(nullptr);
  4454. const FText Title = LOCTEXT("ExportToCSV", "Export columns as CSV...");
  4455. const FString FileTypes = TEXT("Data Table CSV (*.csv)|*.csv");
  4456. TArray<FString> OutFilenames;
  4457. DesktopPlatform->SaveFileDialog(
  4458. ParentWindowWindowHandle,
  4459. Title.ToString(),
  4460. TEXT(""),
  4461. TEXT("Report.csv"),
  4462. FileTypes,
  4463. EFileDialogFlags::None,
  4464. OutFilenames
  4465. );
  4466. if (OutFilenames.Num() > 0)
  4467. {
  4468. const TIndirectArray<SHeaderRow::FColumn>& Columns = ColumnView->GetHeaderRow()->GetColumns();
  4469. TArray<FName> ColumnNames;
  4470. for (const SHeaderRow::FColumn& Column : Columns)
  4471. {
  4472. ColumnNames.Add(Column.ColumnId);
  4473. }
  4474. FString SaveString;
  4475. SortManager.ExportColumnsToCSV(FilteredAssetItems, ColumnNames, CustomColumns, SaveString);
  4476. FFileHelper::SaveStringToFile(SaveString, *OutFilenames[0]);
  4477. }
  4478. }
  4479. void SExtAssetView::ToggleColumn(const FString ColumnName)
  4480. {
  4481. SetColumnVisibility(ColumnName, HiddenColumnNames.Contains(ColumnName));
  4482. }
  4483. void SExtAssetView::SetColumnVisibility(const FString ColumnName, const bool bShow)
  4484. {
  4485. if (!bShow)
  4486. {
  4487. --NumVisibleColumns;
  4488. HiddenColumnNames.Add(ColumnName);
  4489. }
  4490. else
  4491. {
  4492. ++NumVisibleColumns;
  4493. check(HiddenColumnNames.Contains(ColumnName));
  4494. HiddenColumnNames.Remove(ColumnName);
  4495. }
  4496. ColumnView->GetHeaderRow()->RefreshColumns();
  4497. ColumnView->RebuildList();
  4498. }
  4499. bool SExtAssetView::CanToggleColumn(const FString ColumnName) const
  4500. {
  4501. return (HiddenColumnNames.Contains(ColumnName) || NumVisibleColumns > 1);
  4502. }
  4503. bool SExtAssetView::IsColumnVisible(const FString ColumnName) const
  4504. {
  4505. const FName ColumnNameToCheck(*ColumnName);
  4506. const bool bAssetTypeSpecificColumns = ColumnNameToCheck != SortManager.NameColumnId
  4507. && ColumnNameToCheck != SortManager.ClassColumnId
  4508. && ColumnNameToCheck != SortManager.PathColumnId;
  4509. const bool bHideMajorAssetTypeColumns = !bShowMajorAssetTypeColumnsInColumnView && bAssetTypeSpecificColumns;
  4510. return !bHideMajorAssetTypeColumns && !HiddenColumnNames.Contains(ColumnName);
  4511. }
  4512. bool SExtAssetView::ShouldColumnGenerateWidget(const FString ColumnName) const
  4513. {
  4514. return IsColumnVisible(ColumnName);// !HiddenColumnNames.Contains(ColumnName);
  4515. }
  4516. TSharedRef<SWidget> SExtAssetView::CreateRowHeaderMenuContent(const FString ColumnName)
  4517. {
  4518. FMenuBuilder MenuBuilder(true, NULL);
  4519. MenuBuilder.AddMenuEntry(
  4520. LOCTEXT("HideColumn", "Hide Column"),
  4521. LOCTEXT("HideColumnToolTip", "Hides this column."),
  4522. FSlateIcon(),
  4523. FUIAction(FExecuteAction::CreateSP(this, &SExtAssetView::SetColumnVisibility, ColumnName, false), FCanExecuteAction::CreateSP(this, &SExtAssetView::CanToggleColumn, ColumnName)),
  4524. NAME_None,
  4525. EUserInterfaceActionType::Button);
  4526. return MenuBuilder.MakeWidget();
  4527. }
  4528. #undef LOCTEXT_NAMESPACE