Native pan and zoom for macOS

This commit is contained in:
Bernhard Liebl 2017-11-01 21:49:39 +01:00
parent 5ff84070ca
commit 80ad8afc85
21 changed files with 549 additions and 133 deletions

View File

@ -177,6 +177,14 @@ bool InputEventWithModifiers::get_command() const {
return command; 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() { void InputEventWithModifiers::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_alt", "enable"), &InputEventWithModifiers::set_alt); 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_id(get_id());
mb->set_device(get_device()); mb->set_device(get_device());
mb->set_alt(get_alt()); mb->set_modifiers_from_event(this);
mb->set_shift(get_shift());
mb->set_control(get_control());
mb->set_metakey(get_metakey());
mb->set_position(l); mb->set_position(l);
mb->set_global_position(g); 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_id(get_id());
mm->set_device(get_device()); mm->set_device(get_device());
mm->set_alt(get_alt()); mm->set_modifiers_from_event(this);
mm->set_shift(get_shift());
mm->set_control(get_control());
mm->set_metakey(get_metakey());
mm->set_position(l); mm->set_position(l);
mm->set_global_position(g); mm->set_global_position(g);
@ -930,3 +932,75 @@ void InputEventAction::_bind_methods() {
InputEventAction::InputEventAction() { InputEventAction::InputEventAction() {
pressed = false; 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);
}

View File

@ -213,6 +213,8 @@ public:
void set_command(bool p_enabled); void set_command(bool p_enabled);
bool get_command() const; bool get_command() const;
void set_modifiers_from_event(const InputEventWithModifiers *event);
InputEventWithModifiers(); InputEventWithModifiers();
}; };
@ -468,4 +470,42 @@ public:
InputEventAction(); 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 #endif

View File

@ -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) { void AnimationKeyEditor::_notification(int p_what) {

View File

@ -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; Ref<InputEventKey> k = p_event;
if (k.is_valid()) { if (k.is_valid()) {
@ -999,14 +1016,15 @@ void CodeTextEditor::_text_editor_gui_input(const Ref<InputEvent> &p_event) {
void CodeTextEditor::_zoom_in() { void CodeTextEditor::_zoom_in() {
font_resize_val += EDSCALE; font_resize_val += EDSCALE;
_zoom_changed();
if (font_resize_timer->get_time_left() == 0)
font_resize_timer->start();
} }
void CodeTextEditor::_zoom_out() { void CodeTextEditor::_zoom_out() {
font_resize_val -= EDSCALE; font_resize_val -= EDSCALE;
_zoom_changed();
}
void CodeTextEditor::_zoom_changed() {
if (font_resize_timer->get_time_left() == 0) if (font_resize_timer->get_time_left() == 0)
font_resize_timer->start(); font_resize_timer->start();
} }
@ -1067,16 +1085,25 @@ void CodeTextEditor::_complete_request() {
void CodeTextEditor::_font_resize_timeout() { 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"); Ref<DynamicFont> font = text_editor->get_font("font");
if (font.is_valid()) { 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()) { if (new_size != font->get_size()) {
EditorSettings::get_singleton()->set("interface/editor/source_font_size", new_size / EDSCALE); EditorSettings::get_singleton()->set("interface/editor/source_font_size", new_size / EDSCALE);
font->set_size(new_size); 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"); code_complete_timer->connect("timeout", this, "_code_complete_timer_timeout");
font_resize_val = 0; font_resize_val = 0;
font_size = -1;
font_resize_timer = memnew(Timer); font_resize_timer = memnew(Timer);
add_child(font_resize_timer); add_child(font_resize_timer);
font_resize_timer->set_one_shot(true); font_resize_timer->set_one_shot(true);

View File

@ -204,6 +204,7 @@ class CodeTextEditor : public VBoxContainer {
Timer *font_resize_timer; Timer *font_resize_timer;
int font_resize_val; int font_resize_val;
real_t font_size;
Label *error; Label *error;
@ -212,10 +213,12 @@ class CodeTextEditor : public VBoxContainer {
void _update_font(); void _update_font();
void _complete_request(); void _complete_request();
void _font_resize_timeout(); void _font_resize_timeout();
bool _add_font_size(int p_delta);
void _text_editor_gui_input(const Ref<InputEvent> &p_event); void _text_editor_gui_input(const Ref<InputEvent> &p_event);
void _zoom_in(); void _zoom_in();
void _zoom_out(); void _zoom_out();
void _zoom_changed();
void _reset_zoom(); void _reset_zoom();
CodeTextEditorCodeCompleteFunc code_complete_func; CodeTextEditorCodeCompleteFunc code_complete_func;

View File

@ -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; Ref<InputEventMouseButton> b = p_event;
if (b.is_valid()) { if (b.is_valid()) {
// Button event // Button event

View File

@ -339,6 +339,19 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
uv_edit_draw->update(); 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) { void Polygon2DEditor::_uv_scroll_changed(float) {

View File

@ -1694,92 +1694,78 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
switch (nav_mode) { switch (nav_mode) {
case NAVIGATION_PAN: { case NAVIGATION_PAN: {
_nav_pan(m, _get_warped_mouse_motion(m));
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;
} break; } break;
case NAVIGATION_ZOOM: { case NAVIGATION_ZOOM: {
real_t zoom_speed = 1 / 80.0; _nav_zoom(m, m->get_relative());
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));
}
} break; } break;
case NAVIGATION_ORBIT: { 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; } break;
case NAVIGATION_LOOK: { case NAVIGATION_LOOK: {
// Freelook only works properly in perspective. _nav_look(m, _get_warped_mouse_motion(m));
// 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);
real_t degrees_per_pixel = EditorSettings::get_singleton()->get("editors/3d/navigation_feel/orbit_sensitivity"); } break;
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". default: {}
Transform prev_camera_transform = to_camera_transform(cursor); }
}
cursor.x_rot += relative.y * radians_per_pixel; Ref<InputEventMagnifyGesture> magnify_gesture = p_event;
cursor.y_rot += relative.x * radians_per_pixel; if (magnify_gesture.is_valid()) {
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 if (is_freelook_active())
Transform camera_transform = to_camera_transform(cursor); scale_freelook_speed(magnify_gesture->get_factor());
Vector3 pos = camera_transform.xform(Vector3(0, 0, 0)); else
Vector3 prev_pos = prev_camera_transform.xform(Vector3(0, 0, 0)); scale_cursor_distance(1.0 / magnify_gesture->get_factor());
Vector3 diff = prev_pos - pos; }
cursor.pos += diff;
name = ""; Ref<InputEventPanGesture> pan_gesture = p_event;
_update_name(); 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; } break;
@ -1885,6 +1871,94 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
accept_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) { void SpatialEditorViewport::set_freelook_active(bool active_now) {
if (!freelook_active && active_now) { if (!freelook_active && active_now) {

View File

@ -170,6 +170,11 @@ private:
void _select_region(); void _select_region();
bool _gizmo_select(const Vector2 &p_screenpos, bool p_highlight_only = false); 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_znear() const;
float get_zfar() const; float get_zfar() const;
float get_fov() const; float get_fov() const;

View File

@ -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()); 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()) { if (!p_event->is_echo()) {
for (const Map<StringName, InputMap::Action>::Element *E = InputMap::get_singleton()->get_action_map().front(); E; E = E->next()) { for (const Map<StringName, InputMap::Action>::Element *E = InputMap::get_singleton()->get_action_map().front(); E; E = E->next()) {

View File

@ -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); 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; return false;
} }

View File

@ -85,6 +85,15 @@ static int prev_mouse_y = 0;
static int button_mask = 0; static int button_mask = 0;
static bool mouse_down_control = false; 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 @interface GodotApplication : NSApplication
@end @end
@ -508,12 +517,9 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) {
mm->set_button_mask(button_mask); mm->set_button_mask(button_mask);
prev_mouse_x = mouse_x; prev_mouse_x = mouse_x;
prev_mouse_y = mouse_y; prev_mouse_y = mouse_y;
const NSRect contentRect = [OS_OSX::singleton->window_view frame]; const Vector2 pos = get_mouse_pos(event);
const NSPoint p = [event locationInWindow]; mm->set_position(pos);
mouse_x = p.x * OS_OSX::singleton->_mouse_scale([[event window] backingScaleFactor]); mm->set_global_position(pos);
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));
Vector2 relativeMotion = Vector2(); Vector2 relativeMotion = Vector2();
relativeMotion.x = [event deltaX] * OS_OSX::singleton->_mouse_scale([[event window] backingScaleFactor]); relativeMotion.x = [event deltaX] * OS_OSX::singleton->_mouse_scale([[event window] backingScaleFactor]);
relativeMotion.y = [event deltaY] * 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); 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 { - (void)viewDidChangeBackingProperties {
// nothing left to do here // nothing left to do here
} }
@ -838,6 +853,18 @@ inline void sendScrollEvent(int button, double factor, int modifierFlags) {
OS_OSX::singleton->push_input(sc); 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 { - (void)scrollWheel:(NSEvent *)event {
double deltaX, deltaY; double deltaX, deltaY;
@ -856,11 +883,16 @@ inline void sendScrollEvent(int button, double factor, int modifierFlags) {
deltaX = [event deltaX]; deltaX = [event deltaX];
deltaY = [event deltaY]; deltaY = [event deltaY];
} }
if (fabs(deltaX)) {
sendScrollEvent(0 > deltaX ? BUTTON_WHEEL_RIGHT : BUTTON_WHEEL_LEFT, fabs(deltaX * 0.3), [event modifierFlags]); if ([event phase] != NSEventPhaseNone || [event momentumPhase] != NSEventPhaseNone) {
} sendPanEvent(deltaX, deltaY, [event modifierFlags]);
if (fabs(deltaY)) { } else {
sendScrollEvent(0 < deltaY ? BUTTON_WHEEL_UP : BUTTON_WHEEL_DOWN, fabs(deltaY * 0.3), [event modifierFlags]); 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]);
}
} }
} }

View File

@ -964,6 +964,19 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
emit_signal("delete_nodes_request"); emit_signal("delete_nodes_request");
accept_event(); 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() { void GraphEdit::clear_connections() {
@ -975,6 +988,11 @@ void GraphEdit::clear_connections() {
void GraphEdit::set_zoom(float p_zoom) { 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); p_zoom = CLAMP(p_zoom, MIN_ZOOM, MAX_ZOOM);
if (zoom == p_zoom) if (zoom == p_zoom)
return; return;
@ -982,7 +1000,7 @@ void GraphEdit::set_zoom(float p_zoom) {
zoom_minus->set_disabled(zoom == MIN_ZOOM); zoom_minus->set_disabled(zoom == MIN_ZOOM);
zoom_plus->set_disabled(zoom == MAX_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; zoom = p_zoom;
top_layer->update(); top_layer->update();
@ -992,7 +1010,7 @@ void GraphEdit::set_zoom(float p_zoom) {
if (is_visible_in_tree()) { if (is_visible_in_tree()) {
Vector2 ofs = sbofs * zoom - get_size() / 2; Vector2 ofs = sbofs * zoom - p_center;
h_scroll->set_value(ofs.x); h_scroll->set_value(ofs.x);
v_scroll->set_value(ofs.y); v_scroll->set_value(ofs.y);
} }

View File

@ -179,6 +179,7 @@ public:
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_zoom(float p_zoom); void set_zoom(float p_zoom);
void set_zoom_custom(float p_zoom, const Vector2 &p_center);
float get_zoom() const; float get_zoom() const;
GraphEditFilter *get_top_layer() const { return top_layer; } GraphEditFilter *get_top_layer() const { return top_layer; }

View File

@ -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() { void ItemList::ensure_current_is_visible() {

View File

@ -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; Ref<InputEventKey> k = p_event;
if (k.is_valid()) { if (k.is_valid()) {

View File

@ -180,6 +180,17 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) {
time_since_motion = 0; 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() { void ScrollContainer::_update_scrollbar_position() {

View File

@ -1777,46 +1777,10 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
if (mb->is_pressed()) { if (mb->is_pressed()) {
if (mb->get_button_index() == BUTTON_WHEEL_UP && !mb->get_command()) { if (mb->get_button_index() == BUTTON_WHEEL_UP && !mb->get_command()) {
float scroll_factor = 3 * mb->get_factor(); _scroll_up(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);
}
} }
if (mb->get_button_index() == BUTTON_WHEEL_DOWN && !mb->get_command()) { if (mb->get_button_index() == BUTTON_WHEEL_DOWN && !mb->get_command()) {
float scroll_factor = 3 * mb->get_factor(); _scroll_down(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);
}
} }
if (mb->get_button_index() == BUTTON_WHEEL_LEFT) { if (mb->get_button_index() == BUTTON_WHEEL_LEFT) {
h_scroll->set_value(h_scroll->get_value() - (100 * mb->get_factor())); 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; Ref<InputEventMouseMotion> mm = p_gui_input;
if (mm.is_valid()) { 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() { void TextEdit::_pre_shift_selection() {
if (!selection.active || selection.selecting_mode == Selection::MODE_NONE) { if (!selection.active || selection.selecting_mode == Selection::MODE_NONE) {

View File

@ -328,6 +328,9 @@ class TextEdit : public Control {
void _update_selection_mode_word(); void _update_selection_mode_word();
void _update_selection_mode_line(); void _update_selection_mode_line();
void _scroll_up(real_t p_delta);
void _scroll_down(real_t p_delta);
void _pre_shift_selection(); void _pre_shift_selection();
void _post_shift_selection(); void _post_shift_selection();

View File

@ -2612,6 +2612,12 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
} break; } 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() { bool Tree::edit_selected() {

View File

@ -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; Ref<InputEventScreenDrag> drag_event = p_event;
if (drag_event.is_valid()) { if (drag_event.is_valid()) {