Skip to content

Commit c0df16e

Browse files
authored
Added "Create Script..." option to "Add Component..." ItemPicker (#771)
1 parent 135bf7a commit c0df16e

12 files changed

Lines changed: 197 additions & 56 deletions

File tree

Sources/OvCore/include/OvCore/Helpers/GUIHelpers.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ namespace OvCore::Helpers
3535
std::string tooltip;
3636
uint32_t iconID = 0;
3737
std::function<void()> onSelected;
38+
bool alwaysVisible = false;
3839
};
3940

4041
class PickerItemList
@@ -60,6 +61,7 @@ namespace OvCore::Helpers
6061
using FileItemBuilderCallback = std::function<PickerItemList(OvTools::Utils::PathParser::EFileType, std::function<void(std::string)>, bool, bool)>;
6162
using OpenProviderCallback = std::function<void(const std::string&)>;
6263
using PickerProviderCallback = std::function<void(PickerItemList, std::string)>;
64+
using PickerSearchTextProviderCallback = std::function<std::string()>;
6365
using IconProviderCallback = std::function<uint32_t(OvTools::Utils::PathParser::EFileType)>;
6466
using ActorSelectionProviderCallback = std::function<void(uint64_t)>;
6567
using AssetExistsCallback = std::function<bool(const std::string&)>;
@@ -85,6 +87,9 @@ namespace OvCore::Helpers
8587
static void SetPickerProvider(PickerProviderCallback p_provider);
8688
static void OpenPicker(PickerItemList p_items, std::string p_title);
8789

90+
static void SetPickerSearchTextProvider(PickerSearchTextProviderCallback p_provider);
91+
static std::string GetPickerSearchText();
92+
8893
static void SetActorIconID(uint32_t p_id);
8994
static uint32_t GetActorIconID();
9095

Sources/OvCore/src/OvCore/Helpers/GUIHelpers.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ namespace
1313
OvRendering::Resources::Texture* __EMPTY_TEXTURE = nullptr;
1414
OvCore::Helpers::GUIHelpers::FileItemBuilderCallback __FILE_ITEM_BUILDER;
1515
OvCore::Helpers::GUIHelpers::PickerProviderCallback __PICKER_PROVIDER;
16+
OvCore::Helpers::GUIHelpers::PickerSearchTextProviderCallback __PICKER_SEARCH_TEXT_PROVIDER;
1617
OvCore::Helpers::GUIHelpers::IconProviderCallback __ICON_PROVIDER;
1718
OvCore::Helpers::GUIHelpers::OpenProviderCallback __OPEN_PROVIDER;
1819
OvCore::Helpers::GUIHelpers::ActorSelectionProviderCallback __ACTOR_SELECTION_PROVIDER;
@@ -103,6 +104,16 @@ void OvCore::Helpers::GUIHelpers::OpenPicker(PickerItemList p_items, std::string
103104
__PICKER_PROVIDER(std::move(p_items), std::move(p_title));
104105
}
105106

107+
void OvCore::Helpers::GUIHelpers::SetPickerSearchTextProvider(PickerSearchTextProviderCallback p_provider)
108+
{
109+
__PICKER_SEARCH_TEXT_PROVIDER = std::move(p_provider);
110+
}
111+
112+
std::string OvCore::Helpers::GUIHelpers::GetPickerSearchText()
113+
{
114+
return __PICKER_SEARCH_TEXT_PROVIDER ? __PICKER_SEARCH_TEXT_PROVIDER() : "";
115+
}
116+
106117
void OvCore::Helpers::GUIHelpers::SetActorIconID(uint32_t p_id)
107118
{
108119
__ACTOR_ICON_ID = p_id;

Sources/OvEditor/include/OvEditor/Core/EditorActions.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,14 @@ namespace OvEditor::Core
311311
*/
312312
bool ImportAsset(const std::string& p_initialDestinationDirectory);
313313

314+
/**
315+
* Open a save dialog to create a new script file at a user-chosen location.
316+
* Returns the absolute path of the created script, or empty on cancellation.
317+
* @param p_initialDirectory Directory the dialog opens in
318+
* @param p_initialName Suggested filename (without extension)
319+
*/
320+
std::string CreateScript(const std::string& p_initialDirectory, const std::string& p_initialName);
321+
314322
/**
315323
* Import an asset at location
316324
* @param p_destination

Sources/OvEditor/include/OvEditor/Helpers/PickerHelpers.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,14 @@ namespace OvEditor::Helpers::PickerHelpers
2424
* @param p_onSelected Called with the resource path when the item is selected
2525
* @param p_searchProject Include project assets
2626
* @param p_searchEngine Include engine assets
27+
* @param p_filter Optional predicate; return false to exclude an item (receives resource path)
2728
*/
2829
void AddFileItems(
2930
OvCore::Helpers::GUIHelpers::PickerItemList& p_list,
3031
OvTools::Utils::PathParser::EFileType p_fileType,
3132
std::function<void(std::string)> p_onSelected,
3233
bool p_searchProject = true,
33-
bool p_searchEngine = true
34+
bool p_searchEngine = true,
35+
std::function<bool(const std::string&)> p_filter = {}
3436
);
3537
}

