Merge pull request #12573 from poke1024/macostouchpad
Native pan and zoom for macOS + InputEventGesture
This commit is contained in:
commit
5a23136d1b
21 changed files with 549 additions and 133 deletions
|
@ -177,6 +177,14 @@ bool InputEventWithModifiers::get_command() const {
|
|||
return command;
|
||||
}
|
||||
|
||||
void InputEventWithModifiers::set_modifiers_from_event(const InputEventWithModifiers *event) {
|
||||
|
||||
set_alt(event->get_alt());
|
||||
set_shift(event->get_shift());
|
||||
set_control(event->get_control());
|
||||
set_metakey(event->get_metakey());
|
||||
}
|
||||
|
||||
void InputEventWithModifiers::_bind_methods() {
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_alt", "enable"), &InputEventWithModifiers::set_alt);
|
||||
|
@ -436,10 +444,7 @@ Ref<InputEvent> InputEventMouseButton::xformed_by(const Transform2D &p_xform, co
|
|||
mb->set_id(get_id());
|
||||
mb->set_device(get_device());
|
||||
|
||||
mb->set_alt(get_alt());
|
||||
mb->set_shift(get_shift());
|
||||
mb->set_control(get_control());
|
||||
mb->set_metakey(get_metakey());
|
||||
mb->set_modifiers_from_event(this);
|
||||
|
||||
mb->set_position(l);
|
||||
mb->set_global_position(g);
|
||||
|
@ -555,10 +560,7 @@ Ref<InputEvent> InputEventMouseMotion::xformed_by(const Transform2D &p_xform, co
|
|||
mm->set_id(get_id());
|
||||
mm->set_device(get_device());
|
||||
|
||||
mm->set_alt(get_alt());
|
||||
mm->set_shift(get_shift());
|
||||
mm->set_control(get_control());
|
||||
mm->set_metakey(get_metakey());
|
||||
mm->set_modifiers_from_event(this);
|
||||
|
||||
mm->set_position(l);
|
||||
mm->set_global_position(g);
|
||||
|
@ -930,3 +932,75 @@ void InputEventAction::_bind_methods() {
|
|||
InputEventAction::InputEventAction() {
|
||||
pressed = false;
|
||||
}
|
||||
/////////////////////////////
|
||||
|
||||
void InputEventGesture::set_position(const Vector2 &p_pos) {
|
||||
|
||||
pos = p_pos;
|
||||
}
|
||||
|
||||
Vector2 InputEventGesture::get_position() const {
|
||||
|
||||
return pos;
|
||||
}
|
||||
/////////////////////////////
|
||||
|
||||
void InputEventMagnifyGesture::set_factor(real_t p_factor) {
|
||||
|
||||
factor = p_factor;
|
||||
}
|
||||
|
||||
real_t InputEventMagnifyGesture::get_factor() const {
|
||||
|
||||
return factor;
|
||||
}
|
||||
|
||||
Ref<InputEvent> InputEventMagnifyGesture::xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs) const {
|
||||
|
||||
Ref<InputEventMagnifyGesture> ev;
|
||||
ev.instance();
|
||||
|
||||
ev->set_id(get_id());
|
||||
ev->set_device(get_device());
|
||||
ev->set_modifiers_from_event(this);
|
||||
|
||||
ev->set_position(p_xform.xform(get_position() + p_local_ofs));
|
||||
ev->set_factor(get_factor());
|
||||
|
||||
return ev;
|
||||
}
|
||||
|
||||
InputEventMagnifyGesture::InputEventMagnifyGesture() {
|
||||
|
||||
factor = 1.0;
|
||||
}
|
||||
/////////////////////////////
|
||||
|
||||
void InputEventPanGesture::set_delta(const Vector2 &p_delta) {
|
||||
|
||||
delta = p_delta;
|
||||
}
|
||||
|
||||
Vector2 InputEventPanGesture::get_delta() const {
|
||||
return delta;
|
||||
}
|
||||
|
||||
Ref<InputEvent> InputEventPanGesture::xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs) const {
|
||||
|
||||
Ref<InputEventPanGesture> ev;
|
||||
ev.instance();
|
||||
|
||||
ev->set_id(get_id());
|
||||
ev->set_device(get_device());
|
||||
ev->set_modifiers_from_event(this);
|
||||
|
||||
ev->set_position(p_xform.xform(get_position() + p_local_ofs));
|
||||
ev->set_delta(get_delta());
|
||||
|
||||
return ev;
|
||||
}
|
||||
|
||||
InputEventPanGesture::InputEventPanGesture() {
|
||||
|
||||
delta = Vector2(0, 0);
|
||||
}
|
||||
|
|
|
@ -213,6 +213,8 @@ public:
|
|||
void set_command(bool p_enabled);
|
||||
bool get_command() const;
|
||||
|
||||
void set_modifiers_from_event(const InputEventWithModifiers *event);
|
||||
|
||||
InputEventWithModifiers();
|
||||
};
|
||||
|
||||
|
@ -468,4 +470,42 @@ public:
|
|||
InputEventAction();
|
||||
};
|
||||
|
||||
class InputEventGesture : public InputEventWithModifiers {
|
||||
|
||||
GDCLASS(InputEventGesture, InputEventWithModifiers)
|
||||
|
||||
Vector2 pos;
|
||||
|
||||
public:
|
||||
void set_position(const Vector2 &p_pos);
|
||||
Vector2 get_position() const;
|
||||
};
|
||||
|
||||
class InputEventMagnifyGesture : public InputEventGesture {
|
||||
|
||||
GDCLASS(InputEventMagnifyGesture, InputEventGesture)
|
||||
real_t factor;
|
||||
|
||||
public:
|
||||
void set_factor(real_t p_factor);
|
||||
real_t get_factor() const;
|
||||
|
||||
virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const;
|
||||
|
||||
InputEventMagnifyGesture();
|
||||
};
|
||||
|
||||
class InputEventPanGesture : public InputEventGesture {
|
||||
|
||||
GDCLASS(InputEventPanGesture, InputEventGesture)
|
||||
Vector2 delta;
|
||||
|
||||
public:
|
||||
void set_delta(const Vector2 &p_delta);
|
||||
Vector2 get_delta() const;
|
||||
|
||||
virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const;
|
||||
|
||||
InputEventPanGesture();
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -2889,6 +2889,18 @@ void AnimationKeyEditor::_track_editor_gui_input(const Ref<InputEvent> &p_input)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ref<InputEventMagnifyGesture> magnify_gesture = p_input;
|
||||
if (magnify_gesture.is_valid()) {
|
||||
zoom->set_value(zoom->get_value() * magnify_gesture->get_factor());
|
||||
}
|
||||
|
||||
Ref<InputEventPanGesture> pan_gesture = p_input;
|
||||
if (pan_gesture.is_valid()) {
|
||||
|
||||
h_scroll->set_value(h_scroll->get_value() - h_scroll->get_page() * pan_gesture->get_delta().x / 8);
|
||||
v_scroll->set_value(v_scroll->get_value() - v_scroll->get_page() * pan_gesture->get_delta().y / 8);
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationKeyEditor::_notification(int p_what) {
|
||||
|
|
|
@ -979,6 +979,23 @@ void CodeTextEditor::_text_editor_gui_input(const Ref<InputEvent> &p_event) {
|
|||
}
|
||||
}
|
||||
|
||||
Ref<InputEventMagnifyGesture> magnify_gesture = p_event;
|
||||
if (magnify_gesture.is_valid()) {
|
||||
|
||||
Ref<DynamicFont> font = text_editor->get_font("font");
|
||||
|
||||
if (font.is_valid()) {
|
||||
if (font->get_size() != (int)font_size) {
|
||||
font_size = font->get_size();
|
||||
}
|
||||
|
||||
font_size *= powf(magnify_gesture->get_factor(), 0.25);
|
||||
|
||||
_add_font_size((int)font_size - font->get_size());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Ref<InputEventKey> k = p_event;
|
||||
|
||||
if (k.is_valid()) {
|
||||
|
@ -999,14 +1016,15 @@ void CodeTextEditor::_text_editor_gui_input(const Ref<InputEvent> &p_event) {
|
|||
|
||||
void CodeTextEditor::_zoom_in() {
|
||||
font_resize_val += EDSCALE;
|
||||
|
||||
if (font_resize_timer->get_time_left() == 0)
|
||||
font_resize_timer->start();
|
||||
_zoom_changed();
|
||||
}
|
||||
|
||||
void CodeTextEditor::_zoom_out() {
|
||||
font_resize_val -= EDSCALE;
|
||||
_zoom_changed();
|
||||
}
|
||||
|
||||
void CodeTextEditor::_zoom_changed() {
|
||||
if (font_resize_timer->get_time_left() == 0)
|
||||
font_resize_timer->start();
|
||||
}
|
||||
|
@ -1067,16 +1085,25 @@ void CodeTextEditor::_complete_request() {
|
|||
|
||||
void CodeTextEditor::_font_resize_timeout() {
|
||||
|
||||
if (_add_font_size(font_resize_val)) {
|
||||
font_resize_val = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool CodeTextEditor::_add_font_size(int p_delta) {
|
||||
|
||||
Ref<DynamicFont> font = text_editor->get_font("font");
|
||||
|
||||
if (font.is_valid()) {
|
||||
int new_size = CLAMP(font->get_size() + font_resize_val, 8 * EDSCALE, 96 * EDSCALE);
|
||||
int new_size = CLAMP(font->get_size() + p_delta, 8 * EDSCALE, 96 * EDSCALE);
|
||||
if (new_size != font->get_size()) {
|
||||
EditorSettings::get_singleton()->set("interface/editor/source_font_size", new_size / EDSCALE);
|
||||
font->set_size(new_size);
|
||||
}
|
||||
|
||||
font_resize_val = 0;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1285,6 +1312,7 @@ CodeTextEditor::CodeTextEditor() {
|
|||
code_complete_timer->connect("timeout", this, "_code_complete_timer_timeout");
|
||||
|
||||
font_resize_val = 0;
|
||||
font_size = -1;
|
||||
font_resize_timer = memnew(Timer);
|
||||
add_child(font_resize_timer);
|
||||
font_resize_timer->set_one_shot(true);
|
||||
|
|
|
@ -204,6 +204,7 @@ class CodeTextEditor : public VBoxContainer {
|
|||
|
||||
Timer *font_resize_timer;
|
||||
int font_resize_val;
|
||||
real_t font_size;
|
||||
|
||||
Label *error;
|
||||
|
||||
|
@ -212,10 +213,12 @@ class CodeTextEditor : public VBoxContainer {
|
|||
void _update_font();
|
||||
void _complete_request();
|
||||
void _font_resize_timeout();
|
||||
bool _add_font_size(int p_delta);
|
||||
|
||||
void _text_editor_gui_input(const Ref<InputEvent> &p_event);
|
||||
void _zoom_in();
|
||||
void _zoom_out();
|
||||
void _zoom_changed();
|
||||
void _reset_zoom();
|
||||
|
||||
CodeTextEditorCodeCompleteFunc code_complete_func;
|
||||
|
|
|
@ -1442,6 +1442,22 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) {
|
|||
}
|
||||
}
|
||||
|
||||
Ref<InputEventMagnifyGesture> magnify_gesture = p_event;
|
||||
if (magnify_gesture.is_valid()) {
|
||||
|
||||
_zoom_on_position(zoom * magnify_gesture->get_factor(), magnify_gesture->get_position());
|
||||
return;
|
||||
}
|
||||
|
||||
Ref<InputEventPanGesture> pan_gesture = p_event;
|
||||
if (pan_gesture.is_valid()) {
|
||||
|
||||
const Vector2 delta = (int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom) * pan_gesture->get_delta();
|
||||
h_scroll->set_value(h_scroll->get_value() + delta.x);
|
||||
v_scroll->set_value(v_scroll->get_value() + delta.y);
|
||||
return;
|
||||
}
|
||||
|
||||
Ref<InputEventMouseButton> b = p_event;
|
||||
if (b.is_valid()) {
|
||||
// Button event
|
||||
|
|
|
@ -339,6 +339,19 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
|
|||
uv_edit_draw->update();
|
||||
}
|
||||
}
|
||||
|
||||
Ref<InputEventMagnifyGesture> magnify_gesture = p_input;
|
||||
if (magnify_gesture.is_valid()) {
|
||||
|
||||
uv_zoom->set_value(uv_zoom->get_value() * magnify_gesture->get_factor());
|
||||
}
|
||||
|
||||
Ref<InputEventPanGesture> pan_gesture = p_input;
|
||||
if (pan_gesture.is_valid()) {
|
||||
|
||||
uv_hscroll->set_value(uv_hscroll->get_value() + uv_hscroll->get_page() * pan_gesture->get_delta().x / 8);
|
||||
uv_vscroll->set_value(uv_vscroll->get_value() + uv_vscroll->get_page() * pan_gesture->get_delta().y / 8);
|
||||
}
|
||||
}
|
||||
|
||||
void Polygon2DEditor::_uv_scroll_changed(float) {
|
||||
|
|
|
@ -1694,92 +1694,78 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
|
|||
|
||||
switch (nav_mode) {
|
||||
case NAVIGATION_PAN: {
|
||||
|
||||
real_t pan_speed = 1 / 150.0;
|
||||
int pan_speed_modifier = 10;
|
||||
if (nav_scheme == NAVIGATION_MAYA && m->get_shift())
|
||||
pan_speed *= pan_speed_modifier;
|
||||
|
||||
Point2i relative = _get_warped_mouse_motion(m);
|
||||
|
||||
Transform camera_transform;
|
||||
|
||||
camera_transform.translate(cursor.pos);
|
||||
camera_transform.basis.rotate(Vector3(1, 0, 0), -cursor.x_rot);
|
||||
camera_transform.basis.rotate(Vector3(0, 1, 0), -cursor.y_rot);
|
||||
Vector3 translation(-relative.x * pan_speed, relative.y * pan_speed, 0);
|
||||
translation *= cursor.distance / DISTANCE_DEFAULT;
|
||||
camera_transform.translate(translation);
|
||||
cursor.pos = camera_transform.origin;
|
||||
_nav_pan(m, _get_warped_mouse_motion(m));
|
||||
|
||||
} break;
|
||||
|
||||
case NAVIGATION_ZOOM: {
|
||||
real_t zoom_speed = 1 / 80.0;
|
||||
int zoom_speed_modifier = 10;
|
||||
if (nav_scheme == NAVIGATION_MAYA && m->get_shift())
|
||||
zoom_speed *= zoom_speed_modifier;
|
||||
|
||||
NavigationZoomStyle zoom_style = (NavigationZoomStyle)EditorSettings::get_singleton()->get("editors/3d/navigation/zoom_style").operator int();
|
||||
if (zoom_style == NAVIGATION_ZOOM_HORIZONTAL) {
|
||||
if (m->get_relative().x > 0)
|
||||
scale_cursor_distance(1 - m->get_relative().x * zoom_speed);
|
||||
else if (m->get_relative().x < 0)
|
||||
scale_cursor_distance(1.0 / (1 + m->get_relative().x * zoom_speed));
|
||||
} else {
|
||||
if (m->get_relative().y > 0)
|
||||
scale_cursor_distance(1 + m->get_relative().y * zoom_speed);
|
||||
else if (m->get_relative().y < 0)
|
||||
scale_cursor_distance(1.0 / (1 - m->get_relative().y * zoom_speed));
|
||||
}
|
||||
_nav_zoom(m, m->get_relative());
|
||||
|
||||
} break;
|
||||
|
||||
case NAVIGATION_ORBIT: {
|
||||
Point2i relative = _get_warped_mouse_motion(m);
|
||||
_nav_orbit(m, _get_warped_mouse_motion(m));
|
||||
|
||||
real_t degrees_per_pixel = EditorSettings::get_singleton()->get("editors/3d/navigation_feel/orbit_sensitivity");
|
||||
real_t radians_per_pixel = Math::deg2rad(degrees_per_pixel);
|
||||
|
||||
cursor.x_rot += relative.y * radians_per_pixel;
|
||||
cursor.y_rot += relative.x * radians_per_pixel;
|
||||
if (cursor.x_rot > Math_PI / 2.0)
|
||||
cursor.x_rot = Math_PI / 2.0;
|
||||
if (cursor.x_rot < -Math_PI / 2.0)
|
||||
cursor.x_rot = -Math_PI / 2.0;
|
||||
name = "";
|
||||
_update_name();
|
||||
} break;
|
||||
|
||||
case NAVIGATION_LOOK: {
|
||||
// Freelook only works properly in perspective.
|
||||
// It technically works too in ortho, but it's awful for a user due to fov being near zero
|
||||
if (!orthogonal) {
|
||||
Point2i relative = _get_warped_mouse_motion(m);
|
||||
_nav_look(m, _get_warped_mouse_motion(m));
|
||||
|
||||
real_t degrees_per_pixel = EditorSettings::get_singleton()->get("editors/3d/navigation_feel/orbit_sensitivity");
|
||||
real_t radians_per_pixel = Math::deg2rad(degrees_per_pixel);
|
||||
} break;
|
||||
|
||||
// Note: do NOT assume the camera has the "current" transform, because it is interpolated and may have "lag".
|
||||
Transform prev_camera_transform = to_camera_transform(cursor);
|
||||
default: {}
|
||||
}
|
||||
}
|
||||
|
||||
cursor.x_rot += relative.y * radians_per_pixel;
|
||||
cursor.y_rot += relative.x * radians_per_pixel;
|
||||
if (cursor.x_rot > Math_PI / 2.0)
|
||||
cursor.x_rot = Math_PI / 2.0;
|
||||
if (cursor.x_rot < -Math_PI / 2.0)
|
||||
cursor.x_rot = -Math_PI / 2.0;
|
||||
Ref<InputEventMagnifyGesture> magnify_gesture = p_event;
|
||||
if (magnify_gesture.is_valid()) {
|
||||
|
||||
// Look is like the opposite of Orbit: the focus point rotates around the camera
|
||||
Transform camera_transform = to_camera_transform(cursor);
|
||||
Vector3 pos = camera_transform.xform(Vector3(0, 0, 0));
|
||||
Vector3 prev_pos = prev_camera_transform.xform(Vector3(0, 0, 0));
|
||||
Vector3 diff = prev_pos - pos;
|
||||
cursor.pos += diff;
|
||||
if (is_freelook_active())
|
||||
scale_freelook_speed(magnify_gesture->get_factor());
|
||||
else
|
||||
scale_cursor_distance(1.0 / magnify_gesture->get_factor());
|
||||
}
|
||||
|
||||
name = "";
|
||||
_update_name();
|
||||
}
|
||||
Ref<InputEventPanGesture> pan_gesture = p_event;
|
||||
if (pan_gesture.is_valid()) {
|
||||
|
||||
NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
|
||||
NavigationMode nav_mode = NAVIGATION_NONE;
|
||||
|
||||
if (nav_scheme == NAVIGATION_GODOT) {
|
||||
|
||||
int mod = _get_key_modifier(pan_gesture);
|
||||
|
||||
if (mod == _get_key_modifier_setting("editors/3d/navigation/pan_modifier"))
|
||||
nav_mode = NAVIGATION_PAN;
|
||||
else if (mod == _get_key_modifier_setting("editors/3d/navigation/zoom_modifier"))
|
||||
nav_mode = NAVIGATION_ZOOM;
|
||||
else if (mod == _get_key_modifier_setting("editors/3d/navigation/orbit_modifier"))
|
||||
nav_mode = NAVIGATION_ORBIT;
|
||||
|
||||
} else if (nav_scheme == NAVIGATION_MAYA) {
|
||||
if (pan_gesture->get_alt())
|
||||
nav_mode = NAVIGATION_PAN;
|
||||
}
|
||||
|
||||
switch (nav_mode) {
|
||||
case NAVIGATION_PAN: {
|
||||
_nav_pan(m, pan_gesture->get_delta());
|
||||
|
||||
} break;
|
||||
|
||||
case NAVIGATION_ZOOM: {
|
||||
_nav_zoom(m, pan_gesture->get_delta());
|
||||
|
||||
} break;
|
||||
|
||||
case NAVIGATION_ORBIT: {
|
||||
_nav_orbit(m, pan_gesture->get_delta());
|
||||
|
||||
} break;
|
||||
|
||||
case NAVIGATION_LOOK: {
|
||||
_nav_look(m, pan_gesture->get_delta());
|
||||
|
||||
} break;
|
||||
|
||||
|
@ -1885,6 +1871,94 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
|
|||
accept_event();
|
||||
}
|
||||
|
||||
void SpatialEditorViewport::_nav_pan(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative) {
|
||||
|
||||
const NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
|
||||
|
||||
real_t pan_speed = 1 / 150.0;
|
||||
int pan_speed_modifier = 10;
|
||||
if (nav_scheme == NAVIGATION_MAYA && p_event->get_shift())
|
||||
pan_speed *= pan_speed_modifier;
|
||||
|
||||
Transform camera_transform;
|
||||
|
||||
camera_transform.translate(cursor.pos);
|
||||
camera_transform.basis.rotate(Vector3(1, 0, 0), -cursor.x_rot);
|
||||
camera_transform.basis.rotate(Vector3(0, 1, 0), -cursor.y_rot);
|
||||
Vector3 translation(-p_relative.x * pan_speed, p_relative.y * pan_speed, 0);
|
||||
translation *= cursor.distance / DISTANCE_DEFAULT;
|
||||
camera_transform.translate(translation);
|
||||
cursor.pos = camera_transform.origin;
|
||||
}
|
||||
|
||||
void SpatialEditorViewport::_nav_zoom(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative) {
|
||||
|
||||
const NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
|
||||
|
||||
real_t zoom_speed = 1 / 80.0;
|
||||
int zoom_speed_modifier = 10;
|
||||
if (nav_scheme == NAVIGATION_MAYA && p_event->get_shift())
|
||||
zoom_speed *= zoom_speed_modifier;
|
||||
|
||||
NavigationZoomStyle zoom_style = (NavigationZoomStyle)EditorSettings::get_singleton()->get("editors/3d/navigation/zoom_style").operator int();
|
||||
if (zoom_style == NAVIGATION_ZOOM_HORIZONTAL) {
|
||||
if (p_relative.x > 0)
|
||||
scale_cursor_distance(1 - p_relative.x * zoom_speed);
|
||||
else if (p_relative.x < 0)
|
||||
scale_cursor_distance(1.0 / (1 + p_relative.x * zoom_speed));
|
||||
} else {
|
||||
if (p_relative.y > 0)
|
||||
scale_cursor_distance(1 + p_relative.y * zoom_speed);
|
||||
else if (p_relative.y < 0)
|
||||
scale_cursor_distance(1.0 / (1 - p_relative.y * zoom_speed));
|
||||
}
|
||||
}
|
||||
|
||||
void SpatialEditorViewport::_nav_orbit(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative) {
|
||||
|
||||
real_t degrees_per_pixel = EditorSettings::get_singleton()->get("editors/3d/navigation_feel/orbit_sensitivity");
|
||||
real_t radians_per_pixel = Math::deg2rad(degrees_per_pixel);
|
||||
|
||||
cursor.x_rot += p_relative.y * radians_per_pixel;
|
||||
cursor.y_rot += p_relative.x * radians_per_pixel;
|
||||
if (cursor.x_rot > Math_PI / 2.0)
|
||||
cursor.x_rot = Math_PI / 2.0;
|
||||
if (cursor.x_rot < -Math_PI / 2.0)
|
||||
cursor.x_rot = -Math_PI / 2.0;
|
||||
name = "";
|
||||
_update_name();
|
||||
}
|
||||
|
||||
void SpatialEditorViewport::_nav_look(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative) {
|
||||
|
||||
// Freelook only works properly in perspective.
|
||||
// It technically works too in ortho, but it's awful for a user due to fov being near zero
|
||||
if (!orthogonal) {
|
||||
real_t degrees_per_pixel = EditorSettings::get_singleton()->get("editors/3d/navigation_feel/orbit_sensitivity");
|
||||
real_t radians_per_pixel = Math::deg2rad(degrees_per_pixel);
|
||||
|
||||
// Note: do NOT assume the camera has the "current" transform, because it is interpolated and may have "lag".
|
||||
Transform prev_camera_transform = to_camera_transform(cursor);
|
||||
|
||||
cursor.x_rot += p_relative.y * radians_per_pixel;
|
||||
cursor.y_rot += p_relative.x * radians_per_pixel;
|
||||
if (cursor.x_rot > Math_PI / 2.0)
|
||||
cursor.x_rot = Math_PI / 2.0;
|
||||
if (cursor.x_rot < -Math_PI / 2.0)
|
||||
cursor.x_rot = -Math_PI / 2.0;
|
||||
|
||||
// Look is like the opposite of Orbit: the focus point rotates around the camera
|
||||
Transform camera_transform = to_camera_transform(cursor);
|
||||
Vector3 pos = camera_transform.xform(Vector3(0, 0, 0));
|
||||
Vector3 prev_pos = prev_camera_transform.xform(Vector3(0, 0, 0));
|
||||
Vector3 diff = prev_pos - pos;
|
||||
cursor.pos += diff;
|
||||
|
||||
name = "";
|
||||
_update_name();
|
||||
}
|
||||
}
|
||||
|
||||
void SpatialEditorViewport::set_freelook_active(bool active_now) {
|
||||
|
||||
if (!freelook_active && active_now) {
|
||||
|
|
|
@ -170,6 +170,11 @@ private:
|
|||
void _select_region();
|
||||
bool _gizmo_select(const Vector2 &p_screenpos, bool p_highlight_only = false);
|
||||
|
||||
void _nav_pan(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative);
|
||||
void _nav_zoom(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative);
|
||||
void _nav_orbit(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative);
|
||||
void _nav_look(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative);
|
||||
|
||||
float get_znear() const;
|
||||
float get_zfar() const;
|
||||
float get_fov() const;
|
||||
|
|
|
@ -319,6 +319,15 @@ void InputDefault::parse_input_event(const Ref<InputEvent> &p_event) {
|
|||
set_joy_axis(jm->get_device(), jm->get_axis(), jm->get_axis_value());
|
||||
}
|
||||
|
||||
Ref<InputEventGesture> ge = p_event;
|
||||
|
||||
if (ge.is_valid()) {
|
||||
|
||||
if (main_loop) {
|
||||
main_loop->input_event(ge);
|
||||
}
|
||||
}
|
||||
|
||||
if (!p_event->is_echo()) {
|
||||
for (const Map<StringName, InputMap::Action>::Element *E = InputMap::get_singleton()->get_action_map().front(); E; E = E->next()) {
|
||||
|
||||
|
|
|
@ -623,6 +623,16 @@ bool GridMapEditor::forward_spatial_input_event(Camera *p_camera, const Ref<Inpu
|
|||
return do_input_action(p_camera, mm->get_position(), false);
|
||||
}
|
||||
|
||||
Ref<InputEventPanGesture> pan_gesture = p_event;
|
||||
if (pan_gesture.is_valid()) {
|
||||
|
||||
if (pan_gesture->get_command() || pan_gesture->get_shift()) {
|
||||
const real_t delta = pan_gesture->get_delta().y;
|
||||
floor->set_value(floor->get_value() + SGN(delta));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -85,6 +85,15 @@ static int prev_mouse_y = 0;
|
|||
static int button_mask = 0;
|
||||
static bool mouse_down_control = false;
|
||||
|
||||
static Vector2 get_mouse_pos(NSEvent *event) {
|
||||
|
||||
const NSRect contentRect = [OS_OSX::singleton->window_view frame];
|
||||
const NSPoint p = [event locationInWindow];
|
||||
mouse_x = p.x * OS_OSX::singleton->_mouse_scale([[event window] backingScaleFactor]);
|
||||
mouse_y = (contentRect.size.height - p.y) * OS_OSX::singleton->_mouse_scale([[event window] backingScaleFactor]);
|
||||
return Vector2(mouse_x, mouse_y);
|
||||
}
|
||||
|
||||
@interface GodotApplication : NSApplication
|
||||
@end
|
||||
|
||||
|
@ -508,12 +517,9 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) {
|
|||
mm->set_button_mask(button_mask);
|
||||
prev_mouse_x = mouse_x;
|
||||
prev_mouse_y = mouse_y;
|
||||
const NSRect contentRect = [OS_OSX::singleton->window_view frame];
|
||||
const NSPoint p = [event locationInWindow];
|
||||
mouse_x = p.x * OS_OSX::singleton->_mouse_scale([[event window] backingScaleFactor]);
|
||||
mouse_y = (contentRect.size.height - p.y) * OS_OSX::singleton->_mouse_scale([[event window] backingScaleFactor]);
|
||||
mm->set_position(Vector2(mouse_x, mouse_y));
|
||||
mm->set_global_position(Vector2(mouse_x, mouse_y));
|
||||
const Vector2 pos = get_mouse_pos(event);
|
||||
mm->set_position(pos);
|
||||
mm->set_global_position(pos);
|
||||
Vector2 relativeMotion = Vector2();
|
||||
relativeMotion.x = [event deltaX] * OS_OSX::singleton->_mouse_scale([[event window] backingScaleFactor]);
|
||||
relativeMotion.y = [event deltaY] * OS_OSX::singleton->_mouse_scale([[event window] backingScaleFactor]);
|
||||
|
@ -575,6 +581,15 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) {
|
|||
OS_OSX::singleton->input->set_mouse_in_window(true);
|
||||
}
|
||||
|
||||
- (void)magnifyWithEvent:(NSEvent *)event {
|
||||
Ref<InputEventMagnifyGesture> ev;
|
||||
ev.instance();
|
||||
get_key_modifier_state([event modifierFlags], ev);
|
||||
ev->set_position(get_mouse_pos(event));
|
||||
ev->set_factor([event magnification] + 1.0);
|
||||
OS_OSX::singleton->push_input(ev);
|
||||
}
|
||||
|
||||
- (void)viewDidChangeBackingProperties {
|
||||
// nothing left to do here
|
||||
}
|
||||
|
@ -838,6 +853,18 @@ inline void sendScrollEvent(int button, double factor, int modifierFlags) {
|
|||
OS_OSX::singleton->push_input(sc);
|
||||
}
|
||||
|
||||
inline void sendPanEvent(double dx, double dy, int modifierFlags) {
|
||||
|
||||
Ref<InputEventPanGesture> pg;
|
||||
pg.instance();
|
||||
|
||||
get_key_modifier_state(modifierFlags, pg);
|
||||
Vector2 mouse_pos = Vector2(mouse_x, mouse_y);
|
||||
pg->set_position(mouse_pos);
|
||||
pg->set_delta(Vector2(-dx, -dy));
|
||||
OS_OSX::singleton->push_input(pg);
|
||||
}
|
||||
|
||||
- (void)scrollWheel:(NSEvent *)event {
|
||||
double deltaX, deltaY;
|
||||
|
||||
|
@ -856,11 +883,16 @@ inline void sendScrollEvent(int button, double factor, int modifierFlags) {
|
|||
deltaX = [event deltaX];
|
||||
deltaY = [event deltaY];
|
||||
}
|
||||
if (fabs(deltaX)) {
|
||||
sendScrollEvent(0 > deltaX ? BUTTON_WHEEL_RIGHT : BUTTON_WHEEL_LEFT, fabs(deltaX * 0.3), [event modifierFlags]);
|
||||
}
|
||||
if (fabs(deltaY)) {
|
||||
sendScrollEvent(0 < deltaY ? BUTTON_WHEEL_UP : BUTTON_WHEEL_DOWN, fabs(deltaY * 0.3), [event modifierFlags]);
|
||||
|
||||
if ([event phase] != NSEventPhaseNone || [event momentumPhase] != NSEventPhaseNone) {
|
||||
sendPanEvent(deltaX, deltaY, [event modifierFlags]);
|
||||
} else {
|
||||
if (fabs(deltaX)) {
|
||||
sendScrollEvent(0 > deltaX ? BUTTON_WHEEL_RIGHT : BUTTON_WHEEL_LEFT, fabs(deltaX * 0.3), [event modifierFlags]);
|
||||
}
|
||||
if (fabs(deltaY)) {
|
||||
sendScrollEvent(0 < deltaY ? BUTTON_WHEEL_UP : BUTTON_WHEEL_DOWN, fabs(deltaY * 0.3), [event modifierFlags]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -964,6 +964,19 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
|
|||
emit_signal("delete_nodes_request");
|
||||
accept_event();
|
||||
}
|
||||
|
||||
Ref<InputEventMagnifyGesture> magnify_gesture = p_ev;
|
||||
if (magnify_gesture.is_valid()) {
|
||||
|
||||
set_zoom_custom(zoom * magnify_gesture->get_factor(), magnify_gesture->get_position());
|
||||
}
|
||||
|
||||
Ref<InputEventPanGesture> pan_gesture = p_ev;
|
||||
if (pan_gesture.is_valid()) {
|
||||
|
||||
h_scroll->set_value(h_scroll->get_value() + h_scroll->get_page() * pan_gesture->get_delta().x / 8);
|
||||
v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() * pan_gesture->get_delta().y / 8);
|
||||
}
|
||||
}
|
||||
|
||||
void GraphEdit::clear_connections() {
|
||||
|
@ -975,6 +988,11 @@ void GraphEdit::clear_connections() {
|
|||
|
||||
void GraphEdit::set_zoom(float p_zoom) {
|
||||
|
||||
set_zoom_custom(p_zoom, get_size() / 2);
|
||||
}
|
||||
|
||||
void GraphEdit::set_zoom_custom(float p_zoom, const Vector2 &p_center) {
|
||||
|
||||
p_zoom = CLAMP(p_zoom, MIN_ZOOM, MAX_ZOOM);
|
||||
if (zoom == p_zoom)
|
||||
return;
|
||||
|
@ -982,7 +1000,7 @@ void GraphEdit::set_zoom(float p_zoom) {
|
|||
zoom_minus->set_disabled(zoom == MIN_ZOOM);
|
||||
zoom_plus->set_disabled(zoom == MAX_ZOOM);
|
||||
|
||||
Vector2 sbofs = (Vector2(h_scroll->get_value(), v_scroll->get_value()) + get_size() / 2) / zoom;
|
||||
Vector2 sbofs = (Vector2(h_scroll->get_value(), v_scroll->get_value()) + p_center) / zoom;
|
||||
|
||||
zoom = p_zoom;
|
||||
top_layer->update();
|
||||
|
@ -992,7 +1010,7 @@ void GraphEdit::set_zoom(float p_zoom) {
|
|||
|
||||
if (is_visible_in_tree()) {
|
||||
|
||||
Vector2 ofs = sbofs * zoom - get_size() / 2;
|
||||
Vector2 ofs = sbofs * zoom - p_center;
|
||||
h_scroll->set_value(ofs.x);
|
||||
v_scroll->set_value(ofs.y);
|
||||
}
|
||||
|
|
|
@ -179,6 +179,7 @@ public:
|
|||
bool is_valid_connection_type(int p_type, int p_with_type) const;
|
||||
|
||||
void set_zoom(float p_zoom);
|
||||
void set_zoom_custom(float p_zoom, const Vector2 &p_center);
|
||||
float get_zoom() const;
|
||||
|
||||
GraphEditFilter *get_top_layer() const { return top_layer; }
|
||||
|
|
|
@ -713,6 +713,12 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ref<InputEventPanGesture> pan_gesture = p_event;
|
||||
if (pan_gesture.is_valid()) {
|
||||
|
||||
scroll_bar->set_value(scroll_bar->get_value() + scroll_bar->get_page() * pan_gesture->get_delta().y / 8);
|
||||
}
|
||||
}
|
||||
|
||||
void ItemList::ensure_current_is_visible() {
|
||||
|
|
|
@ -817,6 +817,16 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
|
|||
}
|
||||
}
|
||||
|
||||
Ref<InputEventPanGesture> pan_gesture = p_event;
|
||||
if (pan_gesture.is_valid()) {
|
||||
|
||||
if (scroll_active)
|
||||
|
||||
vscroll->set_value(vscroll->get_value() + vscroll->get_page() * pan_gesture->get_delta().y * 0.5 / 8);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Ref<InputEventKey> k = p_event;
|
||||
|
||||
if (k.is_valid()) {
|
||||
|
|
|
@ -180,6 +180,17 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) {
|
|||
time_since_motion = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Ref<InputEventPanGesture> pan_gesture = p_gui_input;
|
||||
if (pan_gesture.is_valid()) {
|
||||
|
||||
if (h_scroll->is_visible_in_tree()) {
|
||||
h_scroll->set_value(h_scroll->get_value() + h_scroll->get_page() * pan_gesture->get_delta().x / 8);
|
||||
}
|
||||
if (v_scroll->is_visible_in_tree()) {
|
||||
v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() * pan_gesture->get_delta().y / 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ScrollContainer::_update_scrollbar_position() {
|
||||
|
|
|
@ -1777,46 +1777,10 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
|
|||
if (mb->is_pressed()) {
|
||||
|
||||
if (mb->get_button_index() == BUTTON_WHEEL_UP && !mb->get_command()) {
|
||||
float scroll_factor = 3 * mb->get_factor();
|
||||
if (scrolling) {
|
||||
target_v_scroll = (target_v_scroll - scroll_factor);
|
||||
} else {
|
||||
target_v_scroll = (v_scroll->get_value() - scroll_factor);
|
||||
}
|
||||
|
||||
if (smooth_scroll_enabled) {
|
||||
if (target_v_scroll <= 0) {
|
||||
target_v_scroll = 0;
|
||||
}
|
||||
scrolling = true;
|
||||
set_physics_process(true);
|
||||
} else {
|
||||
v_scroll->set_value(target_v_scroll);
|
||||
}
|
||||
_scroll_up(3 * mb->get_factor());
|
||||
}
|
||||
if (mb->get_button_index() == BUTTON_WHEEL_DOWN && !mb->get_command()) {
|
||||
float scroll_factor = 3 * mb->get_factor();
|
||||
if (scrolling) {
|
||||
target_v_scroll = (target_v_scroll + scroll_factor);
|
||||
} else {
|
||||
target_v_scroll = (v_scroll->get_value() + scroll_factor);
|
||||
}
|
||||
|
||||
if (smooth_scroll_enabled) {
|
||||
int max_v_scroll = get_total_unhidden_rows();
|
||||
if (!scroll_past_end_of_file_enabled) {
|
||||
max_v_scroll -= get_visible_rows();
|
||||
max_v_scroll = CLAMP(max_v_scroll, 0, get_total_unhidden_rows());
|
||||
}
|
||||
|
||||
if (target_v_scroll > max_v_scroll) {
|
||||
target_v_scroll = max_v_scroll;
|
||||
}
|
||||
scrolling = true;
|
||||
set_physics_process(true);
|
||||
} else {
|
||||
v_scroll->set_value(target_v_scroll);
|
||||
}
|
||||
_scroll_down(3 * mb->get_factor());
|
||||
}
|
||||
if (mb->get_button_index() == BUTTON_WHEEL_LEFT) {
|
||||
h_scroll->set_value(h_scroll->get_value() - (100 * mb->get_factor()));
|
||||
|
@ -1973,6 +1937,19 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
|
|||
}
|
||||
}
|
||||
|
||||
const Ref<InputEventPanGesture> pan_gesture = p_gui_input;
|
||||
if (pan_gesture.is_valid()) {
|
||||
|
||||
const real_t delta = pan_gesture->get_delta().y;
|
||||
if (delta < 0) {
|
||||
_scroll_up(-delta);
|
||||
} else {
|
||||
_scroll_down(delta);
|
||||
}
|
||||
h_scroll->set_value(h_scroll->get_value() + pan_gesture->get_delta().x * 100);
|
||||
return;
|
||||
}
|
||||
|
||||
Ref<InputEventMouseMotion> mm = p_gui_input;
|
||||
|
||||
if (mm.is_valid()) {
|
||||
|
@ -3066,6 +3043,50 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
|
|||
}
|
||||
}
|
||||
|
||||
void TextEdit::_scroll_up(real_t p_delta) {
|
||||
|
||||
if (scrolling) {
|
||||
target_v_scroll = (target_v_scroll - p_delta);
|
||||
} else {
|
||||
target_v_scroll = (v_scroll->get_value() - p_delta);
|
||||
}
|
||||
|
||||
if (smooth_scroll_enabled) {
|
||||
if (target_v_scroll <= 0) {
|
||||
target_v_scroll = 0;
|
||||
}
|
||||
scrolling = true;
|
||||
set_physics_process(true);
|
||||
} else {
|
||||
v_scroll->set_value(target_v_scroll);
|
||||
}
|
||||
}
|
||||
|
||||
void TextEdit::_scroll_down(real_t p_delta) {
|
||||
|
||||
if (scrolling) {
|
||||
target_v_scroll = (target_v_scroll + p_delta);
|
||||
} else {
|
||||
target_v_scroll = (v_scroll->get_value() + p_delta);
|
||||
}
|
||||
|
||||
if (smooth_scroll_enabled) {
|
||||
int max_v_scroll = get_total_unhidden_rows();
|
||||
if (!scroll_past_end_of_file_enabled) {
|
||||
max_v_scroll -= get_visible_rows();
|
||||
max_v_scroll = CLAMP(max_v_scroll, 0, get_total_unhidden_rows());
|
||||
}
|
||||
|
||||
if (target_v_scroll > max_v_scroll) {
|
||||
target_v_scroll = max_v_scroll;
|
||||
}
|
||||
scrolling = true;
|
||||
set_physics_process(true);
|
||||
} else {
|
||||
v_scroll->set_value(target_v_scroll);
|
||||
}
|
||||
}
|
||||
|
||||
void TextEdit::_pre_shift_selection() {
|
||||
|
||||
if (!selection.active || selection.selecting_mode == Selection::MODE_NONE) {
|
||||
|
|
|
@ -328,6 +328,9 @@ class TextEdit : public Control {
|
|||
void _update_selection_mode_word();
|
||||
void _update_selection_mode_line();
|
||||
|
||||
void _scroll_up(real_t p_delta);
|
||||
void _scroll_down(real_t p_delta);
|
||||
|
||||
void _pre_shift_selection();
|
||||
void _post_shift_selection();
|
||||
|
||||
|
|
|
@ -2612,6 +2612,12 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
|
|||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
Ref<InputEventPanGesture> pan_gesture = p_event;
|
||||
if (pan_gesture.is_valid()) {
|
||||
|
||||
v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() * pan_gesture->get_delta().y / 8);
|
||||
}
|
||||
}
|
||||
|
||||
bool Tree::edit_selected() {
|
||||
|
|
|
@ -2013,6 +2013,30 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
|
|||
}
|
||||
}
|
||||
|
||||
Ref<InputEventGesture> gesture_event = p_event;
|
||||
if (gesture_event.is_valid()) {
|
||||
|
||||
Size2 pos = gesture_event->get_position();
|
||||
|
||||
Control *over = _gui_find_control(pos);
|
||||
if (over) {
|
||||
|
||||
if (over->can_process()) {
|
||||
|
||||
gesture_event = gesture_event->xformed_by(Transform2D()); //make a copy
|
||||
if (over == gui.mouse_focus) {
|
||||
pos = gui.focus_inv_xform.xform(pos);
|
||||
} else {
|
||||
pos = over->get_global_transform_with_canvas().affine_inverse().xform(pos);
|
||||
}
|
||||
gesture_event->set_position(pos);
|
||||
_gui_call_input(over, gesture_event);
|
||||
}
|
||||
get_tree()->set_input_as_handled();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Ref<InputEventScreenDrag> drag_event = p_event;
|
||||
if (drag_event.is_valid()) {
|
||||
|
||||
|
|
Loading…
Reference in a new issue