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;
}
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);
}

View file

@ -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

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) {

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;
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);

View file

@ -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;

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;
if (b.is_valid()) {
// Button event

View file

@ -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) {

View file

@ -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) {

View file

@ -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;

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());
}
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()) {

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);
}
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;
}

View file

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

View file

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

View file

@ -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; }

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() {

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;
if (k.is_valid()) {

View file

@ -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() {

View file

@ -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) {

View file

@ -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();

View file

@ -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() {

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;
if (drag_event.is_valid()) {