Skip to content

Commit e6edbff

Browse files
author
Roberto De Ioris
committed
added combobox and rotator slate widget
1 parent ded156b commit e6edbff

File tree

6 files changed

+313
-0
lines changed

6 files changed

+313
-0
lines changed
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
2+
#include "UnrealEnginePythonPrivatePCH.h"
3+
4+
#include "UEPySPythonComboBox.h"
5+
6+
7+
#define sw_python_combo_box StaticCastSharedRef<SPythonComboBox>(self->s_panel.s_widget.s_widget)
8+
9+
static PyObject *py_ue_spython_combo_box_clear_selection(ue_PySPythonComboBox *self, PyObject * args) {
10+
sw_python_combo_box->ClearSelection();
11+
Py_INCREF(self);
12+
return (PyObject *)self;
13+
}
14+
15+
static PyObject *py_ue_spython_combo_box_get_selected_item(ue_PySPythonComboBox *self, PyObject * args) {
16+
17+
TSharedPtr<FPythonItem> ptr_item = sw_python_combo_box->GetSelectedItem();
18+
if (!ptr_item.IsValid())
19+
return PyErr_Format(PyExc_Exception, "invalid shared pointer to python item");
20+
21+
Py_INCREF(ptr_item.Get()->py_object);
22+
return ptr_item.Get()->py_object;
23+
}
24+
25+
static PyObject *py_ue_spython_combo_box_set_selected_item(ue_PySPythonComboBox *self, PyObject * args) {
26+
PyObject *py_item;
27+
if (!PyArg_ParseTuple(args, "O", &py_item)) {
28+
return nullptr;
29+
}
30+
31+
for (TSharedPtr<FPythonItem> item : *(sw_python_combo_box->PythonOptionsSource)) {
32+
// just for being safe
33+
if (!item.IsValid())
34+
continue;
35+
if (py_item == item.Get()->py_object) {
36+
sw_python_combo_box->SetSelectedItem(item);
37+
break;
38+
}
39+
}
40+
41+
Py_INCREF(self);
42+
return (PyObject *)self;
43+
}
44+
45+
static PyMethodDef ue_PySPythonComboBox_methods[] = {
46+
{ "clear_selection", (PyCFunction)py_ue_spython_combo_box_clear_selection, METH_VARARGS, "" },
47+
{ "get_selected_item", (PyCFunction)py_ue_spython_combo_box_get_selected_item, METH_VARARGS, "" },
48+
{ "set_selected_item", (PyCFunction)py_ue_spython_combo_box_set_selected_item, METH_VARARGS, "" },
49+
{ NULL } /* Sentinel */
50+
};
51+
52+
PyTypeObject ue_PySPythonComboBoxType = {
53+
PyVarObject_HEAD_INIT(NULL, 0)
54+
"unreal_engine.SPythonComboBox", /* tp_name */
55+
sizeof(ue_PySPythonComboBox), /* tp_basicsize */
56+
0, /* tp_itemsize */
57+
0, /* tp_dealloc */
58+
0, /* tp_print */
59+
0, /* tp_getattr */
60+
0, /* tp_setattr */
61+
0, /* tp_reserved */
62+
0, /* tp_repr */
63+
0, /* tp_as_number */
64+
0, /* tp_as_sequence */
65+
0, /* tp_as_mapping */
66+
0, /* tp_hash */
67+
0, /* tp_call */
68+
0, /* tp_str */
69+
0, /* tp_getattro */
70+
0, /* tp_setattro */
71+
0, /* tp_as_buffer */
72+
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
73+
"Unreal Engine SPythonComboBox", /* tp_doc */
74+
0, /* tp_traverse */
75+
0, /* tp_clear */
76+
0, /* tp_richcompare */
77+
0, /* tp_weaklistoffset */
78+
0, /* tp_iter */
79+
0, /* tp_iternext */
80+
ue_PySPythonComboBox_methods, /* tp_methods */
81+
};
82+
83+
static int ue_py_spython_combo_box_init(ue_PySPythonComboBox *self, PyObject *args, PyObject *kwargs) {
84+
ue_py_slate_setup_farguments(SPythonComboBox);
85+
86+
// first of all check for values
87+
PyObject *values = ue_py_dict_get_item(kwargs, "values");
88+
if (!values) {
89+
PyErr_SetString(PyExc_Exception, "you must specify the combo box items");
90+
return -1;
91+
}
92+
93+
values = PyObject_GetIter(values);
94+
if (!values) {
95+
PyErr_SetString(PyExc_Exception, "values field is not an iterable");
96+
return -1;
97+
}
98+
99+
TArray<TSharedPtr<FPythonItem>> *items = new TArray<TSharedPtr<FPythonItem>>();
100+
while (PyObject *item = PyIter_Next(values)) {
101+
Py_INCREF(item);
102+
// keep track of items
103+
self->s_panel.s_widget.py_refs.Add(item);
104+
items->Add(TSharedPtr<FPythonItem>(new FPythonItem(item)));
105+
}
106+
Py_DECREF(values);
107+
108+
arguments.OptionsSource(items);
109+
110+
ue_PySWidget *s_widget_content = nullptr;
111+
112+
PyObject *content = ue_py_dict_get_item(kwargs, "content");
113+
if (content) {
114+
s_widget_content = py_ue_is_swidget(content);
115+
if (!content) {
116+
PyErr_SetString(PyExc_Exception, "content is not a SWidget");
117+
return -1;
118+
}
119+
Py_INCREF(s_widget_content);
120+
arguments.Content()[s_widget_content->s_widget];
121+
}
122+
123+
ue_py_slate_farguments_optional_struct_ptr("button_style", ButtonStyle, FButtonStyle);
124+
ue_py_slate_farguments_struct("content_padding", ContentPadding, FMargin);
125+
ue_py_slate_farguments_optional_bool("enable_gamepad_navigation_mode", EnableGamepadNavigationMode);
126+
ue_py_slate_farguments_struct("foreground_color", ForegroundColor, FSlateColor);
127+
ue_py_slate_farguments_optional_bool("has_down_arrow", HasDownArrow);
128+
ue_py_slate_farguments_optional_struct_ptr("item_style", ItemStyle, FTableRowStyle);
129+
ue_py_slate_farguments_optional_float("max_list_height", MaxListHeight);
130+
ue_py_slate_farguments_optional_enum("method", Method, EPopupMethod);
131+
ue_py_slate_farguments_optional_struct("pressed_sound_override", PressedSoundOverride, FSlateSound);
132+
ue_py_slate_farguments_optional_struct("pressed_sound_override", PressedSoundOverride, FSlateSound);
133+
ue_py_slate_farguments_event("on_generate_widget", OnGenerateWidget, TSlateDelegates<TSharedPtr<FPythonItem>>::FOnGenerateWidget, OnGenerateWidget);
134+
ue_py_slate_farguments_event("on_selection_changed", OnSelectionChanged, TSlateDelegates<TSharedPtr<FPythonItem>>::FOnSelectionChanged, OnSelectionChanged);
135+
136+
137+
ue_py_snew(SPythonComboBox, s_panel.s_widget);
138+
139+
// keep track of the list, so we can delete on destruction
140+
sw_python_combo_box->PythonOptionsSource = items;
141+
142+
// eventually track the content
143+
self->s_panel.s_widget.py_swidget_content = s_widget_content;
144+
145+
return 0;
146+
}
147+
148+
void ue_python_init_spython_combo_box(PyObject *ue_module) {
149+
150+
ue_PySPythonComboBoxType.tp_base = &ue_PySPanelType;
151+
ue_PySPythonComboBoxType.tp_init = (initproc)ue_py_spython_combo_box_init;
152+
153+
if (PyType_Ready(&ue_PySPythonComboBoxType) < 0)
154+
return;
155+
156+
Py_INCREF(&ue_PySPythonComboBoxType);
157+
PyModule_AddObject(ue_module, "SPythonComboBox", (PyObject *)&ue_PySPythonComboBoxType);
158+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#pragma once
2+
3+
#include "UnrealEnginePython.h"
4+
5+
#include "UEPySPanel.h"
6+
7+
#include "Runtime/Slate/Public/Widgets/Input/SComboBox.h"
8+
9+
extern PyTypeObject ue_PySPythonComboBoxType;
10+
11+
class SPythonComboBox : public SComboBox<TSharedPtr<FPythonItem>> {
12+
public:
13+
~SPythonComboBox() {
14+
if (PythonOptionsSource)
15+
delete(PythonOptionsSource);
16+
}
17+
18+
const TArray<TSharedPtr<FPythonItem>> *PythonOptionsSource;
19+
};
20+
21+
typedef struct {
22+
ue_PySPanel s_panel;
23+
/* Type-specific fields go here. */
24+
} ue_PySPythonComboBox;
25+
26+
void ue_python_init_spython_combo_box(PyObject *);
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#include "UnrealEnginePythonPrivatePCH.h"
2+
3+
#include "UEPySRotatorInputBox.h"
4+
5+
#define sw_rotator_input_box StaticCastSharedRef<SRotatorInputBox>(self->s_compound_widget.s_widget.s_widget)
6+
7+
8+
static PyMethodDef ue_PySRotatorInputBox_methods[] = {
9+
{ NULL } /* Sentinel */
10+
};
11+
12+
PyTypeObject ue_PySRotatorInputBoxType = {
13+
PyVarObject_HEAD_INIT(NULL, 0)
14+
"unreal_engine.SRotatorInputBox", /* tp_name */
15+
sizeof(ue_PySRotatorInputBox), /* tp_basicsize */
16+
0, /* tp_itemsize */
17+
0, /* tp_dealloc */
18+
0, /* tp_print */
19+
0, /* tp_getattr */
20+
0, /* tp_setattr */
21+
0, /* tp_reserved */
22+
0, /* tp_repr */
23+
0, /* tp_as_number */
24+
0, /* tp_as_sequence */
25+
0, /* tp_as_mapping */
26+
0, /* tp_hash */
27+
0, /* tp_call */
28+
0, /* tp_str */
29+
0, /* tp_getattro */
30+
0, /* tp_setattro */
31+
0, /* tp_as_buffer */
32+
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
33+
"Unreal Engine SRotatorInputBox", /* tp_doc */
34+
0, /* tp_traverse */
35+
0, /* tp_clear */
36+
0, /* tp_richcompare */
37+
0, /* tp_weaklistoffset */
38+
0, /* tp_iter */
39+
0, /* tp_iternext */
40+
ue_PySRotatorInputBox_methods, /* tp_methods */
41+
};
42+
43+
static int ue_py_srotator_input_box_init(ue_PySRotatorInputBox *self, PyObject *args, PyObject *kwargs) {
44+
ue_py_slate_setup_farguments(SRotatorInputBox);
45+
46+
ue_py_slate_farguments_optional_bool("allow_responsive_layout", AllowResponsiveLayout);
47+
ue_py_slate_farguments_optional_bool("color_axis_labels", bColorAxisLabels);
48+
ue_py_slate_farguments_optional_bool("allow_spin", AllowSpin);
49+
ue_py_slate_farguments_struct("font", Font, FSlateFontInfo);
50+
ue_py_slate_farguments_event("on_roll_changed", OnRollChanged, FOnFloatValueChanged, OnFloatChanged);
51+
ue_py_slate_farguments_event("on_pitch_changed", OnPitchChanged, FOnFloatValueChanged, OnFloatChanged);
52+
ue_py_slate_farguments_event("on_yaw_changed", OnYawChanged, FOnFloatValueChanged, OnFloatChanged);
53+
ue_py_slate_farguments_event("on_roll_committed", OnRollCommitted, FOnFloatValueCommitted, OnFloatCommitted);
54+
ue_py_slate_farguments_event("on_pitch_committed", OnPitchCommitted, FOnFloatValueCommitted, OnFloatCommitted);
55+
ue_py_slate_farguments_event("on_yaw_committed", OnYawCommitted, FOnFloatValueCommitted, OnFloatCommitted);
56+
ue_py_slate_farguments_tfloat("roll", Roll);
57+
ue_py_slate_farguments_tfloat("pitch", Pitch);
58+
ue_py_slate_farguments_tfloat("yaw", Yaw);
59+
60+
ue_py_snew(SRotatorInputBox, s_compound_widget.s_widget);
61+
return 0;
62+
}
63+
64+
void ue_python_init_srotator_input_box(PyObject *ue_module) {
65+
66+
ue_PySRotatorInputBoxType.tp_init = (initproc)ue_py_srotator_input_box_init;
67+
68+
ue_PySRotatorInputBoxType.tp_base = &ue_PySCompoundWidgetType;
69+
70+
if (PyType_Ready(&ue_PySRotatorInputBoxType) < 0)
71+
return;
72+
73+
Py_INCREF(&ue_PySRotatorInputBoxType);
74+
PyModule_AddObject(ue_module, "SRotatorInputBox", (PyObject *)&ue_PySRotatorInputBoxType);
75+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#pragma once
2+
3+
#include "UnrealEnginePython.h"
4+
5+
6+
#include "UEPySCompoundWidget.h"
7+
8+
#include "Runtime/Slate/Public/Widgets/Input/SRotatorInputBox.h"
9+
10+
extern PyTypeObject ue_PySRotatorInputBoxType;
11+
12+
typedef struct {
13+
ue_PySCompoundWidget s_compound_widget;
14+
/* Type-specific fields go here. */
15+
} ue_PySRotatorInputBox;
16+
17+
void ue_python_init_srotator_input_box(PyObject *);

Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,37 @@ TSharedPtr<SWidget> UPythonSlateDelegate::OnGetAssetContextMenu(const TArray<FAs
179179
}
180180
#endif
181181

182+
TSharedRef<SWidget> UPythonSlateDelegate::OnGenerateWidget(TSharedPtr<FPythonItem> py_item) {
183+
FScopePythonGIL gil;
184+
185+
PyObject *ret = PyObject_CallFunction(py_callable, (char *)"O", py_item.Get()->py_object);
186+
if (!ret) {
187+
unreal_engine_py_log_error();
188+
return SNullWidget::NullWidget;
189+
}
190+
191+
ue_PySWidget *s_widget = py_ue_is_swidget(ret);
192+
if (!s_widget) {
193+
Py_DECREF(ret);
194+
UE_LOG(LogPython, Error, TEXT("returned value is not a SWidget"));
195+
return SNullWidget::NullWidget;
196+
}
197+
TSharedRef<SWidget> value = s_widget->s_widget;
198+
Py_DECREF(ret);
199+
return value;
200+
}
201+
202+
void UPythonSlateDelegate::OnSelectionChanged(TSharedPtr<FPythonItem> py_item, ESelectInfo::Type select_type) {
203+
FScopePythonGIL gil;
204+
205+
PyObject *ret = PyObject_CallFunction(py_callable, (char *)"Oi", py_item.Get()->py_object, (int)select_type);
206+
if (!ret) {
207+
unreal_engine_py_log_error();
208+
return;
209+
}
210+
Py_DECREF(ret);
211+
}
212+
182213
TSharedPtr<SWidget> UPythonSlateDelegate::OnContextMenuOpening() {
183214
FScopePythonGIL gil;
184215

@@ -530,6 +561,8 @@ void ue_python_init_slate(PyObject *module) {
530561
ue_python_init_scanvas(module);
531562
ue_python_init_sslider(module);
532563
ue_python_init_svector_input_box(module);
564+
ue_python_init_srotator_input_box(module);
565+
ue_python_init_spython_combo_box(module);
533566

534567

535568
#if WITH_EDITOR

Source/UnrealEnginePython/Private/Slate/UEPySlate.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@
4646
#include "UEPySCanvas.h"
4747
#include "UEPySSlider.h"
4848
#include "UEPySVectorInputBox.h"
49+
#include "UEPySRotatorInputBox.h"
50+
#include "UEPySPythonComboBox.h"
4951

5052

5153

@@ -388,6 +390,8 @@ class UPythonSlateDelegate : public UPythonDelegate
388390
#endif
389391

390392
TSharedPtr<SWidget> OnContextMenuOpening();
393+
TSharedRef<SWidget> OnGenerateWidget(TSharedPtr<FPythonItem> py_item);
394+
void OnSelectionChanged(TSharedPtr<FPythonItem> py_item, ESelectInfo::Type select_type);
391395

392396
void SimpleExecuteAction();
393397
void ExecuteAction(PyObject *py_obj);

0 commit comments

Comments
 (0)