| /* |
| * Copyright 2019 University of Toronto |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| * Authors: Mario Badr, Sameh Attia and Tanner Young-Schultz |
| */ |
| |
| #include "ezgl/callback.hpp" |
| |
| namespace ezgl { |
| |
| // File wide static variables to track whether the middle mouse |
| // button is currently pressed AND the old x and y positions of the mouse pointer |
| bool middle_mouse_button_pressed = false; |
| int last_panning_event_time = 0; |
| double prev_x = 0, prev_y = 0; |
| |
| gboolean press_key(GtkWidget *, GdkEventKey *event, gpointer data) |
| { |
| auto application = static_cast<ezgl::application *>(data); |
| |
| // Call the user-defined key press callback if defined |
| if(application->key_press_callback != nullptr) { |
| // see: https://developer.gnome.org/gdk3/stable/gdk3-Keyboard-Handling.html |
| application->key_press_callback(application, event, gdk_keyval_name(event->keyval)); |
| } |
| |
| return FALSE; // propagate the event |
| } |
| |
| gboolean press_mouse(GtkWidget *, GdkEventButton *event, gpointer data) |
| { |
| auto application = static_cast<ezgl::application *>(data); |
| |
| if(event->type == GDK_BUTTON_PRESS) { |
| |
| // Check for Middle mouse press to support dragging |
| if(event->button == 2) { |
| middle_mouse_button_pressed = true; |
| prev_x = event->x; |
| prev_y = event->y; |
| } |
| |
| // Call the user-defined mouse press callback if defined |
| if(application->mouse_press_callback != nullptr) { |
| ezgl::point2d const widget_coordinates(event->x, event->y); |
| |
| std::string main_canvas_id = application->get_main_canvas_id(); |
| ezgl::canvas *canvas = application->get_canvas(main_canvas_id); |
| |
| ezgl::point2d const world = canvas->get_camera().widget_to_world(widget_coordinates); |
| application->mouse_press_callback(application, event, world.x, world.y); |
| } |
| } |
| |
| return TRUE; // consume the event |
| } |
| |
| gboolean release_mouse(GtkWidget *, GdkEventButton *event, gpointer ) |
| { |
| if(event->type == GDK_BUTTON_RELEASE) { |
| // Check for Middle mouse release to support dragging |
| if(event->button == 2) { |
| middle_mouse_button_pressed = false; |
| } |
| } |
| |
| return TRUE; // consume the event |
| } |
| |
| gboolean move_mouse(GtkWidget *, GdkEventButton *event, gpointer data) |
| { |
| auto application = static_cast<ezgl::application *>(data); |
| |
| if(event->type == GDK_MOTION_NOTIFY) { |
| |
| // Check if the middle mouse is pressed to support dragging |
| if(middle_mouse_button_pressed) { |
| // drop this panning event if we have just served another one |
| if(gtk_get_current_event_time() - last_panning_event_time < 100) |
| return true; |
| |
| last_panning_event_time = gtk_get_current_event_time(); |
| |
| GdkEventMotion *motion_event = (GdkEventMotion *)event; |
| |
| std::string main_canvas_id = application->get_main_canvas_id(); |
| auto canvas = application->get_canvas(main_canvas_id); |
| |
| point2d curr_trans = canvas->get_camera().widget_to_world({motion_event->x, motion_event->y}); |
| point2d prev_trans = canvas->get_camera().widget_to_world({prev_x, prev_y}); |
| |
| double dx = curr_trans.x - prev_trans.x; |
| double dy = curr_trans.y - prev_trans.y; |
| |
| prev_x = motion_event->x; |
| prev_y = motion_event->y; |
| |
| // Flip the delta x to avoid inverted dragging |
| translate(canvas, -dx, -dy); |
| } |
| // Else call the user-defined mouse move callback if defined |
| else if(application->mouse_move_callback != nullptr) { |
| ezgl::point2d const widget_coordinates(event->x, event->y); |
| |
| std::string main_canvas_id = application->get_main_canvas_id(); |
| ezgl::canvas *canvas = application->get_canvas(main_canvas_id); |
| |
| ezgl::point2d const world = canvas->get_camera().widget_to_world(widget_coordinates); |
| application->mouse_move_callback(application, event, world.x, world.y); |
| } |
| } |
| |
| return TRUE; // consume the event |
| } |
| |
| gboolean scroll_mouse(GtkWidget *, GdkEvent *event, gpointer data) |
| { |
| |
| if(event->type == GDK_SCROLL) { |
| auto application = static_cast<ezgl::application *>(data); |
| |
| std::string main_canvas_id = application->get_main_canvas_id(); |
| auto canvas = application->get_canvas(main_canvas_id); |
| |
| GdkEventScroll *scroll_event = (GdkEventScroll *)event; |
| |
| ezgl::point2d scroll_point(scroll_event->x, scroll_event->y); |
| |
| if(scroll_event->direction == GDK_SCROLL_UP) { |
| // Zoom in at the scroll point |
| ezgl::zoom_in(canvas, scroll_point, 5.0 / 3.0); |
| } else if(scroll_event->direction == GDK_SCROLL_DOWN) { |
| // Zoom out at the scroll point |
| ezgl::zoom_out(canvas, scroll_point, 5.0 / 3.0); |
| } else if(scroll_event->direction == GDK_SCROLL_SMOOTH) { |
| // Doesn't seem to be happening |
| } // NOTE: We ignore scroll GDK_SCROLL_LEFT and GDK_SCROLL_RIGHT |
| } |
| return TRUE; |
| } |
| |
| gboolean press_zoom_fit(GtkWidget *, gpointer data) |
| { |
| |
| auto application = static_cast<ezgl::application *>(data); |
| |
| std::string main_canvas_id = application->get_main_canvas_id(); |
| auto canvas = application->get_canvas(main_canvas_id); |
| |
| ezgl::zoom_fit(canvas, canvas->get_camera().get_initial_world()); |
| |
| return TRUE; |
| } |
| |
| gboolean press_zoom_in(GtkWidget *, gpointer data) |
| { |
| |
| auto application = static_cast<ezgl::application *>(data); |
| |
| std::string main_canvas_id = application->get_main_canvas_id(); |
| auto canvas = application->get_canvas(main_canvas_id); |
| |
| ezgl::zoom_in(canvas, 5.0 / 3.0); |
| |
| return TRUE; |
| } |
| |
| gboolean press_zoom_out(GtkWidget *, gpointer data) |
| { |
| |
| auto application = static_cast<ezgl::application *>(data); |
| |
| std::string main_canvas_id = application->get_main_canvas_id(); |
| auto canvas = application->get_canvas(main_canvas_id); |
| |
| ezgl::zoom_out(canvas, 5.0 / 3.0); |
| |
| return TRUE; |
| } |
| |
| gboolean press_up(GtkWidget *, gpointer data) |
| { |
| |
| auto application = static_cast<ezgl::application *>(data); |
| |
| std::string main_canvas_id = application->get_main_canvas_id(); |
| auto canvas = application->get_canvas(main_canvas_id); |
| |
| ezgl::translate_up(canvas, 5.0); |
| |
| return TRUE; |
| } |
| |
| gboolean press_down(GtkWidget *, gpointer data) |
| { |
| |
| auto application = static_cast<ezgl::application *>(data); |
| |
| std::string main_canvas_id = application->get_main_canvas_id(); |
| auto canvas = application->get_canvas(main_canvas_id); |
| |
| ezgl::translate_down(canvas, 5.0); |
| |
| return TRUE; |
| } |
| |
| gboolean press_left(GtkWidget *, gpointer data) |
| { |
| |
| auto application = static_cast<ezgl::application *>(data); |
| |
| std::string main_canvas_id = application->get_main_canvas_id(); |
| auto canvas = application->get_canvas(main_canvas_id); |
| |
| ezgl::translate_left(canvas, 5.0); |
| |
| return TRUE; |
| } |
| |
| gboolean press_right(GtkWidget *, gpointer data) |
| { |
| |
| auto application = static_cast<ezgl::application *>(data); |
| |
| std::string main_canvas_id = application->get_main_canvas_id(); |
| auto canvas = application->get_canvas(main_canvas_id); |
| |
| ezgl::translate_right(canvas, 5.0); |
| |
| return TRUE; |
| } |
| |
| gboolean press_proceed(GtkWidget *, gpointer data) |
| { |
| auto ezgl_app = static_cast<ezgl::application *>(data); |
| ezgl_app->quit(); |
| |
| return TRUE; |
| } |
| } |