Sources/OvEditor/include/OvEditor/Panels/ItemPicker.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ namespace OvEditor::Panels
4747
*/
4848
void Open(OvCore::Helpers::GUIHelpers::PickerItemList p_items, std::string p_title);
4949

50+
/**
51+
* Returns the current text in the search field.
52+
*/
53+
std::string GetSearchText() const;
54+
5055
private:
5156
void _Draw_Impl() override;
5257
void Populate();
@@ -65,7 +70,13 @@ namespace OvEditor::Panels
6570
OvUI::Widgets::InputFields::InputText* m_searchField = nullptr;
6671
OvUI::Widgets::Layout::Group* m_listGroup = nullptr;
6772

68-
/* Each entry: (search key, row widget) */
69-
std::vector<std::pair<std::string, OvUI::Widgets::Layout::Group*>> m_rows;
73+
/* Each entry: search key, always-visible flag, and row widget */
74+
struct RowEntry
75+
{
76+
std::string key;
77+
bool alwaysVisible;
78+
OvUI::Widgets::Layout::Group* widget;
79+
};
80+
std::vector<RowEntry> m_rows;
7081
};
7182
}

Sources/OvEditor/src/OvEditor/Core/Editor.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ void OvEditor::Core::Editor::SetupUI()
7676
}
7777
);
7878

79+
OvCore::Helpers::GUIHelpers::SetPickerSearchTextProvider(
80+
[this]() { return m_itemPicker->GetSearchText(); }
81+
);
82+
7983
OvCore::Helpers::GUIHelpers::SetIconProvider(
8084
[this](OvTools::Utils::PathParser::EFileType p_fileType) -> uint32_t {
8185
auto* texture = m_context.editorResources->GetTexture(OvTools::Utils::PathParser::FileTypeToString(p_fileType));

Sources/OvEditor/src/OvEditor/Core/EditorActions.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <OvEditor/Core/EditorActions.h>
3232
#include <OvEditor/Core/GizmoBehaviour.h>
3333
#include <OvEditor/Helpers/PickerHelpers.h>
34+
#include <OvEditor/Panels/AssetBrowser.h>
3435
#include <OvEditor/Panels/AssetView.h>
3536
#include <OvEditor/Panels/GameView.h>
3637
#include <OvEditor/Panels/Inspector.h>
@@ -1101,6 +1102,42 @@ bool OvEditor::Core::EditorActions::ImportAsset(const std::string& p_initialDest
11011102
return false;
11021103
}
11031104

1105+
std::string OvEditor::Core::EditorActions::CreateScript(const std::string& p_initialDirectory, const std::string& p_initialName)
1106+
{
1107+
using namespace OvWindowing::Dialogs;
1108+
1109+
const std::string extension = m_context.scriptEngine->GetDefaultExtension();
1110+
1111+
SaveFileDialog dialog("Create Script");
1112+
dialog.SetInitialDirectory(p_initialDirectory);
1113+
dialog.SetInitialFilename(p_initialName);
1114+
dialog.DefineExtension("Script", extension);
1115+
dialog.Show(
1116+
EExplorerFlags::DONTADDTORECENT |
1117+
EExplorerFlags::PATHMUSTEXIST |
1118+
EExplorerFlags::HIDEREADONLY |
1119+
EExplorerFlags::NOCHANGEDIR
1120+
);
1121+
1122+
if (!dialog.HasSucceeded())
1123+
return {};
1124+
1125+
const std::string destination = dialog.GetSelectedFilePath();
1126+
1127+
if (!std::filesystem::exists(destination))
1128+
{
1129+
const std::string scriptName = std::filesystem::path{ destination }.stem().string();
1130+
const std::string fileContent = m_context.scriptEngine->GetDefaultScriptContent(scriptName);
1131+
1132+
std::ofstream outfile(destination);
1133+
outfile << fileContent << std::endl;
1134+
1135+
EDITOR_PANEL(Panels::AssetBrowser, "Asset Browser").Refresh();
1136+
}
1137+
1138+
return destination;
1139+
}
1140+
11041141
bool OvEditor::Core::EditorActions::ImportAssetAtLocation(const std::string& p_destination)
11051142
{
11061143
using namespace OvWindowing::Dialogs;

Sources/OvEditor/src/OvEditor/Helpers/PickerHelpers.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ namespace
1919
const std::filesystem::path& p_directory,
2020
bool p_isEngine,
2121
PathParser::EFileType p_fileType,
22-
const std::function<void(std::string)>& p_onSelected)
22+
const std::function<void(std::string)>& p_onSelected,
23+
const std::function<bool(const std::string&)>& p_filter)
2324
{
2425
if (!std::filesystem::exists(p_directory))
2526
return;
@@ -41,6 +42,10 @@ namespace
4142
continue;
4243

4344
const std::string resourcePath = EDITOR_EXEC(GetResourcePath(path, p_isEngine));
45+
46+
if (p_filter && !p_filter(resourcePath))
47+
continue;
48+
4449
const std::string filename = PathParser::GetElementName(resourcePath);
4550
const std::string friendlyPath = PathParser::GetFriendlyPath(resourcePath);
4651
const uint32_t iconID = EDITOR_CONTEXT(editorResources)->GetFileIcon(path)->GetTexture().GetID();
@@ -61,11 +66,12 @@ void OvEditor::Helpers::PickerHelpers::AddFileItems(
6166
PathParser::EFileType p_fileType,
6267
std::function<void(std::string)> p_onSelected,
6368
bool p_searchProject,
64-
bool p_searchEngine)
69+
bool p_searchEngine,
70+
std::function<bool(const std::string&)> p_filter)
6571
{
6672
if (p_searchProject)
67-
CollectFromDirectory(p_list, EDITOR_CONTEXT(projectAssetsPath), false, p_fileType, p_onSelected);
73+
CollectFromDirectory(p_list, EDITOR_CONTEXT(projectAssetsPath), false, p_fileType, p_onSelected, p_filter);
6874

6975
if (p_searchEngine)
70-
CollectFromDirectory(p_list, EDITOR_CONTEXT(engineAssetsPath), true, p_fileType, p_onSelected);
76+
CollectFromDirectory(p_list, EDITOR_CONTEXT(engineAssetsPath), true, p_fileType, p_onSelected, p_filter);
7177
}

Sources/OvEditor/src/OvEditor/Panels/Inspector.cpp

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ void OvEditor::Panels::Inspector::_DrawAddSection()
250250
return;
251251

252252
const uint32_t componentIconID = EDITOR_CONTEXT(editorResources)->GetTexture("Component")->GetTexture().GetID();
253+
const uint32_t scriptIconID = EDITOR_CONTEXT(editorResources)->GetTexture("Script")->GetTexture().GetID();
253254

254255
OvCore::Helpers::GUIHelpers::PickerItemList items;
255256

@@ -307,9 +308,48 @@ void OvEditor::Panels::Inspector::_DrawAddSection()
307308

308309
m_targetActor->AddBehaviour(scriptPath);
309310
},
310-
true, false
311+
true, false,
312+
[this](const std::string& p_resourcePath) {
313+
const std::string scriptPath = EDITOR_EXEC(GetScriptPath(p_resourcePath));
314+
return !m_targetActor->GetBehaviour(scriptPath);
315+
}
311316
);
312317

