[Window] Add unfiltered input handler signal for custom decorations.
This commit is contained in:
@ -691,6 +691,9 @@
|
||||
[b]Note:[/b] On Windows, the portion of a window that lies outside the region is not drawn, while on Linux (X11) and macOS it is.
|
||||
[b]Note:[/b] This property is implemented on Linux (X11), macOS and Windows.
|
||||
</member>
|
||||
<member name="nonclient_area" type="Rect2i" setter="set_nonclient_area" getter="get_nonclient_area" default="Rect2i(0, 0, 0, 0)">
|
||||
If set, defines the window's custom decoration area which will receive mouse input, even if normal input to the window is blocked (such as when it has an exclusive child opened). See also [signal nonclient_window_input].
|
||||
</member>
|
||||
<member name="popup_window" type="bool" setter="set_flag" getter="get_flag" default="false">
|
||||
If [code]true[/code], the [Window] will be considered a popup. Popups are sub-windows that don't show as separate windows in system's window manager's window list and will send close request when anything is clicked outside of them (unless [member exclusive] is enabled).
|
||||
</member>
|
||||
@ -803,6 +806,12 @@
|
||||
Emitted when the mouse cursor leaves the [Window]'s visible area, that is not occluded behind other [Control]s or windows, provided its [member Viewport.gui_disable_input] is [code]false[/code] and regardless if it's currently focused or not.
|
||||
</description>
|
||||
</signal>
|
||||
<signal name="nonclient_window_input">
|
||||
<param index="0" name="event" type="InputEvent" />
|
||||
<description>
|
||||
Emitted when the mouse event is received by the custom decoration area defined by [member nonclient_area], and normal input to the window is blocked (such as when it has an exclusive child opened). [param event]'s position is in the embedder's coordinate system.
|
||||
</description>
|
||||
</signal>
|
||||
<signal name="theme_changed">
|
||||
<description>
|
||||
Emitted when the [constant NOTIFICATION_THEME_CHANGED] notification is sent.
|
||||
|
||||
@ -89,57 +89,71 @@ Control *EditorTitleBar::get_center_control() const {
|
||||
}
|
||||
|
||||
void EditorTitleBar::_notification(int p_what) {
|
||||
if (!center_control || p_what != NOTIFICATION_SORT_CHILDREN) {
|
||||
return;
|
||||
}
|
||||
|
||||
Control *prev = nullptr;
|
||||
Control *base = nullptr;
|
||||
Control *next = nullptr;
|
||||
|
||||
bool rtl = is_layout_rtl();
|
||||
|
||||
int start;
|
||||
int end;
|
||||
int delta;
|
||||
if (rtl) {
|
||||
start = get_child_count() - 1;
|
||||
end = -1;
|
||||
delta = -1;
|
||||
} else {
|
||||
start = 0;
|
||||
end = get_child_count();
|
||||
delta = +1;
|
||||
}
|
||||
|
||||
for (int i = start; i != end; i += delta) {
|
||||
Control *c = as_sortable_control(get_child(i));
|
||||
if (!c) {
|
||||
continue;
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_EXIT_TREE: {
|
||||
SceneTree::get_singleton()->get_root()->disconnect(SceneStringName(nonclient_window_input), callable_mp(this, &EditorTitleBar::gui_input));
|
||||
get_window()->set_nonclient_area(Rect2i());
|
||||
} break;
|
||||
case NOTIFICATION_ENTER_TREE: {
|
||||
SceneTree::get_singleton()->get_root()->connect(SceneStringName(nonclient_window_input), callable_mp(this, &EditorTitleBar::gui_input));
|
||||
[[fallthrough]];
|
||||
}
|
||||
if (base) {
|
||||
next = c;
|
||||
break;
|
||||
}
|
||||
if (c != center_control) {
|
||||
prev = c;
|
||||
continue;
|
||||
}
|
||||
base = c;
|
||||
}
|
||||
if (base && prev && next) {
|
||||
Size2i title_size = get_size();
|
||||
Size2i c_size = base->get_combined_minimum_size();
|
||||
case NOTIFICATION_RESIZED: {
|
||||
get_window()->set_nonclient_area(get_global_transform().xform(Rect2i(get_position(), get_size())));
|
||||
} break;
|
||||
case NOTIFICATION_SORT_CHILDREN: {
|
||||
if (!center_control) {
|
||||
break;
|
||||
}
|
||||
Control *prev = nullptr;
|
||||
Control *base = nullptr;
|
||||
Control *next = nullptr;
|
||||
|
||||
int min_offset = prev->get_position().x + prev->get_combined_minimum_size().x;
|
||||
int max_offset = next->get_position().x + next->get_size().x - next->get_combined_minimum_size().x - c_size.x;
|
||||
bool rtl = is_layout_rtl();
|
||||
|
||||
int offset = (title_size.width - c_size.width) / 2;
|
||||
offset = CLAMP(offset, min_offset, max_offset);
|
||||
int start;
|
||||
int end;
|
||||
int delta;
|
||||
if (rtl) {
|
||||
start = get_child_count() - 1;
|
||||
end = -1;
|
||||
delta = -1;
|
||||
} else {
|
||||
start = 0;
|
||||
end = get_child_count();
|
||||
delta = +1;
|
||||
}
|
||||
|
||||
fit_child_in_rect(prev, Rect2i(prev->get_position().x, 0, offset - prev->get_position().x, title_size.height));
|
||||
fit_child_in_rect(base, Rect2i(offset, 0, c_size.width, title_size.height));
|
||||
fit_child_in_rect(next, Rect2i(offset + c_size.width, 0, next->get_position().x + next->get_size().x - (offset + c_size.width), title_size.height));
|
||||
for (int i = start; i != end; i += delta) {
|
||||
Control *c = as_sortable_control(get_child(i));
|
||||
if (!c) {
|
||||
continue;
|
||||
}
|
||||
if (base) {
|
||||
next = c;
|
||||
break;
|
||||
}
|
||||
if (c != center_control) {
|
||||
prev = c;
|
||||
continue;
|
||||
}
|
||||
base = c;
|
||||
}
|
||||
if (base && prev && next) {
|
||||
Size2i title_size = get_size();
|
||||
Size2i c_size = base->get_combined_minimum_size();
|
||||
|
||||
int min_offset = prev->get_position().x + prev->get_combined_minimum_size().x;
|
||||
int max_offset = next->get_position().x + next->get_size().x - next->get_combined_minimum_size().x - c_size.x;
|
||||
|
||||
int offset = (title_size.width - c_size.width) / 2;
|
||||
offset = CLAMP(offset, min_offset, max_offset);
|
||||
|
||||
fit_child_in_rect(prev, Rect2i(prev->get_position().x, 0, offset - prev->get_position().x, title_size.height));
|
||||
fit_child_in_rect(base, Rect2i(offset, 0, c_size.width, title_size.height));
|
||||
fit_child_in_rect(next, Rect2i(offset + c_size.width, 0, next->get_position().x + next->get_size().x - (offset + c_size.width), title_size.height));
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1726,6 +1726,15 @@ real_t Window::get_content_scale_factor() const {
|
||||
return content_scale_factor;
|
||||
}
|
||||
|
||||
void Window::set_nonclient_area(const Rect2i &p_rect) {
|
||||
ERR_MAIN_THREAD_GUARD;
|
||||
nonclient_area = p_rect;
|
||||
}
|
||||
|
||||
Rect2i Window::get_nonclient_area() const {
|
||||
return nonclient_area;
|
||||
}
|
||||
|
||||
DisplayServer::WindowID Window::get_window_id() const {
|
||||
ERR_READ_THREAD_GUARD_V(DisplayServer::INVALID_WINDOW_ID);
|
||||
if (get_embedder()) {
|
||||
@ -1816,6 +1825,12 @@ void Window::_window_input(const Ref<InputEvent> &p_ev) {
|
||||
ERR_MAIN_THREAD_GUARD;
|
||||
|
||||
if (exclusive_child != nullptr) {
|
||||
if (nonclient_area.has_area() && is_inside_tree()) {
|
||||
Ref<InputEventMouse> me = p_ev;
|
||||
if (me.is_valid() && nonclient_area.has_point(me->get_position())) {
|
||||
emit_signal(SceneStringName(nonclient_window_input), p_ev);
|
||||
}
|
||||
}
|
||||
if (!is_embedding_subwindows()) { // Not embedding, no need for event.
|
||||
return;
|
||||
}
|
||||
@ -3227,6 +3242,9 @@ void Window::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_content_scale_stretch", "stretch"), &Window::set_content_scale_stretch);
|
||||
ClassDB::bind_method(D_METHOD("get_content_scale_stretch"), &Window::get_content_scale_stretch);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_nonclient_area", "area"), &Window::set_nonclient_area);
|
||||
ClassDB::bind_method(D_METHOD("get_nonclient_area"), &Window::get_nonclient_area);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_keep_title_visible", "title_visible"), &Window::set_keep_title_visible);
|
||||
ClassDB::bind_method(D_METHOD("get_keep_title_visible"), &Window::get_keep_title_visible);
|
||||
|
||||
@ -3331,6 +3349,7 @@ void Window::_bind_methods() {
|
||||
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "position", PROPERTY_HINT_NONE, "suffix:px"), "set_position", "get_position");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "size", PROPERTY_HINT_NONE, "suffix:px"), "set_size", "get_size");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "current_screen", PROPERTY_HINT_RANGE, "0,64,1,or_greater"), "set_current_screen", "get_current_screen");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::RECT2I, "nonclient_area", PROPERTY_HINT_NONE, ""), "set_nonclient_area", "get_nonclient_area");
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "mouse_passthrough_polygon"), "set_mouse_passthrough_polygon", "get_mouse_passthrough_polygon");
|
||||
|
||||
@ -3380,6 +3399,7 @@ void Window::_bind_methods() {
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "theme_type_variation", PROPERTY_HINT_ENUM_SUGGESTION), "set_theme_type_variation", "get_theme_type_variation");
|
||||
|
||||
ADD_SIGNAL(MethodInfo("window_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
|
||||
ADD_SIGNAL(MethodInfo("nonclient_window_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
|
||||
ADD_SIGNAL(MethodInfo("files_dropped", PropertyInfo(Variant::PACKED_STRING_ARRAY, "files")));
|
||||
ADD_SIGNAL(MethodInfo("mouse_entered"));
|
||||
ADD_SIGNAL(MethodInfo("mouse_exited"));
|
||||
|
||||
@ -171,6 +171,8 @@ private:
|
||||
|
||||
Size2i max_size_used;
|
||||
|
||||
Rect2i nonclient_area;
|
||||
|
||||
Size2i _clamp_limit_size(const Size2i &p_limit_size);
|
||||
Size2i _clamp_window_size(const Size2i &p_size);
|
||||
void _validate_limit_size();
|
||||
@ -391,6 +393,9 @@ public:
|
||||
void set_content_scale_factor(real_t p_factor);
|
||||
real_t get_content_scale_factor() const;
|
||||
|
||||
void set_nonclient_area(const Rect2i &p_rect);
|
||||
Rect2i get_nonclient_area() const;
|
||||
|
||||
void set_mouse_passthrough_polygon(const Vector<Vector2> &p_region);
|
||||
Vector<Vector2> get_mouse_passthrough_polygon() const;
|
||||
|
||||
|
||||
@ -53,6 +53,7 @@ public:
|
||||
const StringName input_event = "input_event";
|
||||
const StringName gui_input = "gui_input";
|
||||
const StringName window_input = "window_input";
|
||||
const StringName nonclient_window_input = "nonclient_window_input";
|
||||
|
||||
const StringName tree_entered = "tree_entered";
|
||||
const StringName tree_exiting = "tree_exiting";
|
||||
|
||||
Reference in New Issue
Block a user