Unify panning in sub-editors and make it configurable

This commit is contained in:
kobewi 2021-09-28 18:00:16 +02:00
parent b52f90e795
commit ba7ed05792
10 changed files with 312 additions and 65 deletions

View File

@ -214,6 +214,9 @@
<member name="minimap_size" type="Vector2" setter="set_minimap_size" getter="get_minimap_size" default="Vector2(240, 160)"> <member name="minimap_size" type="Vector2" setter="set_minimap_size" getter="get_minimap_size" default="Vector2(240, 160)">
The size of the minimap rectangle. The map itself is based on the size of the grid area and is scaled to fit this rectangle. The size of the minimap rectangle. The map itself is based on the size of the grid area and is scaled to fit this rectangle.
</member> </member>
<member name="panning_scheme" type="int" setter="set_panning_scheme" getter="get_panning_scheme" enum="GraphEdit.PanningScheme" default="0">
Defines the control scheme for panning with mouse wheel.
</member>
<member name="rect_clip_content" type="bool" setter="set_clip_contents" getter="is_clipping_contents" overrides="Control" default="true" /> <member name="rect_clip_content" type="bool" setter="set_clip_contents" getter="is_clipping_contents" overrides="Control" default="true" />
<member name="right_disconnects" type="bool" setter="set_right_disconnects" getter="is_right_disconnects_enabled" default="false"> <member name="right_disconnects" type="bool" setter="set_right_disconnects" getter="is_right_disconnects_enabled" default="false">
If [code]true[/code], enables disconnection of existing connections in the GraphEdit by dragging the right end. If [code]true[/code], enables disconnection of existing connections in the GraphEdit by dragging the right end.
@ -345,6 +348,14 @@
</description> </description>
</signal> </signal>
</signals> </signals>
<constants>
<constant name="SCROLL_ZOOMS" value="0" enum="PanningScheme">
[kbd]Mouse Wheel[/kbd] will zoom, [kbd]Ctrl + Mouse Wheel[/kbd] will move the view.
</constant>
<constant name="SCROLL_PANS" value="1" enum="PanningScheme">
[kbd]Mouse Wheel[/kbd] will move the view, [kbd]Ctrl + Mouse Wheel[/kbd] will zoom.
</constant>
</constants>
<theme_items> <theme_items>
<theme_item name="activity" data_type="color" type="Color" default="Color(1, 1, 1, 1)"> <theme_item name="activity" data_type="color" type="Color" default="Color(1, 1, 1, 1)">
</theme_item> </theme_item>

View File

