Merge pull request #4146 from AaronVanGeffen/reposition-mouse

Change mouse scroll zooming behaviour to zoom towards the cursor keeping the map position under the cursor consistent. This new behaviour is opt-out.
This commit is contained in:
Ted John 2016-07-31 12:38:06 +01:00 committed by GitHub
commit 349684b7ce
10 changed files with 100 additions and 20 deletions

View file

@ -4214,6 +4214,8 @@ STR_5902 :Show bounding boxes
STR_5903 :Show paint debug window
STR_5904 :Reset date
STR_5905 :{SMALLFONT}{BLACK}A map generation tool that automatically creates a custom landscape
STR_5906 :Zoom to cursor position
STR_5907 :{SMALLFONT}{BLACK}When enabled, zooming in will centre around the cursor, as opposed to the screen centre.
#############
# Scenarios #

View file

@ -19,6 +19,7 @@
- Feature: Add console command to set scenario initial cash.
- Feature: Objects are scanned from the user directory as well as the RCT2 directory.
- Feature: Objects directory is scanned recursively.
- Feature: Optionally zoom in towards the cursor rather than the screen centre.
- Improve: Performance and reliability of loading objects.
- Improve: Screenshots are now saved with the name of the park and the current date and time.
- Improve: More accurate frame rate calculation

View file