318+
items.Add({
319+
"Create Script...",
320+
"Create Script...",
321+
"Create Script...",
322+
scriptIconID,
323+
[this] {
324+
if (!m_targetActor.has_value())
325+
return;
326+
327+
const std::string searchText = OvCore::Helpers::GUIHelpers::GetPickerSearchText();
328+
const std::string initialDir = EDITOR_CONTEXT(projectAssetsPath).string();
329+
const std::string destination = EDITOR_EXEC(CreateScript(initialDir, searchText));
330+
331+
if (destination.empty())
332+
return;
333+
334+
const std::string scriptPath = EDITOR_EXEC(GetScriptPath(destination));
335+
const std::string displayName = OvTools::Utils::PathParser::GetElementName(scriptPath);
336+
337+
if (m_targetActor->GetBehaviour(scriptPath))
338+
{
339+
OvWindowing::Dialogs::MessageBox(
340+
"Script already attached",
341+
"The script \"" + displayName + "\" is already attached to this actor.",
342+
OvWindowing::Dialogs::MessageBox::EMessageType::ERROR,
343+
OvWindowing::Dialogs::MessageBox::EButtonLayout::OK
344+
);
345+
return;
346+
}
347+
348+
m_targetActor->AddBehaviour(scriptPath);
349+
},
350+
true /* alwaysVisible */
351+
});
352+
313353
OvCore::Helpers::GUIHelpers::OpenPicker(std::move(items), "Add Component");
314354
};
315355
}

Sources/OvEditor/src/OvEditor/Panels/ItemPicker.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ void ItemPicker::_Draw_Impl()
8484
const auto& items = m_items.Items();
8585
for (size_t i = 0; i < m_rows.size() && i < items.size(); ++i)
8686
{
87-
if (m_rows[i].second->enabled)
87+
if (m_rows[i].widget->enabled)
8888
{
8989
items[i].onSelected();
9090
Close();
@@ -164,12 +164,17 @@ void ItemPicker::Populate()
164164
Close();
165165
};
166166

167-
m_rows.emplace_back(item.key, &row);
167+
m_rows.emplace_back(item.key, item.alwaysVisible, &row);
168168
}
169169
}
170170

171171
void ItemPicker::FilterList(const std::string& p_search)
172172
{
173-
for (auto& [key, row] : m_rows)
174-
row->enabled = ContainsCaseInsensitive(key, p_search);
173+
for (auto& entry : m_rows)
174+
entry.widget->enabled = entry.alwaysVisible || ContainsCaseInsensitive(entry.key, p_search);
175+
}
176+
177+
std::string ItemPicker::GetSearchText() const
178+
{
179+
return m_searchField ? m_searchField->content : "";
175180
}

0 commit comments

Comments
 (0)