@ -6038,6 +6038,9 @@ EditorNode::EditorNode() {
EDITOR_DEF("interface/inspector/default_color_picker_shape", (int32_t)ColorPicker::SHAPE_VHS_CIRCLE); EDITOR_DEF("interface/inspector/default_color_picker_shape", (int32_t)ColorPicker::SHAPE_VHS_CIRCLE);
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "interface/inspector/default_color_picker_shape", PROPERTY_HINT_ENUM, "HSV Rectangle,HSV Rectangle Wheel,VHS Circle", PROPERTY_USAGE_DEFAULT)); EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "interface/inspector/default_color_picker_shape", PROPERTY_HINT_ENUM, "HSV Rectangle,HSV Rectangle Wheel,VHS Circle", PROPERTY_USAGE_DEFAULT));
EDITOR_DEF("run/auto_save/save_before_running", true); EDITOR_DEF("run/auto_save/save_before_running", true);
EDITOR_DEF("interface/editors/sub_editor_panning_scheme", 0);
// Should be in sync with ControlScheme in ViewPanner.
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "interface/editors/sub_editor_panning_scheme", PROPERTY_HINT_ENUM, "Scroll Zooms,Scroll Pans", PROPERTY_USAGE_DEFAULT));
const Vector<String> textfile_ext = ((String)(EditorSettings::get_singleton()->get("docks/filesystem/textfile_extensions"))).split(",", false); const Vector<String> textfile_ext = ((String)(EditorSettings::get_singleton()->get("docks/filesystem/textfile_extensions"))).split(",", false);
for (const String &E : textfile_ext) { for (const String &E : textfile_ext) {

View File

@ -37,57 +37,31 @@
#include "scene/gui/label.h" #include "scene/gui/label.h"
#include "scene/gui/panel.h" #include "scene/gui/panel.h"
#include "scene/gui/texture_rect.h" #include "scene/gui/texture_rect.h"
#include "scene/gui/view_panner.h"
#include "editor/editor_scale.h" #include "editor/editor_scale.h"
#include "editor/editor_settings.h" #include "editor/editor_settings.h"
void TileAtlasView::gui_input(const Ref<InputEvent> &p_event) { void TileAtlasView::gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event; if (panner->gui_input(p_event)) {
if (mb.is_valid()) { accept_event();
drag_type = DRAG_TYPE_NONE; }
Vector2i scroll_vec = Vector2((mb->get_button_index() == MouseButton::WHEEL_LEFT) - (mb->get_button_index() == MouseButton::WHEEL_RIGHT), (mb->get_button_index() == MouseButton::WHEEL_UP) - (mb->get_button_index() == MouseButton::WHEEL_DOWN));
if (scroll_vec != Vector2()) {
if (mb->is_ctrl_pressed()) {
if (mb->is_shift_pressed()) {
panning.x += 32 * mb->get_factor() * scroll_vec.y;
panning.y += 32 * mb->get_factor() * scroll_vec.x;
} else {
panning.y += 32 * mb->get_factor() * scroll_vec.y;
panning.x += 32 * mb->get_factor() * scroll_vec.x;
} }
void TileAtlasView::_scroll_callback(Vector2 p_scroll_vec) {
_pan_callback(-p_scroll_vec * 32);
}
void TileAtlasView::_pan_callback(Vector2 p_scroll_vec) {
panning += p_scroll_vec;
emit_signal(SNAME("transform_changed"), zoom_widget->get_zoom(), panning); emit_signal(SNAME("transform_changed"), zoom_widget->get_zoom(), panning);
_update_zoom_and_panning(true); _update_zoom_and_panning(true);
accept_event(); }
} else if (!mb->is_shift_pressed()) { void TileAtlasView::_zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin) {
zoom_widget->set_zoom_by_increments(scroll_vec.y * 2); zoom_widget->set_zoom_by_increments(-p_scroll_vec.y * 2);
emit_signal(SNAME("transform_changed"), zoom_widget->get_zoom(), panning); emit_signal(SNAME("transform_changed"), zoom_widget->get_zoom(), panning);
_update_zoom_and_panning(true); _update_zoom_and_panning(true);
accept_event();
}
}
if (mb->get_button_index() == MouseButton::MIDDLE || mb->get_button_index() == MouseButton::RIGHT) {
if (mb->is_pressed()) {
drag_type = DRAG_TYPE_PAN;
} else {
drag_type = DRAG_TYPE_NONE;
}
accept_event();
}
}
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
if (drag_type == DRAG_TYPE_PAN) {
panning += mm->get_relative();
_update_zoom_and_panning();
emit_signal(SNAME("transform_changed"), zoom_widget->get_zoom(), panning);
accept_event();
}
}
} }
Size2i TileAtlasView::_compute_base_tiles_control_size() { Size2i TileAtlasView::_compute_base_tiles_control_size() {
@ -548,6 +522,11 @@ void TileAtlasView::update() {
void TileAtlasView::_notification(int p_what) { void TileAtlasView::_notification(int p_what) {
switch (p_what) { switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED:
panner->set_control_scheme((ViewPanner::ControlScheme)EDITOR_GET("interface/editors/sub_editor_panning_scheme").operator int());
break;
case NOTIFICATION_READY: case NOTIFICATION_READY:
button_center_view->set_icon(get_theme_icon(SNAME("CenterView"), SNAME("EditorIcons"))); button_center_view->set_icon(get_theme_icon(SNAME("CenterView"), SNAME("EditorIcons")));
break; break;
@ -561,6 +540,9 @@ void TileAtlasView::_bind_methods() {
TileAtlasView::TileAtlasView() { TileAtlasView::TileAtlasView() {
set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST); set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST);
panner.instantiate();
panner->set_callbacks(callable_mp(this, &TileAtlasView::_scroll_callback), callable_mp(this, &TileAtlasView::_pan_callback), callable_mp(this, &TileAtlasView::_zoom_callback));
Panel *panel = memnew(Panel); Panel *panel = memnew(Panel);
panel->set_clip_contents(true); panel->set_clip_contents(true);
panel->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); panel->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);

View File

@ -41,6 +41,8 @@
#include "scene/gui/texture_rect.h" #include "scene/gui/texture_rect.h"
#include "scene/resources/tile_set.h" #include "scene/resources/tile_set.h"
class ViewPanner;
class TileAtlasView : public Control { class TileAtlasView : public Control {
GDCLASS(TileAtlasView, Control); GDCLASS(TileAtlasView, Control);
@ -64,6 +66,11 @@ private:
void _center_view(); void _center_view();
virtual void gui_input(const Ref<InputEvent> &p_event) override; virtual void gui_input(const Ref<InputEvent> &p_event) override;
Ref<ViewPanner> panner;
void _scroll_callback(Vector2 p_scroll_vec);
void _pan_callback(Vector2 p_scroll_vec);
void _zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin);
Map<Vector2, Map<int, Rect2i>> alternative_tiles_rect_cache; Map<Vector2, Map<int, Rect2i>> alternative_tiles_rect_cache;
void _update_alternative_tiles_rect_cache(); void _update_alternative_tiles_rect_cache();

View File

@ -3209,6 +3209,10 @@ void VisualShaderEditor::_notification(int p_what) {
} }
} }
if (p_what == NOTIFICATION_ENTER_TREE || p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) {
graph->set_panning_scheme((GraphEdit::PanningScheme)EDITOR_GET("interface/editors/sub_editor_panning_scheme").operator int());
}
if (p_what == NOTIFICATION_DRAG_BEGIN) { if (p_what == NOTIFICATION_DRAG_BEGIN) {
Dictionary dd = get_viewport()->gui_get_drag_data(); Dictionary dd = get_viewport()->gui_get_drag_data();
if (members->is_visible_in_tree() && dd.has("id")) { if (members->is_visible_in_tree() && dd.has("id")) {

View File

@ -3753,6 +3753,11 @@ void VisualScriptEditor::_toggle_scripts_pressed() {
void VisualScriptEditor::_notification(int p_what) { void VisualScriptEditor::_notification(int p_what) {
switch (p_what) { switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
graph->set_panning_scheme((GraphEdit::PanningScheme)EDITOR_GET("interface/editors/sub_editor_panning_scheme").operator int());
} break;
case NOTIFICATION_READY: { case NOTIFICATION_READY: {
variable_editor->connect("changed", callable_mp(this, &VisualScriptEditor::_update_members)); variable_editor->connect("changed", callable_mp(this, &VisualScriptEditor::_update_members));
variable_editor->connect("changed", callable_mp(this, &VisualScriptEditor::_update_graph), varray(-1), CONNECT_DEFERRED); variable_editor->connect("changed", callable_mp(this, &VisualScriptEditor::_update_graph), varray(-1), CONNECT_DEFERRED);

View File

@ -35,6 +35,7 @@
#include "core/os/keyboard.h" #include "core/os/keyboard.h"
#include "scene/gui/box_container.h" #include "scene/gui/box_container.h"
#include "scene/gui/button.h" #include "scene/gui/button.h"
#include "scene/gui/view_panner.h"
constexpr int MINIMAP_OFFSET = 12; constexpr int MINIMAP_OFFSET = 12;
constexpr int MINIMAP_PADDING = 5; constexpr int MINIMAP_PADDING = 5;
@ -1069,13 +1070,9 @@ void GraphEdit::set_selected(Node *p_child) {
void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) { void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
ERR_FAIL_COND(p_ev.is_null()); ERR_FAIL_COND(p_ev.is_null());
panner->gui_input(p_ev);
Ref<InputEventMouseMotion> mm = p_ev; Ref<InputEventMouseMotion> mm = p_ev;
if (mm.is_valid() && ((mm->get_button_mask() & MouseButton::MASK_MIDDLE) != MouseButton::NONE || ((mm->get_button_mask() & MouseButton::MASK_LEFT) != MouseButton::NONE && Input::get_singleton()->is_key_pressed(Key::SPACE)))) {
Vector2i relative = Input::get_singleton()->warp_mouse_motion(mm, get_global_rect());
h_scroll->set_value(h_scroll->get_value() - relative.x);
v_scroll->set_value(v_scroll->get_value() - relative.y);
}
if (mm.is_valid() && dragging) { if (mm.is_valid() && dragging) {
if (!moving_selection) { if (!moving_selection) {
@ -1327,22 +1324,6 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
top_layer->update(); top_layer->update();
minimap->update(); minimap->update();
} }
int scroll_direction = (b->get_button_index() == MouseButton::WHEEL_DOWN) - (b->get_button_index() == MouseButton::WHEEL_UP);
if (scroll_direction != 0) {
if (b->is_ctrl_pressed()) {
if (b->is_shift_pressed()) {
// Horizontal scrolling.
h_scroll->set_value(h_scroll->get_value() + (h_scroll->get_page() * b->get_factor() / 8) * scroll_direction);
} else {
// Vertical scrolling.
v_scroll->set_value(v_scroll->get_value() + (v_scroll->get_page() * b->get_factor() / 8) * scroll_direction);
}
} else {
// Zooming.
set_zoom_custom(scroll_direction < 0 ? zoom * zoom_step : zoom / zoom_step, b->get_position());
}
}
} }
if (p_ev->is_pressed()) { if (p_ev->is_pressed()) {
@ -1373,6 +1354,23 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
} }
} }
void GraphEdit::_scroll_callback(Vector2 p_scroll_vec) {
if (p_scroll_vec.x != 0) {
h_scroll->set_value(h_scroll->get_value() + (h_scroll->get_page() * Math::abs(p_scroll_vec.x) / 8) * SIGN(p_scroll_vec.x));
} else {
v_scroll->set_value(v_scroll->get_value() + (v_scroll->get_page() * Math::abs(p_scroll_vec.y) / 8) * SIGN(p_scroll_vec.y));
}
}
void GraphEdit::_pan_callback(Vector2 p_scroll_vec) {
h_scroll->set_value(h_scroll->get_value() - p_scroll_vec.x);
v_scroll->set_value(v_scroll->get_value() - p_scroll_vec.y);
}
void GraphEdit::_zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin) {
set_zoom_custom(p_scroll_vec.y < 0 ? zoom * zoom_step : zoom / zoom_step, p_origin);
}
void GraphEdit::set_connection_activity(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port, float p_activity) { void GraphEdit::set_connection_activity(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port, float p_activity) {
for (Connection &E : connections) { for (Connection &E : connections) {
if (E.from == p_from && E.from_port == p_from_port && E.to == p_to && E.to_port == p_to_port) { if (E.from == p_from && E.from_port == p_from_port && E.to == p_to && E.to_port == p_to_port) {
@ -1406,6 +1404,15 @@ void GraphEdit::force_connection_drag_end() {
emit_signal(SNAME("connection_drag_ended")); emit_signal(SNAME("connection_drag_ended"));
} }
void GraphEdit::set_panning_scheme(PanningScheme p_scheme) {
panning_scheme = p_scheme;
panner->set_control_scheme((ViewPanner::ControlScheme)p_scheme);
}
GraphEdit::PanningScheme GraphEdit::get_panning_scheme() const {
return panning_scheme;
}
void GraphEdit::set_zoom(float p_zoom) { void GraphEdit::set_zoom(float p_zoom) {
set_zoom_custom(p_zoom, get_size() / 2); set_zoom_custom(p_zoom, get_size() / 2);
} }
@ -2190,6 +2197,9 @@ void GraphEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_valid_connection_type", "from_type", "to_type"), &GraphEdit::is_valid_connection_type); ClassDB::bind_method(D_METHOD("is_valid_connection_type", "from_type", "to_type"), &GraphEdit::is_valid_connection_type);
ClassDB::bind_method(D_METHOD("get_connection_line", "from", "to"), &GraphEdit::get_connection_line); ClassDB::bind_method(D_METHOD("get_connection_line", "from", "to"), &GraphEdit::get_connection_line);
ClassDB::bind_method(D_METHOD("set_panning_scheme", "scheme"), &GraphEdit::set_panning_scheme);
ClassDB::bind_method(D_METHOD("get_panning_scheme"), &GraphEdit::get_panning_scheme);
ClassDB::bind_method(D_METHOD("set_zoom", "zoom"), &GraphEdit::set_zoom); ClassDB::bind_method(D_METHOD("set_zoom", "zoom"), &GraphEdit::set_zoom);
ClassDB::bind_method(D_METHOD("get_zoom"), &GraphEdit::get_zoom); ClassDB::bind_method(D_METHOD("get_zoom"), &GraphEdit::get_zoom);
@ -2244,6 +2254,7 @@ void GraphEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scroll_offset"), "set_scroll_ofs", "get_scroll_ofs"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scroll_offset"), "set_scroll_ofs", "get_scroll_ofs");
ADD_PROPERTY(PropertyInfo(Variant::INT, "snap_distance"), "set_snap", "get_snap"); ADD_PROPERTY(PropertyInfo(Variant::INT, "snap_distance"), "set_snap", "get_snap");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_snap"), "set_use_snap", "is_using_snap"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_snap"), "set_use_snap", "is_using_snap");
ADD_PROPERTY(PropertyInfo(Variant::INT, "panning_scheme", PROPERTY_HINT_ENUM, "Scroll Zooms,Scroll Pans"), "set_panning_scheme", "get_panning_scheme");
ADD_GROUP("Connection Lines", "connection_lines"); ADD_GROUP("Connection Lines", "connection_lines");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "connection_lines_thickness"), "set_connection_lines_thickness", "get_connection_lines_thickness"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "connection_lines_thickness"), "set_connection_lines_thickness", "get_connection_lines_thickness");
@ -2277,6 +2288,9 @@ void GraphEdit::_bind_methods() {
ADD_SIGNAL(MethodInfo("scroll_offset_changed", PropertyInfo(Variant::VECTOR2, "ofs"))); ADD_SIGNAL(MethodInfo("scroll_offset_changed", PropertyInfo(Variant::VECTOR2, "ofs")));
ADD_SIGNAL(MethodInfo("connection_drag_started", PropertyInfo(Variant::STRING, "from"), PropertyInfo(Variant::STRING, "slot"), PropertyInfo(Variant::BOOL, "is_output"))); ADD_SIGNAL(MethodInfo("connection_drag_started", PropertyInfo(Variant::STRING, "from"), PropertyInfo(Variant::STRING, "slot"), PropertyInfo(Variant::BOOL, "is_output")));
ADD_SIGNAL(MethodInfo("connection_drag_ended")); ADD_SIGNAL(MethodInfo("connection_drag_ended"));
BIND_ENUM_CONSTANT(SCROLL_ZOOMS);
BIND_ENUM_CONSTANT(SCROLL_PANS);
} }
GraphEdit::GraphEdit() { GraphEdit::GraphEdit() {
@ -2289,6 +2303,10 @@ GraphEdit::GraphEdit() {
// Allow zooming 4 times from the default zoom level. // Allow zooming 4 times from the default zoom level.
zoom_max = (1 * Math::pow(zoom_step, 4)); zoom_max = (1 * Math::pow(zoom_step, 4));
panner.instantiate();
panner->set_callbacks(callable_mp(this, &GraphEdit::_scroll_callback), callable_mp(this, &GraphEdit::_pan_callback), callable_mp(this, &GraphEdit::_zoom_callback));
panner->set_disable_rmb(true);
top_layer = memnew(GraphEditFilter(this)); top_layer = memnew(GraphEditFilter(this));
add_child(top_layer, false, INTERNAL_MODE_BACK); add_child(top_layer, false, INTERNAL_MODE_BACK);
top_layer->set_mouse_filter(MOUSE_FILTER_PASS); top_layer->set_mouse_filter(MOUSE_FILTER_PASS);

View File

@ -41,6 +41,7 @@
#include "scene/gui/texture_rect.h" #include "scene/gui/texture_rect.h"
class GraphEdit; class GraphEdit;
class ViewPanner;
class GraphEditFilter : public Control { class GraphEditFilter : public Control {
GDCLASS(GraphEditFilter, Control); GDCLASS(GraphEditFilter, Control);
@ -103,6 +104,12 @@ public:
float activity = 0.0; float activity = 0.0;
}; };
// Should be in sync with ControlScheme in ViewPanner.
enum PanningScheme {
SCROLL_ZOOMS,
SCROLL_PANS,
};
private: private:
Label *zoom_label; Label *zoom_label;
Button *zoom_minus; Button *zoom_minus;
@ -122,6 +129,11 @@ private:
float port_grab_distance_horizontal = 0.0; float port_grab_distance_horizontal = 0.0;
float port_grab_distance_vertical; float port_grab_distance_vertical;
Ref<ViewPanner> panner;
void _scroll_callback(Vector2 p_scroll_vec);
void _pan_callback(Vector2 p_scroll_vec);
void _zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin);
bool connecting = false; bool connecting = false;
String connecting_from; String connecting_from;
bool connecting_out = false; bool connecting_out = false;
@ -136,6 +148,7 @@ private:
bool connecting_valid = false; bool connecting_valid = false;
Vector2 click_pos; Vector2 click_pos;
PanningScheme panning_scheme = SCROLL_ZOOMS;
bool dragging = false; bool dragging = false;
bool just_selected = false; bool just_selected = false;
bool moving_selection = false; bool moving_selection = false;
@ -277,6 +290,9 @@ public:
void remove_valid_connection_type(int p_type, int p_with_type); void remove_valid_connection_type(int p_type, int p_with_type);
bool is_valid_connection_type(int p_type, int p_with_type) const; bool is_valid_connection_type(int p_type, int p_with_type) const;
void set_panning_scheme(PanningScheme p_scheme);
PanningScheme get_panning_scheme() const;
void set_zoom(float p_zoom); void set_zoom(float p_zoom);
void set_zoom_custom(float p_zoom, const Vector2 &p_center); void set_zoom_custom(float p_zoom, const Vector2 &p_center);
float get_zoom() const; float get_zoom() const;
@ -338,4 +354,6 @@ public:
GraphEdit(); GraphEdit();
}; };
VARIANT_ENUM_CAST(GraphEdit::PanningScheme);
#endif // GRAPHEdit_H #endif // GRAPHEdit_H

136
scene/gui/view_panner.cpp Normal file
View File

@ -0,0 +1,136 @@
/*************************************************************************/
/* view_panner.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "view_panner.h"
#include "core/input/input.h"
#include "core/os/keyboard.h"
bool ViewPanner::gui_input(const Ref<InputEvent> &p_event, Rect2 p_canvas_rect) {
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
Vector2i scroll_vec = Vector2((mb->get_button_index() == MouseButton::WHEEL_RIGHT) - (mb->get_button_index() == MouseButton::WHEEL_LEFT), (mb->get_button_index() == MouseButton::WHEEL_DOWN) - (mb->get_button_index() == MouseButton::WHEEL_UP));
if (scroll_vec != Vector2()) {
if (control_scheme == SCROLL_PANS) {
if (mb->is_ctrl_pressed()) {
callback_helper(zoom_callback, scroll_vec, mb->get_position());
} else {
Vector2 panning;
if (mb->is_shift_pressed()) {
panning.x += mb->get_factor() * scroll_vec.y;
panning.y += mb->get_factor() * scroll_vec.x;
} else {
panning.y += mb->get_factor() * scroll_vec.y;
panning.x += mb->get_factor() * scroll_vec.x;
}
callback_helper(scroll_callback, panning);
return true;
}
} else {
if (mb->is_ctrl_pressed()) {
Vector2 panning;
if (mb->is_shift_pressed()) {
panning.x += mb->get_factor() * scroll_vec.y;
panning.y += mb->get_factor() * scroll_vec.x;
} else {
panning.y += mb->get_factor() * scroll_vec.y;
panning.x += mb->get_factor() * scroll_vec.x;
}
callback_helper(scroll_callback, panning);
return true;
} else if (!mb->is_shift_pressed()) {
callback_helper(zoom_callback, scroll_vec, mb->get_position());
return true;
}
}
}
if (mb->get_button_index() == MouseButton::MIDDLE || (mb->get_button_index() == MouseButton::RIGHT && !disable_rmb) || (mb->get_button_index() == MouseButton::LEFT && (Input::get_singleton()->is_key_pressed(Key::SPACE) || !mb->is_pressed()))) {
if (mb->is_pressed()) {
is_dragging = true;
} else {
is_dragging = false;
}
return true;
}
}
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
if (is_dragging) {
if (p_canvas_rect != Rect2()) {
callback_helper(pan_callback, Input::get_singleton()->warp_mouse_motion(mm, p_canvas_rect));
} else {
callback_helper(pan_callback, mm->get_relative());
}
return true;
}
}
return false;
}
void ViewPanner::callback_helper(Callable p_callback, Vector2 p_arg1, Vector2 p_arg2) {
if (p_callback == zoom_callback) {
const Variant **argptr = (const Variant **)alloca(sizeof(Variant *) * 2);
Variant var1 = p_arg1;
argptr[0] = &var1;
Variant var2 = p_arg2;
argptr[1] = &var2;
Variant result;
Callable::CallError ce;
p_callback.call(argptr, 2, result, ce);
} else {
const Variant **argptr = (const Variant **)alloca(sizeof(Variant *));
Variant var = p_arg1;
argptr[0] = &var;
Variant result;
Callable::CallError ce;
p_callback.call(argptr, 1, result, ce);
}
}
void ViewPanner::set_callbacks(Callable p_scroll_callback, Callable p_pan_callback, Callable p_zoom_callback) {
scroll_callback = p_scroll_callback;
pan_callback = p_pan_callback;
zoom_callback = p_zoom_callback;
}
void ViewPanner::set_control_scheme(ControlScheme p_scheme) {
control_scheme = p_scheme;
}
void ViewPanner::set_disable_rmb(bool p_disable) {
disable_rmb = p_disable;
}

63
scene/gui/view_panner.h Normal file
View File

@ -0,0 +1,63 @@
/*************************************************************************/
/* view_panner.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifndef VIEW_PANNER_H
#define VIEW_PANNER_H
#include "core/object/ref_counted.h"
class InputEvent;
class ViewPanner : public RefCounted {
GDCLASS(ViewPanner, RefCounted);
bool is_dragging = false;
bool disable_rmb = false;
Callable scroll_callback;
Callable pan_callback;
Callable zoom_callback;
void callback_helper(Callable p_callback, Vector2 p_arg1, Vector2 p_arg2 = Vector2());
public:
enum ControlScheme {
SCROLL_ZOOMS,
SCROLL_PANS,
};
ControlScheme control_scheme = SCROLL_ZOOMS;
void set_callbacks(Callable p_scroll_callback, Callable p_pan_callback, Callable p_zoom_callback);
void set_control_scheme(ControlScheme p_scheme);
void set_disable_rmb(bool p_disable);
bool gui_input(const Ref<InputEvent> &p_ev, Rect2 p_canvas_rect = Rect2());
};
#endif // VIEW_PANNER_H