mirror of
https://github.com/Relintai/pandemonium_engine.git
synced 2024-12-22 03:46:50 +01:00
Backported the shortcut context system from godot4.
This commit is contained in:
parent
bd9abfc160
commit
4637f73099
@ -773,6 +773,14 @@
|
||||
<member name="rect_size" type="Vector2" setter="_set_size" getter="get_size" default="Vector2( 0, 0 )">
|
||||
The size of the node's bounding rectangle, in pixels. [Container] nodes update this property automatically.
|
||||
</member>
|
||||
<member name="shortcut_context" type="Node" setter="set_shortcut_context" getter="get_shortcut_context">
|
||||
The [Node] which must be a parent of the focused [Control] for the shortcut to be activated. If [code]null[/code], the shortcut can be activated when any control is focused (a global shortcut). This allows shortcuts to be accepted only when the user has a certain area of the GUI focused.
|
||||
Setting this will override the node [member shortcut_context_path] is pointing. You can get rid of this override by setting this back to null.
|
||||
</member>
|
||||
<member name="shortcut_context_path" type="NodePath" setter="set_shortcut_context_path" getter="get_shortcut_context_path">
|
||||
The [NodePath] for the [Node] which must be a parent of the focused [Control] for the shortcut to be activated. If [code]null[/code], the shortcut can be activated when any control is focused (a global shortcut). This allows shortcuts to be accepted only when the user has a certain area of the GUI focused.
|
||||
[member shortcut_context] can be used to temporarily override this when needed.
|
||||
</member>
|
||||
<member name="size_flags_horizontal" type="int" setter="set_h_size_flags" getter="get_h_size_flags" default="1">
|
||||
Tells the parent [Container] nodes how they should resize and place the node on the X axis. Use one of the [enum SizeFlags] constants to change the flags. See the constants to learn what each does.
|
||||
</member>
|
||||
|
@ -2503,6 +2503,68 @@ void Control::warp_mouse(const Point2 &p_to_pos) {
|
||||
get_viewport()->warp_mouse(get_global_transform().xform(p_to_pos));
|
||||
}
|
||||
|
||||
void Control::set_shortcut_context(const Node *p_node) {
|
||||
if (p_node != nullptr) {
|
||||
data.shortcut_context = p_node->get_instance_id();
|
||||
} else {
|
||||
data.shortcut_context = ObjectID();
|
||||
}
|
||||
}
|
||||
|
||||
Node *Control::get_shortcut_context() const {
|
||||
if (unlikely(data.shortcut_context)) {
|
||||
Object *ctx_obj = ObjectDB::get_instance(data.shortcut_context);
|
||||
Node *ctx_node = Object::cast_to<Node>(ctx_obj);
|
||||
|
||||
return ctx_node;
|
||||
}
|
||||
|
||||
if (likely(data.shortcut_context_path.is_empty())) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (data.shortcut_context_path_cache) {
|
||||
Object *ctx_obj = ObjectDB::get_instance(data.shortcut_context_path_cache);
|
||||
|
||||
if (ctx_obj) {
|
||||
Node *ctx_node = Object::cast_to<Node>(ctx_obj);
|
||||
|
||||
return ctx_node;
|
||||
} else {
|
||||
data.shortcut_context_path_cache = ObjectID();
|
||||
}
|
||||
}
|
||||
|
||||
Node *n = get_node_or_null(data.shortcut_context_path);
|
||||
|
||||
if (n) {
|
||||
data.shortcut_context_path_cache = n->get_instance_id();
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void Control::set_shortcut_context_path(const NodePath &p_node_path) {
|
||||
data.shortcut_context_path = p_node_path;
|
||||
data.shortcut_context_path_cache = 0;
|
||||
}
|
||||
NodePath Control::get_shortcut_context_path() const {
|
||||
return data.shortcut_context_path;
|
||||
}
|
||||
|
||||
bool Control::is_focus_owner_in_shortcut_context() const {
|
||||
if (data.shortcut_context == ObjectID()) {
|
||||
// No context, therefore global - always "in" context.
|
||||
return true;
|
||||
}
|
||||
|
||||
const Node *ctx_node = get_shortcut_context();
|
||||
const Control *vp_focus = get_viewport() ? get_viewport()->_gui_get_focus_owner() : NULL;
|
||||
|
||||
// If the context is valid and the viewport focus is valid, check if the context is the focus or is a parent of it.
|
||||
return ctx_node && vp_focus && (ctx_node == vp_focus || ctx_node->is_a_parent_of(vp_focus));
|
||||
}
|
||||
|
||||
bool Control::is_text_field() const {
|
||||
return false;
|
||||
}
|
||||
@ -2817,6 +2879,12 @@ void Control::_bind_methods() {
|
||||
|
||||
ClassDB::bind_method(D_METHOD("warp_mouse", "to_position"), &Control::warp_mouse);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_shortcut_context", "node"), &Control::set_shortcut_context);
|
||||
ClassDB::bind_method(D_METHOD("get_shortcut_context"), &Control::get_shortcut_context);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_shortcut_context_path", "path"), &Control::set_shortcut_context_path);
|
||||
ClassDB::bind_method(D_METHOD("get_shortcut_context_path"), &Control::get_shortcut_context_path);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("minimum_size_changed"), &Control::minimum_size_changed);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("_theme_changed"), &Control::_theme_changed);
|
||||
@ -2881,6 +2949,8 @@ void Control::_bind_methods() {
|
||||
|
||||
ADD_GROUP("Input", "input_");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "input_pass_on_modal_close_click"), "set_pass_on_modal_close_click", "get_pass_on_modal_close_click");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "shortcut_context_path"), "set_shortcut_context_path", "get_shortcut_context_path");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut_context", PROPERTY_HINT_NONE, "", 0), "set_shortcut_context", "get_shortcut_context");
|
||||
|
||||
ADD_GROUP("Size Flags", "size_flags_");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "size_flags_horizontal", PROPERTY_HINT_FLAGS, "Fill,Expand,Shrink Center,Shrink End"), "set_h_size_flags", "get_h_size_flags");
|
||||
@ -3007,7 +3077,9 @@ Control::Control() {
|
||||
data.margin[i] = 0;
|
||||
}
|
||||
data.focus_mode = FOCUS_NONE;
|
||||
data.modal_prev_focus_owner = 0;
|
||||
data.modal_prev_focus_owner = ObjectID();
|
||||
data.shortcut_context = ObjectID();
|
||||
data.shortcut_context_path_cache = ObjectID();
|
||||
|
||||
set_physics_interpolation_mode(Node::PHYSICS_INTERPOLATION_MODE_OFF);
|
||||
}
|
||||
|
@ -199,6 +199,10 @@ private:
|
||||
NodePath focus_next;
|
||||
NodePath focus_prev;
|
||||
|
||||
ObjectID shortcut_context;
|
||||
NodePath shortcut_context_path;
|
||||
mutable ObjectID shortcut_context_path_cache;
|
||||
|
||||
HashMap<StringName, Ref<Texture>> icon_override;
|
||||
HashMap<StringName, Ref<Shader>> shader_override;
|
||||
HashMap<StringName, Ref<StyleBox>> style_override;
|
||||
@ -494,6 +498,14 @@ public:
|
||||
|
||||
void warp_mouse(const Point2 &p_to_pos);
|
||||
|
||||
void set_shortcut_context(const Node *p_node);
|
||||
Node *get_shortcut_context() const;
|
||||
|
||||
void set_shortcut_context_path(const NodePath &p_node_path);
|
||||
NodePath get_shortcut_context_path() const;
|
||||
|
||||
bool is_focus_owner_in_shortcut_context() const;
|
||||
|
||||
virtual bool is_text_field() const;
|
||||
|
||||
Control *get_root_parent_control() const;
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "scene/3d/spatial.h"
|
||||
#include "scene/animation/scene_tree_tween.h"
|
||||
#include "scene/debugger/script_debugger_remote.h"
|
||||
#include "scene/gui/control.h"
|
||||
#include "scene/resources/dynamic_font.h"
|
||||
#include "scene/resources/material.h"
|
||||
#include "scene/resources/mesh.h"
|
||||
@ -1279,6 +1280,8 @@ void SceneTree::_call_input_pause(const StringName &p_group, const CallInputType
|
||||
call_lock++;
|
||||
_THREAD_SAFE_UNLOCK_
|
||||
|
||||
Vector<Node *> no_context_nodes;
|
||||
|
||||
StringName method;
|
||||
|
||||
switch (p_call_type) {
|
||||
@ -1296,22 +1299,62 @@ void SceneTree::_call_input_pause(const StringName &p_group, const CallInputType
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = node_count - 1; i >= 0; i--) {
|
||||
if (input_handled) {
|
||||
break;
|
||||
if (p_call_type != CALL_INPUT_TYPE_SHORTCUT_INPUT) {
|
||||
for (int i = node_count - 1; i >= 0; i--) {
|
||||
if (input_handled) {
|
||||
break;
|
||||
}
|
||||
|
||||
Node *n = nodes[i];
|
||||
if (call_lock && call_skip.has(n)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!n->can_process()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
n->call_multilevel(method, (const Variant **)v, 1);
|
||||
//ERR_FAIL_COND(node_count != g.nodes.size());
|
||||
}
|
||||
} else {
|
||||
for (int i = node_count - 1; i >= 0; i--) {
|
||||
if (input_handled) {
|
||||
break;
|
||||
}
|
||||
|
||||
Node *n = nodes[i];
|
||||
if (call_lock && call_skip.has(n)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!n->can_process()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const Control *c = Object::cast_to<Control>(n);
|
||||
if (c) {
|
||||
// If calling shortcut input on a control, ensure it respects the shortcut context.
|
||||
// Shortcut context (based on focus) only makes sense for controls (UI), so don't need to worry about it for nodes
|
||||
if (c->get_shortcut_context() == NULL) {
|
||||
no_context_nodes.push_back(n);
|
||||
continue;
|
||||
}
|
||||
if (!c->is_focus_owner_in_shortcut_context()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
n->call_multilevel(method, (const Variant **)v, 1);
|
||||
//ERR_FAIL_COND(node_count != g.nodes.size());
|
||||
}
|
||||
|
||||
Node *n = nodes[i];
|
||||
if (call_lock && call_skip.has(n)) {
|
||||
continue;
|
||||
}
|
||||
int ncns = no_context_nodes.size();
|
||||
|
||||
if (!n->can_process()) {
|
||||
continue;
|
||||
for (int i = 0; i < ncns; ++i) {
|
||||
Node *n = no_context_nodes[i];
|
||||
n->call_multilevel(method, (const Variant **)v, 1);
|
||||
}
|
||||
|
||||
n->call_multilevel(method, (const Variant **)v, 1);
|
||||
//ERR_FAIL_COND(node_count != g.nodes.size());
|
||||
}
|
||||
|
||||
_THREAD_SAFE_LOCK_
|
||||
|
Loading…
Reference in New Issue
Block a user