Skip to content

Commit 25acd00

Browse files
author
Roberto De Ioris
committed
improved input system for slate
1 parent be32fea commit 25acd00

9 files changed

Lines changed: 312 additions & 3 deletions

File tree

‎Source/UnrealEnginePython/Private/PyUserWidget.cpp‎

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,82 @@ FReply UPyUserWidget::NativeOnMouseButtonDown(const FGeometry & InGeometry, cons
127127
if (!PyObject_HasAttrString(py_user_widget_instance, (char *)"on_mouse_button_down"))
128128
return FReply::Unhandled();
129129

130-
PyObject *ret = PyObject_CallMethod(py_user_widget_instance, (char *)"on_mouse_button_down", (char *)"OO", py_ue_new_fgeometry(InGeometry), py_ue_new_uscriptstruct(FPointerEvent::StaticStruct(), (uint8 *)&InMouseEvent));
130+
PyObject *ret = PyObject_CallMethod(py_user_widget_instance, (char *)"on_mouse_button_down", (char *)"OO", py_ue_new_fgeometry(InGeometry), py_ue_new_fpointer_event(InMouseEvent));
131+
if (!ret) {
132+
unreal_engine_py_log_error();
133+
return FReply::Unhandled();
134+
}
135+
if (PyObject_IsTrue(ret)) {
136+
Py_DECREF(ret);
137+
return FReply::Handled();
138+
}
139+
Py_DECREF(ret);
140+
return FReply::Unhandled();
141+
}
142+
143+
FReply UPyUserWidget::NativeOnMouseButtonUp(const FGeometry & InGeometry, const FPointerEvent & InMouseEvent)
144+
{
145+
Super::NativeOnMouseButtonUp(InGeometry, InMouseEvent);
146+
147+
if (!py_user_widget_instance)
148+
return FReply::Unhandled();
149+
150+
FScopePythonGIL gil;
151+
152+
if (!PyObject_HasAttrString(py_user_widget_instance, (char *)"on_mouse_button_up"))
153+
return FReply::Unhandled();
154+
155+
PyObject *ret = PyObject_CallMethod(py_user_widget_instance, (char *)"on_mouse_button_up", (char *)"OO", py_ue_new_fgeometry(InGeometry), py_ue_new_fpointer_event(InMouseEvent));
156+
if (!ret) {
157+
unreal_engine_py_log_error();
158+
return FReply::Unhandled();
159+
}
160+
if (PyObject_IsTrue(ret)) {
161+
Py_DECREF(ret);
162+
return FReply::Handled();
163+
}
164+
Py_DECREF(ret);
165+
return FReply::Unhandled();
166+
}
167+
168+
FReply UPyUserWidget::NativeOnMouseWheel(const FGeometry & InGeometry, const FPointerEvent & InMouseEvent)
169+
{
170+
Super::NativeOnMouseWheel(InGeometry, InMouseEvent);
171+
172+
if (!py_user_widget_instance)
173+
return FReply::Unhandled();
174+
175+
FScopePythonGIL gil;
176+
177+
if (!PyObject_HasAttrString(py_user_widget_instance, (char *)"on_mouse_wheel"))
178+
return FReply::Unhandled();
179+
180+
PyObject *ret = PyObject_CallMethod(py_user_widget_instance, (char *)"on_mouse_wheel", (char *)"OO", py_ue_new_fgeometry(InGeometry), py_ue_new_fpointer_event(InMouseEvent));
181+
if (!ret) {
182+
unreal_engine_py_log_error();
183+
return FReply::Unhandled();
184+
}
185+
if (PyObject_IsTrue(ret)) {
186+
Py_DECREF(ret);
187+
return FReply::Handled();
188+
}
189+
Py_DECREF(ret);
190+
return FReply::Unhandled();
191+
}
192+
193+
FReply UPyUserWidget::NativeOnMouseMove(const FGeometry & InGeometry, const FPointerEvent & InMouseEvent)
194+
{
195+
Super::NativeOnMouseMove(InGeometry, InMouseEvent);
196+
197+
if (!py_user_widget_instance)
198+
return FReply::Unhandled();
199+
200+
FScopePythonGIL gil;
201+
202+
if (!PyObject_HasAttrString(py_user_widget_instance, (char *)"on_mouse_move"))
203+
return FReply::Unhandled();
204+
205+
PyObject *ret = PyObject_CallMethod(py_user_widget_instance, (char *)"on_mouse_move", (char *)"OO", py_ue_new_fgeometry(InGeometry), py_ue_new_fpointer_event(InMouseEvent));
131206
if (!ret) {
132207
unreal_engine_py_log_error();
133208
return FReply::Unhandled();

‎Source/UnrealEnginePython/Private/Slate/UEPyFGeometry.cpp‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,18 @@ static PyObject *py_ue_fgeometry_get_local_size(ue_PyFGeometry *self, PyObject *
77
return Py_BuildValue("(ff)", size.X, size.Y);
88
}
99

10+
static PyObject *py_ue_fgeometry_absolute_to_local(ue_PyFGeometry *self, PyObject * args) {
11+
float x, y;
12+
if (!PyArg_ParseTuple(args, "(ff)", &x, &y))
13+
return nullptr;
14+
FVector2D absolute(x, y);
15+
FVector2D local = self->geometry.AbsoluteToLocal(absolute);
16+
return Py_BuildValue((char *)"(ff)", local.X, local.Y);
17+
}
18+
1019
static PyMethodDef ue_PyFGeometry_methods[] = {
1120
{ "get_local_size", (PyCFunction)py_ue_fgeometry_get_local_size, METH_VARARGS, "" },
21+
{ "absolute_to_local", (PyCFunction)py_ue_fgeometry_absolute_to_local, METH_VARARGS, "" },
1222
{ NULL } /* Sentinel */
1323
};
1424

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
#include "UnrealEnginePythonPrivatePCH.h"
2+
3+
#include "UEPyFInputEvent.h"
4+
5+
static PyObject *py_ue_finput_event_to_text(ue_PyFInputEvent *self, PyObject * args) {
6+
return PyUnicode_FromString(TCHAR_TO_UTF8(*self->input.ToText().ToString()));
7+
}
8+
9+
static PyObject *py_ue_finput_event_get_user_index(ue_PyFInputEvent *self, PyObject * args) {
10+
return PyLong_FromUnsignedLong(self->input.GetUserIndex());
11+
}
12+
13+
static PyObject *py_ue_finput_event_is_alt_down(ue_PyFInputEvent *self, PyObject * args) {
14+
if (self->input.IsAltDown())
15+
Py_RETURN_TRUE;
16+
Py_RETURN_FALSE;
17+
}
18+
19+
static PyObject *py_ue_finput_event_is_command_down(ue_PyFInputEvent *self, PyObject * args) {
20+
if (self->input.IsCommandDown())
21+
Py_RETURN_TRUE;
22+
Py_RETURN_FALSE;
23+
}
24+
25+
static PyObject *py_ue_finput_event_is_control_down(ue_PyFInputEvent *self, PyObject * args) {
26+
if (self->input.IsControlDown())
27+
Py_RETURN_TRUE;
28+
Py_RETURN_FALSE;
29+
}
30+
31+
static PyMethodDef ue_PyFInputEvent_methods[] = {
32+
{ "to_text", (PyCFunction)py_ue_finput_event_to_text, METH_VARARGS, "" },
33+
{ "get_user_index", (PyCFunction)py_ue_finput_event_get_user_index, METH_VARARGS, "" },
34+
{ "is_alt_down", (PyCFunction)py_ue_finput_event_is_alt_down, METH_VARARGS, "" },
35+
{ "is_command_down", (PyCFunction)py_ue_finput_event_is_command_down, METH_VARARGS, "" },
36+
{ "is_control_down", (PyCFunction)py_ue_finput_event_is_control_down, METH_VARARGS, "" },
37+
{ NULL } /* Sentinel */
38+
};
39+
40+
static PyObject *ue_PyFInputEvent_str(ue_PyFInputEvent *self)
41+
{
42+
return PyUnicode_FromFormat("<unreal_engine.FInputEvent '%s'>",
43+
TCHAR_TO_UTF8(*self->input.ToText().ToString()));
44+
}
45+
46+
PyTypeObject ue_PyFInputEventType = {
47+
PyVarObject_HEAD_INIT(NULL, 0)
48+
"unreal_engine.FInputEvent", /* tp_name */
49+
sizeof(ue_PyFInputEvent), /* tp_basicsize */
50+
0, /* tp_itemsize */
51+
0, /* tp_dealloc */
52+
0, /* tp_print */
53+
0, /* tp_getattr */
54+
0, /* tp_setattr */
55+
0, /* tp_reserved */
56+
0, /* tp_repr */
57+
0, /* tp_as_number */
58+
0, /* tp_as_sequence */
59+
0, /* tp_as_mapping */
60+
0, /* tp_hash */
61+
0, /* tp_call */
62+
(reprfunc)ue_PyFInputEvent_str, /* tp_str */
63+
0, /* tp_getattro */
64+
0, /* tp_setattro */
65+
0, /* tp_as_buffer */
66+
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
67+
"Unreal Engine FInputEvent", /* tp_doc */
68+
0, /* tp_traverse */
69+
0, /* tp_clear */
70+
0, /* tp_richcompare */
71+
0, /* tp_weaklistoffset */
72+
0, /* tp_iter */
73+
0, /* tp_iternext */
74+
ue_PyFInputEvent_methods, /* tp_methods */
75+
};
76+
77+
void ue_python_init_finput_event(PyObject *ue_module) {
78+
ue_PyFInputEventType.tp_new = PyType_GenericNew;
79+
80+
if (PyType_Ready(&ue_PyFInputEventType) < 0)
81+
return;
82+
83+
Py_INCREF(&ue_PyFInputEventType);
84+
PyModule_AddObject(ue_module, "FInputEvent", (PyObject *)&ue_PyFInputEventType);
85+
}
86+
87+
PyObject *py_ue_new_finput_event(FInputEvent input) {
88+
ue_PyFInputEvent *ret = (ue_PyFInputEvent *)PyObject_New(ue_PyFInputEvent, &ue_PyFInputEventType);
89+
new(&ret->input) FInputEvent(input);
90+
return (PyObject *)ret;
91+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#pragma once
2+
3+
#include "UnrealEnginePython.h"
4+
5+
#include "Runtime/SlateCore/Public/Input/Events.h"
6+
7+
typedef struct {
8+
PyObject_HEAD
9+
/* Type-specific fields go here. */
10+
FInputEvent input;
11+
} ue_PyFInputEvent;
12+
13+
void ue_python_init_finput_event(PyObject *);
14+
15+
PyObject *py_ue_new_finput_event(FInputEvent);
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
#include "UnrealEnginePythonPrivatePCH.h"
2+
3+
#include "UEPyFPointerEvent.h"
4+
5+
static PyObject *py_ue_fpointer_event_get_effecting_button(ue_PyFPointerEvent *self, PyObject * args) {
6+
FKey key = self->pointer.GetEffectingButton();
7+
return py_ue_new_uscriptstruct(FKey::StaticStruct(), (uint8*)&key);
8+
}
9+
10+
static PyObject *py_ue_fpointer_event_get_effecting_button_name(ue_PyFPointerEvent *self, PyObject * args) {
11+
FKey key = self->pointer.GetEffectingButton();
12+
return PyUnicode_FromString(TCHAR_TO_UTF8(*key.ToString()));
13+
}
14+
15+
static PyObject *py_ue_fpointer_event_get_wheel_delta(ue_PyFPointerEvent *self, PyObject * args) {
16+
float delta = self->pointer.GetWheelDelta();
17+
return PyFloat_FromDouble(delta);
18+
}
19+
20+
static PyObject *py_ue_fpointer_event_get_cursor_delta(ue_PyFPointerEvent *self, PyObject * args) {
21+
FVector2D delta = self->pointer.GetCursorDelta();
22+
return Py_BuildValue((char *)"(ff)", delta.X, delta.Y);
23+
}
24+
25+
static PyObject *py_ue_fpointer_event_get_screen_space_position(ue_PyFPointerEvent *self, PyObject * args) {
26+
FVector2D pos = self->pointer.GetScreenSpacePosition();
27+
return Py_BuildValue((char *)"(ff)", pos.X, pos.Y);
28+
}
29+
30+
static PyMethodDef ue_PyFPointerEvent_methods[] = {
31+
{ "get_effecting_button", (PyCFunction)py_ue_fpointer_event_get_effecting_button, METH_VARARGS, "" },
32+
{ "get_effecting_button_name", (PyCFunction)py_ue_fpointer_event_get_effecting_button_name, METH_VARARGS, "" },
33+
{ "get_wheel_delta", (PyCFunction)py_ue_fpointer_event_get_wheel_delta, METH_VARARGS, "" },
34+
{ "get_cursor_delta", (PyCFunction)py_ue_fpointer_event_get_cursor_delta, METH_VARARGS, "" },
35+
{ "get_screen_space_position", (PyCFunction)py_ue_fpointer_event_get_screen_space_position, METH_VARARGS, "" },
36+
{ NULL } /* Sentinel */
37+
};
38+
39+
static PyObject *ue_PyFPointerEvent_str(ue_PyFPointerEvent *self)
40+
{
41+
return PyUnicode_FromFormat("<unreal_engine.FPointerEvent '%s'>",
42+
TCHAR_TO_UTF8(*self->pointer.ToText().ToString()));
43+
}
44+
45+
static PyTypeObject ue_PyFPointerEventType = {
46+
PyVarObject_HEAD_INIT(NULL, 0)
47+
"unreal_engine.FPointerEvent", /* tp_name */
48+
sizeof(ue_PyFPointerEvent), /* tp_basicsize */
49+
0, /* tp_itemsize */
50+
0, /* tp_dealloc */
51+
0, /* tp_print */
52+
0, /* tp_getattr */
53+
0, /* tp_setattr */
54+
0, /* tp_reserved */
55+
0, /* tp_repr */
56+
0, /* tp_as_number */
57+
0, /* tp_as_sequence */
58+
0, /* tp_as_mapping */
59+
0, /* tp_hash */
60+
0, /* tp_call */
61+
(reprfunc)ue_PyFPointerEvent_str, /* tp_str */
62+
0, /* tp_getattro */
63+
0, /* tp_setattro */
64+
0, /* tp_as_buffer */
65+
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
66+
"Unreal Engine FPointerEvent", /* tp_doc */
67+
0, /* tp_traverse */
68+
0, /* tp_clear */
69+
0, /* tp_richcompare */
70+
0, /* tp_weaklistoffset */
71+
0, /* tp_iter */
72+
0, /* tp_iternext */
73+
ue_PyFPointerEvent_methods, /* tp_methods */
74+
};
75+
76+
void ue_python_init_fpointer_event(PyObject *ue_module) {
77+
78+
ue_PyFPointerEventType.tp_base = &ue_PyFInputEventType;
79+
80+
if (PyType_Ready(&ue_PyFPointerEventType) < 0)
81+
return;
82+
83+
Py_INCREF(&ue_PyFPointerEventType);
84+
PyModule_AddObject(ue_module, "FPointerEvent", (PyObject *)&ue_PyFPointerEventType);
85+
}
86+
87+
PyObject *py_ue_new_fpointer_event(FPointerEvent pointer) {
88+
ue_PyFPointerEvent *ret = (ue_PyFPointerEvent *)PyObject_New(ue_PyFPointerEvent, &ue_PyFPointerEventType);
89+
new(&ret->pointer) FPointerEvent(pointer);
90+
new(&ret->f_input.input) FInputEvent(pointer);
91+
return (PyObject *)ret;
92+
}
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+
#include "UEPyFInputEvent.h"
6+
7+
extern PyTypeObject ue_PyFInputEventType;
8+
9+
typedef struct {
10+
/* Type-specific fields go here. */
11+
ue_PyFInputEvent f_input;
12+
FPointerEvent pointer;
13+
} ue_PyFPointerEvent;
14+
15+
void ue_python_init_fpointer_event(PyObject *);
16+
17+
PyObject *py_ue_new_fpointer_event(FPointerEvent);

‎Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
FReply UPythonSlateDelegate::OnMouseEvent(const FGeometry &geometry, const FPointerEvent &pointer_event) {
2929
FScopePythonGIL gil;
3030

31-
PyObject *ret = PyObject_CallFunction(py_callable, (char *)"OO", py_ue_new_uscriptstruct(FGeometry::StaticStruct(), (uint8 *)&geometry), py_ue_new_uscriptstruct(FPointerEvent::StaticStruct(), (uint8 *)&pointer_event));
31+
PyObject *ret = PyObject_CallFunction(py_callable, (char *)"OO", py_ue_new_uscriptstruct(FGeometry::StaticStruct(), (uint8 *)&geometry), py_ue_new_fpointer_event(pointer_event));
3232
if (!ret) {
3333
unreal_engine_py_log_error();
3434
return FReply::Unhandled();
@@ -655,6 +655,9 @@ void ue_python_init_slate(PyObject *module) {
655655

656656
ue_python_init_fgeometry(module);
657657
ue_python_init_fpaint_context(module);
658+
659+
ue_python_init_finput_event(module);
660+
ue_python_init_fpointer_event(module);
658661
}
659662

660663
PyObject *ue_py_dict_get_item(PyObject *dict, const char *key) {

‎Source/UnrealEnginePython/Private/Slate/UEPySlate.h‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@
6767
#include "UEPyFGeometry.h"
6868
#include "UEPyFPaintContext.h"
6969

70+
#include "UEPyFInputEvent.h"
71+
#include "UEPyFPointerEvent.h"
72+
7073
#if WITH_EDITOR
7174
#include "UEPySEditorViewport.h"
7275
#include "UEPySLevelViewport.h"

‎Source/UnrealEnginePython/Public/PyUserWidget.h‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ class UPyUserWidget : public UUserWidget
2525

2626
virtual bool NativeIsInteractable() const override;
2727

28-
virtual FReply NativeOnMouseButtonDown(const FGeometry & InGeometry, const FPointerEvent & InMouseEvent);
28+
virtual FReply NativeOnMouseButtonDown(const FGeometry & InGeometry, const FPointerEvent & InMouseEvent) override;
29+
virtual FReply NativeOnMouseButtonUp(const FGeometry & InGeometry, const FPointerEvent & InMouseEvent) override;
30+
virtual FReply NativeOnMouseWheel(const FGeometry & InGeometry, const FPointerEvent & InMouseEvent) override;
31+
virtual FReply NativeOnMouseMove(const FGeometry & InGeometry, const FPointerEvent & InMouseEvent) override;
2932

3033
UPROPERTY(EditAnywhere, Category = "Python", BlueprintReadWrite, meta = (ExposeOnSpawn = true))
3134
FString PythonModule;

0 commit comments

Comments
 (0)