/* * 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(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(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(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(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(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(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(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(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(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(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(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(data); ezgl_app->quit(); return TRUE; } }