/************************************************************************** Main mouse click handler. **************************************************************************/ static Uint16 main_mouse_button_down_handler(SDL_MouseButtonEvent *pButtonEvent, void *pData) { struct widget *pWidget; if ((pWidget = find_next_widget_at_pos(NULL, pButtonEvent->x, pButtonEvent->y)) != NULL) { if (!(get_wstate(pWidget) == FC_WS_DISABLED)) { return widget_pressed_action(pWidget); } } else { /* no visible widget at this position -> map click */ #ifdef UNDER_CE if (!check_scroll_area(pButtonEvent->x, pButtonEvent->y)) { #endif if (!button_behavior.counting) { /* start counting */ button_behavior.counting = TRUE; button_behavior.button_down_ticks = SDL_GetTicks(); *button_behavior.event = *pButtonEvent; button_behavior.hold_state = MB_HOLD_SHORT; button_behavior.ptile = canvas_pos_to_tile(pButtonEvent->x, pButtonEvent->y); } #ifdef UNDER_CE } #endif } return ID_ERROR; }
/************************************************************************** Put the popup on a smart position, after the real size of the widget is known: left of the cursor if within the right half of the map, and vice versa; displace the popup so as not to obscure it by the mouse cursor; stay always within the map if possible. **************************************************************************/ static void popupinfo_positioning_callback(GtkWidget *w, GtkAllocation *alloc, gpointer data) { struct tmousepos *mousepos = data; gint x, y; struct tile *ptile; ptile = canvas_pos_to_tile(mousepos->x, mousepos->y); if (tile_to_canvas_pos(&x, &y, ptile)) { gint minx, miny, maxy; gdk_window_get_origin(gtk_widget_get_window(map_canvas), &minx, &miny); maxy = miny + gtk_widget_get_allocated_height(map_canvas); if (x > mapview.width/2) { /* right part of the map */ x += minx; y += miny + (tileset_tile_height(tileset) - alloc->height)/2; y = CLIP(miny, y, maxy - alloc->height); gtk_window_move(GTK_WINDOW(w), x - alloc->width, y); } else { /* left part of the map */ x += minx + tileset_tile_width(tileset); y += miny + (tileset_tile_height(tileset) - alloc->height)/2; y = CLIP(miny, y, maxy - alloc->height); gtk_window_move(GTK_WINDOW(w), x, y); } } }
/************************************************************************** Main handler for mouse movement handling. **************************************************************************/ static Uint16 main_mouse_motion_handler(SDL_MouseMotionEvent *pMotionEvent, void *pData) { static struct widget *pWidget; struct tile *ptile; /* stop evaluating button hold time when moving to another tile in medium * hold state or above */ if (button_behavior.counting && (button_behavior.hold_state >= MB_HOLD_MEDIUM)) { ptile = canvas_pos_to_tile(pMotionEvent->x, pMotionEvent->y); if (tile_index(ptile) != tile_index(button_behavior.ptile)) { button_behavior.counting = FALSE; } } if(draw_goto_patrol_lines) { update_line(pMotionEvent->x, pMotionEvent->y); } #ifndef UNDER_CE if (gui_sdl_fullscreen) { check_scroll_area(pMotionEvent->x, pMotionEvent->y); } #endif /* UNDER_CE */ if ((pWidget = find_next_widget_at_pos(NULL, pMotionEvent->x, pMotionEvent->y)) != NULL) { update_mouse_cursor(CURSOR_DEFAULT); if (!(get_wstate(pWidget) == FC_WS_DISABLED)) { widget_sellected_action(pWidget); } } else { if (pSellected_Widget) { unsellect_widget_action(); } else { control_mouse_cursor(canvas_pos_to_tile(pMotionEvent->x, pMotionEvent->y)); } } draw_mouse_cursor(); return ID_ERROR; }
/************************************************************************** ... **************************************************************************/ void mapctrl_btn_mapcanvas(XEvent *event) { XButtonEvent *ev=&event->xbutton; struct tile *ptile = canvas_pos_to_tile(ev->x, ev->y); if (!can_client_change_view()) { return; } if (ev->button == Button1 && (ev->state & ControlMask)) { action_button_pressed(ev->x, ev->y, SELECT_SEA); } else if (ev->button == Button1) { action_button_pressed(ev->x, ev->y, SELECT_POPUP); } else if (ev->button == Button2 && ptile) { popit(ev->x, ev->y, ptile); } else if (ev->button == Button3 && (ev->state & ControlMask)) { action_button_pressed(ev->x, ev->y, SELECT_LAND); } else if (ev->button == Button3) { recenter_button_pressed(ev->x, ev->y); } }
/************************************************************************** Triggered by the mouse moving on the mapcanvas, this function will update the mouse cursor and goto lines. **************************************************************************/ gboolean move_mapcanvas(GtkWidget *w, GdkEventMotion *ev, gpointer data) { if (gui_gtk3_mouse_over_map_focus && !gtk_widget_has_focus(map_canvas)) { gtk_widget_grab_focus(map_canvas); } if (editor_is_active()) { return handle_edit_mouse_move(ev); } cur_x = ev->x; cur_y = ev->y; update_line(ev->x, ev->y); update_rect_at_mouse_pos(); if (keyboardless_goto_button_down && hover_state == HOVER_NONE) { maybe_activate_keyboardless_goto(ev->x, ev->y); } control_mouse_cursor(canvas_pos_to_tile(ev->x, ev->y)); return TRUE; }
/************************************************************************** This function will reset the mouse cursor if it leaves the map. **************************************************************************/ gboolean leave_mapcanvas(GtkWidget *widget, GdkEventCrossing *event) { if (gtk_notebook_get_current_page(GTK_NOTEBOOK(top_notebook)) != gtk_notebook_page_num(GTK_NOTEBOOK(top_notebook), map_widget)) { /* Map is not currently topmost tab. Do not use tile specific cursors. */ update_mouse_cursor(CURSOR_DEFAULT); return TRUE; } /* Bizarrely, this function can be called even when we don't "leave" * the map canvas, for instance, it gets called any time the mouse is * clicked. */ if (map_exists() && event->x >= 0 && event->y >= 0 && event->x < mapview.width && event->y < mapview.height) { control_mouse_cursor(canvas_pos_to_tile(event->x, event->y)); } else { update_mouse_cursor(CURSOR_DEFAULT); } update_unit_info_label(get_units_in_focus()); return TRUE; }
JNIEXPORT jboolean JNICALL Java_net_hackcasual_freeciv_NativeHarness_touchEvent (JNIEnv *je, jobject o, jint x, jint y, jint type) { struct timeval tvs, tve; int nif = 0; static int oldx = -1; static int oldy = -1; lastTouchX = x; lastTouchY = y; int deltax; int deltay; static bool cancelUp; struct tile *plasttile; switch (type) { case 0: { cancelUp = FALSE; oldx = x; oldy = y; plasttile = canvas_pos_to_tile(x,y); break; } case 1: { if (!cancelUp && abs(x - oldx) < 10 && abs(y - oldy) < 10) { can_slide = FALSE; LOGI("ABP Lock"); civ_lock(); action_button_pressed(x,y,SELECT_POPUP); can_slide = TRUE; flush_dirty(); struct tile *ptile = canvas_pos_to_tile(x,y); civ_unlock(); return (ptile && ptile->units)?unit_list_size(ptile->units):0; } else if (!cancelUp) { LOGI("Recenter Lock"); civ_lock(); can_slide = FALSE; recenter_button_pressed(x, y); can_slide = TRUE; flush_dirty(); civ_unlock(); } break; } case 2: { /*hover_state = HOVER_GOTO; control_mouse_cursor(canvas_pos_to_tile(x,y)); update_line(x,y); break;*/ if (cancelUp || abs(x - oldx) > 10 || abs(y - oldy) > 10) { cancelUp = TRUE; LOGI("Slide Lock"); civ_lock(); can_slide = FALSE; deltax = oldx - x; deltay = oldy - y; set_mapview_origin(mapview.gui_x0 + deltax, mapview.gui_y0 + deltay); flush_dirty(); civ_unlock(); oldx = x; oldy = y; can_slide = TRUE; } break; } case 3: { cancelUp = TRUE; break; } } return 0; }
void control_mouse_cursor_pos(int x, int y) { control_mouse_cursor(canvas_pos_to_tile(x, y)); }
/************************************************************************** Handle all mouse button press on canvas. Future feature: User-configurable mouse clicks. **************************************************************************/ gboolean butt_down_mapcanvas(GtkWidget *w, GdkEventButton *ev, gpointer data) { struct city *pcity = NULL; struct tile *ptile = NULL; if (editor_is_active()) { return handle_edit_mouse_button_press(ev); } if (!can_client_change_view()) { return TRUE; } gtk_widget_grab_focus(map_canvas); ptile = canvas_pos_to_tile(ev->x, ev->y); pcity = ptile ? tile_city(ptile) : NULL; switch (ev->button) { case 1: /* LEFT mouse button */ /* <SHIFT> + <CONTROL> + LMB : Adjust workers. */ if ((ev->state & GDK_SHIFT_MASK) && (ev->state & GDK_CONTROL_MASK)) { adjust_workers_button_pressed(ev->x, ev->y); } /* <CONTROL> + LMB : Quickselect a sea unit. */ else if (ev->state & GDK_CONTROL_MASK) { action_button_pressed(ev->x, ev->y, SELECT_SEA); } /* <SHIFT> + LMB: Append focus unit. */ else if (ptile && (ev->state & GDK_SHIFT_MASK)) { action_button_pressed(ev->x, ev->y, SELECT_APPEND); } /* <ALT> + LMB: popit (same as middle-click) */ /* FIXME: we need a general mechanism for letting freeciv work with * 1- or 2-button mice. */ else if (ptile && (ev->state & GDK_MOD1_MASK)) { popit(ev, ptile); } /* LMB in Area Selection mode. */ else if(tiles_hilited_cities) { if (ptile) { toggle_tile_hilite(ptile); } } /* Plain LMB click. */ else { action_button_pressed(ev->x, ev->y, SELECT_POPUP); } break; case 2: /* MIDDLE mouse button */ /* <CONTROL> + MMB: Wake up sentries. */ if (ev->state & GDK_CONTROL_MASK) { wakeup_button_pressed(ev->x, ev->y); } /* Plain Middle click. */ else if (ptile) { popit(ev, ptile); } break; case 3: /* RIGHT mouse button */ /* <CONTROL> + <ALT> + RMB : insert city or tile chat link. */ /* <CONTROL> + <ALT> + <SHIFT> + RMB : insert unit chat link. */ if (ptile && (ev->state & GDK_MOD1_MASK) && (ev->state & GDK_CONTROL_MASK)) { inputline_make_chat_link(ptile, (ev->state & GDK_SHIFT_MASK) != 0); } /* <SHIFT> + <ALT> + RMB : Show/hide workers. */ else if ((ev->state & GDK_SHIFT_MASK) && (ev->state & GDK_MOD1_MASK)) { key_city_overlay(ev->x, ev->y); } /* <SHIFT + CONTROL> + RMB: Paste Production. */ else if ((ev->state & GDK_SHIFT_MASK) && (ev->state & GDK_CONTROL_MASK) && pcity != NULL) { clipboard_paste_production(pcity); cancel_tile_hiliting(); } /* <SHIFT> + RMB on city/unit: Copy Production. */ /* If nothing to copy, fall through to rectangle selection. */ else if (ev->state & GDK_SHIFT_MASK && clipboard_copy_production(ptile)) { /* Already done the copy */ } /* <CONTROL> + RMB : Quickselect a land unit. */ else if (ev->state & GDK_CONTROL_MASK) { action_button_pressed(ev->x, ev->y, SELECT_LAND); } /* Plain RMB click. Area selection. */ else { /* A foolproof user will depress button on canvas, * release it on another widget, and return to canvas * to find rectangle still active. */ if (rectangle_active) { release_right_button(ev->x, ev->y, (ev->state & GDK_SHIFT_MASK) != 0); return TRUE; } if (hover_state == HOVER_NONE) { anchor_selection_rectangle(ev->x, ev->y); rbutton_down = TRUE; /* causes rectangle updates */ } } break; default: break; } return TRUE; }