Skip to content

Commit 26c98ce

Browse files
author
Roberto De Ioris
committed
added SPythonShelf
1 parent ace4295 commit 26c98ce

File tree

4 files changed

+179
-0
lines changed

4 files changed

+179
-0
lines changed
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
#if WITH_EDITOR
2+
3+
#include "UnrealEnginePythonPrivatePCH.h"
4+
5+
#include "UEPySPythonShelf.h"
6+
7+
#include "Editor/ContentBrowser/Public/ContentBrowserModule.h"
8+
#include "Editor/ContentBrowser/Public/IContentBrowserSingleton.h"
9+
10+
static PyObject *ue_PySPythonShelf_str(ue_PySPythonShelf *self)
11+
{
12+
return PyUnicode_FromFormat("<unreal_engine.SPythonShelf '%p'>",
13+
self->s_compound_widget.s_widget.s_widget);
14+
}
15+
16+
static PyMethodDef ue_PySPythonShelf_methods[] = {
17+
{ NULL } /* Sentinel */
18+
};
19+
20+
PyTypeObject ue_PySPythonShelfType = {
21+
PyVarObject_HEAD_INIT(NULL, 0)
22+
"unreal_engine.SPythonShelf", /* tp_name */
23+
sizeof(ue_PySPythonShelf), /* tp_basicsize */
24+
0, /* tp_itemsize */
25+
0, /* tp_dealloc */
26+
0, /* tp_print */
27+
0, /* tp_getattr */
28+
0, /* tp_setattr */
29+
0, /* tp_reserved */
30+
0, /* tp_repr */
31+
0, /* tp_as_number */
32+
0, /* tp_as_sequence */
33+
0, /* tp_as_mapping */
34+
0, /* tp_hash */
35+
0, /* tp_call */
36+
(reprfunc)ue_PySPythonShelf_str, /* tp_str */
37+
0, /* tp_getattro */
38+
0, /* tp_setattro */
39+
0, /* tp_as_buffer */
40+
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
41+
"Unreal Engine SPythonShelf", /* tp_doc */
42+
0, /* tp_traverse */
43+
0, /* tp_clear */
44+
0, /* tp_richcompare */
45+
0, /* tp_weaklistoffset */
46+
0, /* tp_iter */
47+
0, /* tp_iternext */
48+
ue_PySPythonShelf_methods, /* tp_methods */
49+
};
50+
51+
static int ue_py_spython_shelf_init(ue_PySPythonShelf *self, PyObject *args, PyObject *kwargs) {
52+
PyObject *py_classes_iterable = nullptr;
53+
PyObject *py_collections_iterable = nullptr;
54+
55+
PyObject *py_callable_double_clicked = nullptr;
56+
PyObject *py_callable_get_context_menu = nullptr;
57+
58+
char *kwlist[] = { (char *)"classes", (char *)"collections", (char *)"on_asset_double_clicked", (char *)"on_get_asset_context_menu", nullptr };
59+
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOOO", kwlist,
60+
&py_classes_iterable,
61+
&py_collections_iterable,
62+
&py_callable_double_clicked,
63+
&py_callable_get_context_menu)) {
64+
return -1;
65+
}
66+
67+
if (py_classes_iterable) {
68+
py_classes_iterable = PyObject_GetIter(py_classes_iterable);
69+
if (!py_classes_iterable) {
70+
PyErr_SetString(PyExc_Exception, "argument is not an iterable");
71+
return -1;
72+
}
73+
}
74+
75+
if (py_collections_iterable) {
76+
py_collections_iterable = PyObject_GetIter(py_collections_iterable);
77+
if (!py_collections_iterable) {
78+
PyErr_SetString(PyExc_Exception, "argument is not an iterable");
79+
return -1;
80+
}
81+
}
82+
83+
if (py_callable_double_clicked && !PyCallable_Check(py_callable_double_clicked)) {
84+
PyErr_SetString(PyExc_Exception, "argument is not callable");
85+
return -1;
86+
}
87+
88+
FContentBrowserModule& module = FModuleManager::Get().LoadModuleChecked<FContentBrowserModule>(TEXT("ContentBrowser"));
89+
90+
FAssetPickerConfig asset_picker_config;
91+
asset_picker_config.InitialAssetViewType = EAssetViewType::Tile;
92+
asset_picker_config.bAllowNullSelection = false;
93+
asset_picker_config.bShowBottomToolbar = false;
94+
asset_picker_config.bAutohideSearchBar = false;
95+
96+
if (py_classes_iterable) {
97+
while (PyObject *item = PyIter_Next(py_classes_iterable)) {
98+
if (PyUnicode_Check(item)) {
99+
FName class_name = FName(UTF8_TO_TCHAR(PyUnicode_AsUTF8(item)));
100+
asset_picker_config.Filter.ClassNames.Add(class_name);
101+
}
102+
}
103+
Py_DECREF(py_classes_iterable);
104+
}
105+
106+
if (py_collections_iterable) {
107+
while (PyObject *item = PyIter_Next(py_collections_iterable)) {
108+
if (PyUnicode_Check(item)) {
109+
FName collection_name = FName(UTF8_TO_TCHAR(PyUnicode_AsUTF8(item)));
110+
asset_picker_config.Collections.Add(FCollectionNameType(collection_name, ECollectionShareType::CST_Local));
111+
}
112+
}
113+
Py_DECREF(py_collections_iterable);
114+
}
115+
116+
if (py_callable_double_clicked) {
117+
FOnAssetDoubleClicked handler;
118+
UPythonSlateDelegate *py_delegate = NewObject<UPythonSlateDelegate>();
119+
py_delegate->SetPyCallable(py_callable_double_clicked);
120+
py_delegate->AddToRoot();
121+
handler.BindUObject(py_delegate, &UPythonSlateDelegate::OnAssetDoubleClicked);
122+
123+
asset_picker_config.OnAssetDoubleClicked = handler;
124+
}
125+
126+
127+
self->s_compound_widget.s_widget.s_widget_owned = module.Get().CreateAssetPicker(asset_picker_config);
128+
self->s_compound_widget.s_widget.s_widget = &self->s_compound_widget.s_widget.s_widget_owned.Get();
129+
return 0;
130+
}
131+
132+
void ue_python_init_spython_shelf(PyObject *ue_module) {
133+
ue_PySPythonShelfType.tp_new = PyType_GenericNew;
134+
135+
ue_PySPythonShelfType.tp_init = (initproc)ue_py_spython_shelf_init;
136+
137+
ue_PySPythonShelfType.tp_base = &ue_PySCompoundWidgetType;
138+
139+
if (PyType_Ready(&ue_PySPythonShelfType) < 0)
140+
return;
141+
142+
Py_INCREF(&ue_PySPythonShelfType);
143+
PyModule_AddObject(ue_module, "SPythonShelf", (PyObject *)&ue_PySPythonShelfType);
144+
}
145+
146+
147+
#endif
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#pragma once
2+
3+
#include "UnrealEnginePython.h"
4+
5+
#if WITH_EDITOR
6+
7+
#include "UEPySCompoundWidget.h"
8+
9+
extern PyTypeObject ue_PySPythonShelfType;
10+
11+
typedef struct {
12+
ue_PySCompoundWidget s_compound_widget;
13+
/* Type-specific fields go here. */
14+
} ue_PySPythonShelf;
15+
16+
void ue_python_init_spython_shelf(PyObject *);
17+
18+
#endif

Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,16 @@ FReply UPythonSlateDelegate::OnClicked() {
4545
return FReply::Handled();
4646
}
4747