@ -227,7 +227,7 @@ config_property_definition _generalDefinitions[] = {
{ offsetof(general_configuration, last_save_scenario_directory), "last_scenario_directory", CONFIG_VALUE_TYPE_STRING, { .value_string = NULL }, NULL },
{ offsetof(general_configuration, last_save_track_directory), "last_track_directory", CONFIG_VALUE_TYPE_STRING, { .value_string = NULL }, NULL },
{ offsetof(general_configuration, window_limit), "window_limit", CONFIG_VALUE_TYPE_UINT8, WINDOW_LIMIT_MAX, NULL },
{ offsetof(general_configuration, zoom_to_cursor), "zoom_to_cursor", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL },
};
config_property_definition _interfaceDefinitions[] = {

View file

@ -198,6 +198,7 @@ typedef struct general_configuration {
utf8string last_save_scenario_directory;
utf8string last_save_track_directory;
uint8 window_limit;
uint8 zoom_to_cursor;
} general_configuration;
typedef struct interface_configuration {

View file

@ -1445,6 +1445,49 @@ void window_rotate_camera(rct_window *w, int direction)
reset_all_sprite_quadrant_placements();
}
void window_viewport_get_map_coords_by_cursor(rct_window *w, sint16 *map_x, sint16 *map_y, sint16 *offset_x, sint16 *offset_y)
{
// Get mouse position to offset against.
int mouse_x, mouse_y;
platform_get_cursor_position_scaled(&mouse_x, &mouse_y);
// Compute map coordinate by mouse position.
get_map_coordinates_from_pos(mouse_x, mouse_y, VIEWPORT_INTERACTION_MASK_NONE, map_x, map_y, NULL, NULL, NULL);
// Get viewport coordinates centring around the tile.
int base_height = map_element_height(*map_x, *map_y);
int dest_x, dest_y;
center_2d_coordinates(*map_x, *map_y, base_height, &dest_x, &dest_y, w->viewport);
// Rebase mouse position onto centre of window, and compensate for zoom level.
int rebased_x = ((w->width >> 1) - mouse_x) << w->viewport->zoom,
rebased_y = ((w->height >> 1) - mouse_y) << w->viewport->zoom;
// Compute cursor offset relative to tile.
*offset_x = (w->saved_view_x - (dest_x + rebased_x)) << w->viewport->zoom;
*offset_y = (w->saved_view_y - (dest_y + rebased_y)) << w->viewport->zoom;
}
void window_viewport_centre_tile_around_cursor(rct_window *w, sint16 map_x, sint16 map_y, sint16 offset_x, sint16 offset_y)
{
// Get viewport coordinates centring around the tile.
int dest_x, dest_y;
int base_height = map_element_height(map_x, map_y);
center_2d_coordinates(map_x, map_y, base_height, &dest_x, &dest_y, w->viewport);
// Get mouse position to offset against.
int mouse_x, mouse_y;
platform_get_cursor_position_scaled(&mouse_x, &mouse_y);
// Rebase mouse position onto centre of window, and compensate for zoom level.
int rebased_x = ((w->width >> 1) - mouse_x) << w->viewport->zoom,
rebased_y = ((w->height >> 1) - mouse_y) << w->viewport->zoom;
// Apply offset to the viewport.
w->saved_view_x = dest_x + rebased_x + (offset_x >> w->viewport->zoom);
w->saved_view_y = dest_y + rebased_y + (offset_y >> w->viewport->zoom);
}
void window_zoom_set(rct_window *w, int zoomLevel)
{
rct_viewport* v = w->viewport;
@ -1453,12 +1496,18 @@ void window_zoom_set(rct_window *w, int zoomLevel)
if (v->zoom == zoomLevel)
return;
// Zooming to cursor? Remember where we're pointing at the moment.
sint16 saved_map_x, saved_map_y, offset_x, offset_y;
if (gConfigGeneral.zoom_to_cursor) {
window_viewport_get_map_coords_by_cursor(w, &saved_map_x, &saved_map_y, &offset_x, &offset_y);
}
// Zoom in
while (v->zoom > zoomLevel) {
v->zoom--;
w->saved_view_x += v->view_width / 4;
w->saved_view_y += v->view_height / 4;
v->view_width /= 2;
v->view_width /= 2;
v->view_height /= 2;
}
@ -1467,10 +1516,15 @@ void window_zoom_set(rct_window *w, int zoomLevel)
v->zoom++;
w->saved_view_x -= v->view_width / 2;
w->saved_view_y -= v->view_height / 2;
v->view_width *= 2;
v->view_width *= 2;
v->view_height *= 2;
}
// Zooming to cursor? Centre around the tile we were hovering over just now.
if (gConfigGeneral.zoom_to_cursor) {
window_viewport_centre_tile_around_cursor(w, saved_map_x, saved_map_y, offset_x, offset_y);
}
// HACK: Prevents the redraw from failing when there is
// a window on top of the viewport.
window_bring_to_front(w);

View file

@ -574,6 +574,8 @@ rct_window *window_get_main();
void window_scroll_to_viewport(rct_window *w);
void window_scroll_to_location(rct_window *w, int x, int y, int z);
void window_rotate_camera(rct_window *w, int direction);
void window_viewport_get_map_coords_by_cursor(rct_window *w, sint16 *map_x, sint16 *map_y, sint16 *offset_x, sint16 *offset_y);
void window_viewport_centre_tile_around_cursor(rct_window *w, sint16 map_x, sint16 map_y, sint16 offset_x, sint16 offset_y);
void window_zoom_set(rct_window *w, int zoomLevel);
void window_zoom_in(rct_window *w);
void window_zoom_out(rct_window *w);

View file

@ -3336,8 +3336,9 @@ enum {
STR_DEBUG_PAINT_SHOW_BOUND_BOXES = 5902,
STR_DEBUG_DROPDOWN_DEBUG_PAINT = 5903,
STR_CHEAT_RESET_DATE = 5904,
STR_MAP_GENERATOR_TIP = 5905,
STR_ZOOM_TO_CURSOR = 5906,
STR_ZOOM_TO_CURSOR_TIP = 5907,
// Have to include resource strings (from scenarios and objects) for the time being now that language is partially working
STR_COUNT = 32768

View file

@ -166,6 +166,7 @@ bool platform_file_delete(const utf8 *path);
void platform_hide_cursor();
void platform_show_cursor();
void platform_get_cursor_position(int *x, int *y);
void platform_get_cursor_position_scaled(int *x, int *y);
void platform_set_cursor_position(int x, int y);
unsigned int platform_get_ticks();
void platform_resolve_user_data_path();

View file

@ -783,6 +783,15 @@ void platform_get_cursor_position(int *x, int *y)
SDL_GetMouseState(x, y);
}
void platform_get_cursor_position_scaled(int *x, int *y)
{
platform_get_cursor_position(x, y);
// Compensate for window scaling.
*x = (int) ceilf(*x / gConfigGeneral.window_scale);
*y = (int) ceilf(*y / gConfigGeneral.window_scale);
}
void platform_set_cursor_position(int x, int y)
{
SDL_WarpMouseInWindow(NULL, x, y);

View file

@ -129,6 +129,7 @@ enum WINDOW_OPTIONS_WIDGET_IDX {
WIDX_SCREEN_EDGE_SCROLLING,
WIDX_TRAP_CURSOR,
WIDX_INVERT_DRAG,
WIDX_ZOOM_TO_CURSOR,
WIDX_HOTKEY_DROPDOWN,
WIDX_THEMES_GROUP,
WIDX_THEMES,
@ -269,27 +270,28 @@ static rct_widget window_options_audio_widgets[] = {
static rct_widget window_options_controls_and_interface_widgets[] = {
MAIN_OPTIONS_WIDGETS,
{ WWT_GROUPBOX, 1, 5, 304, 53, 129, STR_CONTROLS_GROUP, STR_NONE }, // Controls group
{ WWT_GROUPBOX, 1, 5, 304, 53, 144, STR_CONTROLS_GROUP, STR_NONE }, // Controls group
{ WWT_CHECKBOX, 2, 10, 299, 68, 79, STR_SCREEN_EDGE_SCROLLING, STR_SCREEN_EDGE_SCROLLING_TIP }, // Edge scrolling
{ WWT_CHECKBOX, 2, 10, 299, 83, 94, STR_TRAP_MOUSE, STR_TRAP_MOUSE_TIP }, // Trap mouse
{ WWT_CHECKBOX, 2, 10, 299, 98, 109, STR_INVERT_RIGHT_MOUSE_DRAG, STR_INVERT_RIGHT_MOUSE_DRAG_TIP }, // Invert right mouse dragging
{ WWT_DROPDOWN_BUTTON, 1, 26, 185, 113, 124, STR_HOTKEY, STR_HOTKEY_TIP }, // Set hotkeys buttons
{ WWT_CHECKBOX, 2, 10, 299, 113, 124, STR_ZOOM_TO_CURSOR, STR_ZOOM_TO_CURSOR_TIP }, // Zoom to cursor
{ WWT_DROPDOWN_BUTTON, 1, 26, 185, 128, 139, STR_HOTKEY, STR_HOTKEY_TIP }, // Set hotkeys buttons
{ WWT_GROUPBOX, 1, 5, 304, 133, 179, STR_THEMES_GROUP, STR_NONE }, // Toolbar buttons group
{ WWT_DROPDOWN, 1, 155, 299, 147, 158, STR_NONE, STR_NONE }, // Themes
{ WWT_DROPDOWN_BUTTON, 1, 288, 298, 148, 157, STR_DROPDOWN_GLYPH, STR_CURRENT_THEME_TIP },
{ WWT_DROPDOWN_BUTTON, 1, 10, 145, 163, 174, STR_EDIT_THEMES_BUTTON, STR_EDIT_THEMES_BUTTON_TIP }, // Themes button
{ WWT_GROUPBOX, 1, 5, 304, 148, 194, STR_THEMES_GROUP, STR_NONE }, // Toolbar buttons group
{ WWT_DROPDOWN, 1, 155, 299, 162, 173, STR_NONE, STR_NONE }, // Themes
{ WWT_DROPDOWN_BUTTON, 1, 288, 298, 163, 172, STR_DROPDOWN_GLYPH, STR_CURRENT_THEME_TIP },
{ WWT_DROPDOWN_BUTTON, 1, 10, 145, 178, 189, STR_EDIT_THEMES_BUTTON, STR_EDIT_THEMES_BUTTON_TIP }, // Themes button
{ WWT_GROUPBOX, 1, 5, 304, 183, 245, STR_TOOLBAR_BUTTONS_GROUP, STR_NONE }, // Toolbar buttons group
{ WWT_CHECKBOX, 2, 10, 145, 214, 225, STR_FINANCES_BUTTON_ON_TOOLBAR, STR_FINANCES_BUTTON_ON_TOOLBAR_TIP }, // Finances
{ WWT_CHECKBOX, 2, 10, 145, 229, 240, STR_RESEARCH_BUTTON_ON_TOOLBAR, STR_RESEARCH_BUTTON_ON_TOOLBAR_TIP }, // Research
{ WWT_CHECKBOX, 2, 155, 299, 214, 225, STR_CHEATS_BUTTON_ON_TOOLBAR, STR_CHEATS_BUTTON_ON_TOOLBAR_TIP }, // Cheats
{ WWT_CHECKBOX, 2, 155, 299, 229, 240, STR_SHOW_RECENT_MESSAGES_ON_TOOLBAR, STR_SHOW_RECENT_MESSAGES_ON_TOOLBAR_TIP }, // Recent messages
{ WWT_GROUPBOX, 1, 5, 304, 198, 260, STR_TOOLBAR_BUTTONS_GROUP, STR_NONE }, // Toolbar buttons group
{ WWT_CHECKBOX, 2, 10, 145, 229, 240, STR_FINANCES_BUTTON_ON_TOOLBAR, STR_FINANCES_BUTTON_ON_TOOLBAR_TIP }, // Finances
{ WWT_CHECKBOX, 2, 10, 145, 244, 255, STR_RESEARCH_BUTTON_ON_TOOLBAR, STR_RESEARCH_BUTTON_ON_TOOLBAR_TIP }, // Research
{ WWT_CHECKBOX, 2, 155, 299, 229, 240, STR_CHEATS_BUTTON_ON_TOOLBAR, STR_CHEATS_BUTTON_ON_TOOLBAR_TIP }, // Cheats
{ WWT_CHECKBOX, 2, 155, 299, 244, 255, STR_SHOW_RECENT_MESSAGES_ON_TOOLBAR, STR_SHOW_RECENT_MESSAGES_ON_TOOLBAR_TIP }, // Recent messages
{ WWT_CHECKBOX, 2, 10, 299, 254, 265, STR_SELECT_BY_TRACK_TYPE, STR_SELECT_BY_TRACK_TYPE_TIP }, // Select by track type
{ WWT_DROPDOWN, 2, 155, 299, 269, 280, STR_NONE, STR_NONE }, // Scenario select mode
{ WWT_DROPDOWN_BUTTON, 2, 288, 298, 270, 279, STR_DROPDOWN_GLYPH, STR_SCENARIO_GROUPING_TIP },
{ WWT_CHECKBOX, 2, 18, 299, 284, 295, STR_OPTIONS_SCENARIO_UNLOCKING, STR_SCENARIO_UNLOCKING_TIP }, // Unlocking of scenarios
{ WWT_CHECKBOX, 2, 10, 299, 269, 280, STR_SELECT_BY_TRACK_TYPE, STR_SELECT_BY_TRACK_TYPE_TIP }, // Select by track type
{ WWT_DROPDOWN, 2, 155, 299, 284, 295, STR_NONE, STR_NONE }, // Scenario select mode
{ WWT_DROPDOWN_BUTTON, 2, 288, 298, 285, 294, STR_DROPDOWN_GLYPH, STR_SCENARIO_GROUPING_TIP },
{ WWT_CHECKBOX, 2, 18, 299, 299, 310, STR_OPTIONS_SCENARIO_UNLOCKING, STR_SCENARIO_UNLOCKING_TIP }, // Unlocking of scenarios
{ WIDGETS_END },
};
@ -491,6 +493,7 @@ static uint32 window_options_page_enabled_widgets[] = {
(1 << WIDX_SCREEN_EDGE_SCROLLING) |
(1 << WIDX_TRAP_CURSOR) |
(1 << WIDX_INVERT_DRAG) |
(1 << WIDX_ZOOM_TO_CURSOR) |
(1 << WIDX_HOTKEY_DROPDOWN) |
(1 << WIDX_TOOLBAR_SHOW_FINANCES) |
(1 << WIDX_TOOLBAR_SHOW_RESEARCH) |
@ -694,6 +697,11 @@ static void window_options_mouseup(rct_window *w, int widgetIndex)
SDL_SetWindowGrab(gWindow, gConfigGeneral.trap_cursor ? SDL_TRUE : SDL_FALSE);
window_invalidate(w);
break;
case WIDX_ZOOM_TO_CURSOR:
gConfigGeneral.zoom_to_cursor ^= 1;
config_save_default();
window_invalidate(w);
break;
case WIDX_TOOLBAR_SHOW_FINANCES:
gConfigInterface.toolbar_show_finances ^= 1;
config_save_default();
@ -1556,6 +1564,7 @@ static void window_options_invalidate(rct_window *w)
widget_set_checkbox_value(w, WIDX_SCREEN_EDGE_SCROLLING, gConfigGeneral.edge_scrolling);
widget_set_checkbox_value(w, WIDX_TRAP_CURSOR, gConfigGeneral.trap_cursor);
widget_set_checkbox_value(w, WIDX_INVERT_DRAG, gConfigGeneral.invert_viewport_drag);
widget_set_checkbox_value(w, WIDX_ZOOM_TO_CURSOR, gConfigGeneral.zoom_to_cursor);
widget_set_checkbox_value(w, WIDX_TOOLBAR_SHOW_FINANCES, gConfigInterface.toolbar_show_finances);
widget_set_checkbox_value(w, WIDX_TOOLBAR_SHOW_RESEARCH, gConfigInterface.toolbar_show_research);
widget_set_checkbox_value(w, WIDX_TOOLBAR_SHOW_CHEATS, gConfigInterface.toolbar_show_cheats);