48+
void UPythonSlateDelegate::OnAssetDoubleClicked(const FAssetData& AssetData) {
49+
FScopePythonGIL gil;
50+
51+
PyObject *ret = PyObject_CallFunction(py_callable, (char *)"O", py_ue_new_fassetdata((FAssetData *)&AssetData));
52+
if (!ret) {
53+
unreal_engine_py_log_error();
54+
}
55+
Py_XDECREF(ret);
56+
}
57+
4858
TSharedRef<SDockTab> UPythonSlateDelegate::SpawnPythonTab(const FSpawnTabArgs &args) {
4959
TSharedRef<SDockTab> dock_tab = SNew(SDockTab).TabRole(ETabRole::NomadTab);
5060
PyObject *py_dock = (PyObject *)ue_py_get_swidget(dock_tab);
@@ -129,6 +139,7 @@ void ue_python_init_slate(PyObject *module) {
129139
ue_python_init_spython_list_view(module);
130140
ue_python_init_ssplitter(module);
131141
ue_python_init_sheader_row(module);
142+
ue_python_init_spython_shelf(module);
132143

133144
ue_python_init_ftab_spawner_entry(module);
134145
}

Source/UnrealEnginePython/Private/Slate/UEPySlate.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "UEPySPythonListView.h"
3838
#include "UEPySSplitter.h"
3939
#include "UEPySHeaderRow.h"
40+
#include "UEPySPythonShelf.h"
4041

4142
#include "UEPyFTabSpawnerEntry.h"
4243

@@ -83,6 +84,8 @@ class UPythonSlateDelegate : public UPythonDelegate
8384
TSharedRef<SDockTab> SpawnPythonTab(const FSpawnTabArgs& args);
8485

8586
TSharedRef<ITableRow> GenerateWidgetForList(TSharedPtr<PyObject> InItem, const TSharedRef<STableViewBase>& OwnerTable);
87+
88+
void OnAssetDoubleClicked(const FAssetData& AssetData);
8689
};
8790

8891
#endif

0 commit comments

Comments
 (0)