From ea4ea9921210856608f91bb4a537ec7302c8142a Mon Sep 17 00:00:00 2001 From: IntelOrca Date: Thu, 24 Apr 2014 18:53:42 +0100 Subject: [PATCH] add more input logic and tooltip window --- projects/openrct2.vcxproj | 2 + projects/openrct2.vcxproj.filters | 6 + src/addresses.h | 4 + src/game.c | 298 ++++++++++++++++++++++++++++-- src/gfx.c | 5 + src/gfx.h | 1 + src/map.c | 5 +- src/widget.c | 5 + src/widget.h | 1 + src/window.c | 16 +- src/window.h | 21 ++- src/window_dropdown.h | 5 + src/window_tooltip.c | 217 ++++++++++++++++++++++ src/window_tooltip.h | 31 ++++ 14 files changed, 587 insertions(+), 30 deletions(-) create mode 100644 src/window_tooltip.c create mode 100644 src/window_tooltip.h diff --git a/projects/openrct2.vcxproj b/projects/openrct2.vcxproj index 2196ebbb79..fafab8457f 100644 --- a/projects/openrct2.vcxproj +++ b/projects/openrct2.vcxproj @@ -45,6 +45,7 @@ + @@ -87,6 +88,7 @@ + diff --git a/projects/openrct2.vcxproj.filters b/projects/openrct2.vcxproj.filters index a701d7fc67..d3571d737f 100644 --- a/projects/openrct2.vcxproj.filters +++ b/projects/openrct2.vcxproj.filters @@ -111,6 +111,9 @@ Header Files + + Header Files + @@ -233,6 +236,9 @@ Source Files + + Windows + diff --git a/src/addresses.h b/src/addresses.h index c005c08743..01f86ae716 100644 --- a/src/addresses.h +++ b/src/addresses.h @@ -83,6 +83,8 @@ #define RCT2_ADDRESS_CURSOR_DRAG_LAST_X 0x009DE52A #define RCT2_ADDRESS_CURSOR_DRAG_LAST_Y 0x009DE52C +#define RCT2_ADDRESS_CURSOR_DRAG_WINDOWNUMBER 0x009DE52E +#define RCT2_ADDRESS_CURSOR_DRAG_WINDOWCLASS 0x009DE530 #define RCT2_ADDRESS_TOOLTIP_WINDOW_CLASS 0x009DE533 #define RCT2_ADDRESS_TOOLTIP_WINDOW_NUMBER 0x009DE534 @@ -166,6 +168,8 @@ #define RCT2_ADDRESS_NEWS_ITEM_LIST 0x013CA754 +#define RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE 0x013CE950 + #define RCT2_ADDRESS_TILE_MAP_ELEMENT_POINTERS 0x013CE9A4 #define RCT2_ADDRESS_CURRENT_ROTATION 0x0141E9E0 diff --git a/src/game.c b/src/game.c index 0de1b92662..9414e9dc2f 100644 --- a/src/game.c +++ b/src/game.c @@ -19,6 +19,7 @@ *****************************************************************************/ #include "addresses.h" +#include "audio.h" #include "rct2.h" #include "game.h" #include "news_item.h" @@ -26,6 +27,7 @@ #include "peep.h" #include "widget.h" #include "window.h" +#include "window_tooltip.h" void game_handle_input(); @@ -260,15 +262,23 @@ static void game_get_next_input(int *x, int *y, int *state) #include POINT _dragPosition; +static void input_mouseover(int x, int y, rct_window *w, int widgetIndex); +static void input_mouseover_widget_check(rct_windowclass windowClass, rct_windownumber windowNumber, int widgetIndex); +static void input_mouseover_widget_flatbutton_invalidate(); +static void input_leftmousedown(int x, int y, rct_window *w, int widgetIndex); + + /** * * rct2: 0x006E8655 */ static void game_handle_input_mouse(int x, int y, int state) { - rct_window *w; + rct_window *w, *w2; rct_widget *widget; int widgetIndex; + rct_windowclass windowClass; + rct_windownumber windowNumber; // Get window and widget under cursor position w = window_find_from_point(x, y); @@ -277,21 +287,15 @@ static void game_handle_input_mouse(int x, int y, int state) switch (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8)) { case INPUT_STATE_RESET: + window_tooltip_reset(x, y); + // fall-through case INPUT_STATE_NORMAL: - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) == 0) { - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_X, uint8) = x; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_Y, uint8) = x; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TIMEOUT, uint8) = 0; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_CLASS, uint8) = 255; - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = 1; - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint32) = 1; - } switch (state) { case 0: - RCT2_CALLPROC_X(0x006E9253, x, y, state, widgetIndex, w, widget, 0); + input_mouseover(x, y, w, widgetIndex); break; case 1: - RCT2_CALLPROC_X(0x006E95F9, x, y, state, widgetIndex, w, widget, 0); + input_leftmousedown(x, y, w, widgetIndex); break; case 3: // Close tooltip @@ -307,7 +311,7 @@ static void game_handle_input_mouse(int x, int y, int state) if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 9) break; w->flags &= ~(1 << 3); - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_VIEWPORT_LEFT; + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_VIEWPORT_DRAG; RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_LAST_X, sint16) = x; RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_LAST_Y, sint16) = y; RCT2_GLOBAL(0x009DE530, rct_windowclass) = w->classification; @@ -334,7 +338,7 @@ static void game_handle_input_mouse(int x, int y, int state) case INPUT_STATE_DRAGGING: RCT2_CALLPROC_X(0x006E8C5C, x, y, state, widgetIndex, w, widget, 0); break; - case INPUT_STATE_VIEWPORT_LEFT: + case INPUT_STATE_VIEWPORT_DRAG: { int dx, dy; @@ -411,7 +415,7 @@ static void game_handle_input_mouse(int x, int y, int state) case INPUT_STATE_DROPDOWN_ACTIVE: RCT2_CALLPROC_X(0x006E8DA7, x, y, state, widgetIndex, w, widget, 0); break; - case INPUT_STATE_VIEWPORT_RIGHT: + case INPUT_STATE_VIEWPORT_LEFT: RCT2_CALLPROC_X(0x006E87B4, x, y, state, widgetIndex, w, widget, 0); break; case INPUT_STATE_SCROLL_LEFT: @@ -425,3 +429,269 @@ static void game_handle_input_mouse(int x, int y, int state) break; } } + +/** + * + * rct2: 0x006E9253 + */ +static void input_mouseover(int x, int y, rct_window *w, int widgetIndex) +{ + // RCT2_CALLPROC_X(0x006E9253, x, y, state, widgetIndex, w, widget, 0); + + rct_windowclass windowClass = 255; + rct_windownumber windowNumber = 0; + rct_widget *widget; + + if (w != NULL) { + windowClass = w->classification; + windowNumber = w->number; + widget = &w->widgets[widgetIndex]; + } + + input_mouseover_widget_check(windowClass, windowNumber, widgetIndex); + + if (w != NULL && widgetIndex != -1 && widget->type == WWT_SCROLL) { + int eax, ebx, ecx, edx, esi, edi, ebp; + eax = x; + ebx = y; + esi = w; + edi = widget; + RCT2_CALLFUNC_X(0x006E9F92, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); // widget_scoll_get_part + eax &= 0xFFFF; + ebx &= 0xFFFF; + ecx &= 0xFFFF; + edx &= 0xFFFF; + if (ecx < 0) + goto showTooltip; + if (ecx == 0) { + RCT2_CALLPROC_X(w->event_handlers[WE_SCROLL_MOUSEOVER], edx, 0, eax, ebx, w, 0, 0); + goto showTooltip; + } else { + + } + } else { + showTooltip: + if (RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_CLASS, rct_windowclass) == 255) { + if (RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_NOT_SHOWN_TICKS, uint16) < 500 || + (RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_X, sint16) == x && + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_Y, sint16) == y) + ) { + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TIMEOUT, uint16) = RCT2_GLOBAL(0x009DE588, uint16); + + int bp = 2000; + if (RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_NOT_SHOWN_TICKS, uint16) <= 1000) + bp = 0; + if (bp > RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TIMEOUT, uint16)) + return; + + window_tooltip_open(w, widgetIndex, x, y); + // RCT2_CALLPROC_X(0x006EA10D, x, y, 0, widgetIndex, w, widget, 0); // window_tooltip_open(); + } + } else { + if (RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_CLASS, rct_windowclass) != w->classification || + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_NUMBER, rct_windownumber) != w->number || + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WIDGET_INDEX, uint16) != widgetIndex + ) { + window_tooltip_close(); + } + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TIMEOUT, uint16) += RCT2_GLOBAL(0x009DE588, uint16); + if (RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TIMEOUT, uint16) < 8000) + return; + window_close_by_id(WC_TOOLTIP, 0); + } + } + + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TIMEOUT, uint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_X, sint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_Y, sint16) = y; +} + +/** + * + * rct2: 0x006E9269 + */ +static void input_mouseover_widget_check(rct_windowclass windowClass, rct_windownumber windowNumber, int widgetIndex) +{ + rct_window *w; + + // Check if widget cursor was over has changed + if (windowClass != RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_OVER_WINDOWCLASS, rct_windowclass) || + windowNumber != RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_OVER_WINDOWNUMBER, rct_windownumber) || + widgetIndex != RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_OVER_WIDGETINDEX, rct_windownumber) + ) { + // Invalidate last widget cursor was on if widget is a flat button + input_mouseover_widget_flatbutton_invalidate(); + + // Set new cursor over widget + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_OVER_WINDOWCLASS, rct_windowclass) = windowClass; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_OVER_WINDOWNUMBER, rct_windowclass) = windowNumber; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_OVER_WIDGETINDEX, rct_windowclass) = widgetIndex; + + // Invalidate new widget cursor is on if widget is a flat button + if (windowClass != 255) + input_mouseover_widget_flatbutton_invalidate(); + } +} + +static void input_mouseover_widget_flatbutton_invalidate() +{ + rct_window *w = window_find_by_id(RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_OVER_WINDOWCLASS, rct_windowclass), RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_OVER_WINDOWNUMBER, rct_windownumber)); + if (w == NULL) + return; + + RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, w, 0, 0); + if (w->widgets[RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_OVER_WIDGETINDEX, rct_windownumber)].type == WWT_FLATBTN) + widget_invalidate(RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_OVER_WINDOWCLASS, rct_windowclass), RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_OVER_WINDOWNUMBER, rct_windownumber), RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_OVER_WIDGETINDEX, rct_windownumber)); +} + +/** + * + * rct2: 0x006E95F9 + */ +static void input_leftmousedown(int x, int y, rct_window *w, int widgetIndex) +{ + // RCT2_CALLPROC_X(0x006E95F9, x, y, state, widgetIndex, w, widget, 0); + + rct_windowclass windowClass = 255; + rct_windownumber windowNumber = 0; + rct_widget *widget; + + if (w != NULL) { + windowClass = w->classification; + windowNumber = w->number; + widget = &w->widgets[widgetIndex]; + } + + window_close_by_id(WC_ERROR, 0); + window_close_by_id(WC_TOOLTIP, 0); + + w = window_find_by_id(windowClass, windowNumber); + if (w == NULL) + return; + + window_bring_to_front(w); + if (widgetIndex == -1) + return; + + switch (widget->type) { + case WWT_FRAME: + case WWT_RESIZE: + if (!(w->flags & WF_RESIZABLE)) + break; + if (w->min_width == w->max_width && w->min_height == w->max_height) + break; + if (x < w->x + w->width - 19 || y < w->y + w->height - 19) + break; + + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_RESIZING; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WIDGETINDEX, uint16) = widgetIndex; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_LAST_X, uint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_LAST_Y, uint16) = y; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_WINDOWCLASS, rct_windowclass) = windowClass; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_WINDOWNUMBER, rct_windownumber) = windowNumber; + break; + case WWT_VIEWPORT: + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_VIEWPORT_LEFT; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_LAST_X, uint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_LAST_Y, uint16) = y; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_WINDOWCLASS, rct_windowclass) = windowClass; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_WINDOWNUMBER, rct_windownumber) = windowNumber; + if (!(RCT2_GLOBAL(0x009DE518, uint32) & (1 << 3))) + break; + + w = window_find_by_id(windowClass, windowNumber); + if (w == NULL) + break; + + RCT2_CALLPROC_X(w->event_handlers[WE_TOOL_DOWN], x, y, 0, RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16), w, 0, 0); + RCT2_GLOBAL(0x009DE518, uint32) |= (1 << 4); + break; + case WWT_CAPTION: + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_DRAGGING; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WIDGETINDEX, uint16) = widgetIndex; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_LAST_X, uint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_LAST_Y, uint16) = y; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_WINDOWCLASS, rct_windowclass) = windowClass; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_WINDOWNUMBER, rct_windownumber) = windowNumber; + break; + case WWT_SCROLL: + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_SCROLL_LEFT; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WIDGETINDEX, uint16) = widgetIndex; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WINDOWCLASS, rct_windowclass) = windowClass; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WINDOWNUMBER, rct_windowclass) = windowNumber; + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_X, uint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_Y, uint16) = y; + + int eax, ebx, ecx, edx, esi, edi, ebp; + eax = x; + ebx = y; + esi = w; + edi = widget; + RCT2_CALLFUNC_X(0x006E9F92, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); // widget_scoll_get_part + eax &= 0xFFFF; + ebx &= 0xFFFF; + ecx &= 0xFFFF; + edx &= 0xFFFF; + + RCT2_GLOBAL(0x009DE548, uint16) = ecx; + RCT2_GLOBAL(0x009DE54C, uint32) = edx; + RCT2_CALLPROC_X(w->event_handlers[WE_UNKNOWN_15], RCT2_GLOBAL(0x009DE54C, uint32), ebx, ecx, edx, w, widget, 0); + switch (ecx) { + case SCROLL_PART_VIEW: + RCT2_CALLPROC_X(w->event_handlers[WE_SCROLL_MOUSEDOWN], edx / sizeof(rct_scroll), ebx, eax, ebx, w, widget, 0); + break; + case SCROLL_PART_HSCROLLBAR_LEFT: + // 0x006E9A60 + RCT2_CALLPROC_X(0x006E9A60, 0, 0, 0, 0, w, 0, 0); + break; + case SCROLL_PART_HSCROLLBAR_RIGHT: + // 0x006E9ABF + RCT2_CALLPROC_X(0x006E9ABF, 0, 0, 0, 0, w, 0, 0); + break; + case SCROLL_PART_HSCROLLBAR_LEFT_TROUGH: + // 0x006E9B47 + RCT2_CALLPROC_X(0x006E9B47, 0, 0, 0, 0, w, 0, 0); + break; + case SCROLL_PART_HSCROLLBAR_RIGHT_TROUGH: + // 0x006E9BB7 + RCT2_CALLPROC_X(0x006E9BB7, 0, 0, 0, 0, w, 0, 0); + break; + case SCROLL_PART_VSCROLLBAR_TOP: + // 0x006E9C37 + RCT2_CALLPROC_X(0x006E9C37, 0, 0, 0, 0, w, 0, 0); + break; + case SCROLL_PART_VSCROLLBAR_BOTTOM: + // 0x006E9C96 + RCT2_CALLPROC_X(0x006E9C96, 0, 0, 0, 0, w, 0, 0); + break; + case SCROLL_PART_VSCROLLBAR_TOP_TROUGH: + // 0x006E9D1E + RCT2_CALLPROC_X(0x006E9D1E, 0, 0, 0, 0, w, 0, 0); + break; + case SCROLL_PART_VSCROLLBAR_BOTTOM_TROUGH: + // 0x006E9D8E + RCT2_CALLPROC_X(0x006E9D8E, 0, 0, 0, 0, w, 0, 0); + break; + } + break; + default: + if (!widget_is_enabled(w, widgetIndex)) + break; + if (widget_is_disabled(w, widgetIndex)) + break; + + sound_play_panned(4, w->x + (widget->left + widget->right) / 2); + + // Set new cursor down widget + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WINDOWCLASS, rct_windowclass) = windowClass; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WINDOWNUMBER, rct_windowclass) = windowNumber; + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WIDGETINDEX, rct_windowclass) = widgetIndex; + RCT2_GLOBAL(0x009DE518, uint32) |= (1 << 0); + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_WIDGET_PRESSED; + RCT2_GLOBAL(0x009DE528, uint16) = 1; + + widget_invalidate(windowClass, windowNumber, widgetIndex); + RCT2_CALLPROC_X(w->event_handlers[WE_MOUSE_DOWN], 0, 0, 0, widgetIndex, w, widget, 0); + break; + } +} \ No newline at end of file diff --git a/src/gfx.c b/src/gfx.c index dac482e2dd..8890e67b5d 100644 --- a/src/gfx.c +++ b/src/gfx.c @@ -89,6 +89,11 @@ void gfx_clear(rct_drawpixelinfo *dpi, int colour) } } +void gfx_draw_pixel(rct_drawpixelinfo *dpi, int x, int y, int colour) +{ + gfx_fill_rect(dpi, x, y, x, y, colour); +} + /** * * rct2: 0x00684466 diff --git a/src/gfx.h b/src/gfx.h index bf9bc4ee73..1280468be3 100644 --- a/src/gfx.h +++ b/src/gfx.h @@ -49,6 +49,7 @@ typedef struct { void gfx_load_g1(); void gfx_clear(rct_drawpixelinfo *dpi, int colour); +void gfx_draw_pixel(rct_drawpixelinfo *dpi, int x, int y, int colour); void gfx_draw_line(rct_drawpixelinfo *dpi, int x1, int y1, int x2, int y2, int colour); void gfx_fill_rect(rct_drawpixelinfo *dpi, int left, int top, int right, int bottom, int colour); void gfx_fill_rect_inset(rct_drawpixelinfo* dpi, short left, short top, short right, short bottom, int colour, short _si); diff --git a/src/map.c b/src/map.c index 67e58eff2f..1e2dc405bd 100644 --- a/src/map.c +++ b/src/map.c @@ -69,15 +69,16 @@ void map_init() for (i = 0; i < MAX_TILE_MAP_ELEMENT_POINTERS; i++) { map_element = GET_MAP_ELEMENT(i); - map_element->type = (MAP_ELEMENT_TYPE_SURFACE << 2) | 1; + map_element->type = (MAP_ELEMENT_TYPE_SURFACE << 2); map_element->flags = MAP_ELEMENT_FLAG_LAST_TILE; map_element->base_height = 14; map_element->clearance_height = 14; - map_element->properties.surface.slope = 1 << 5; + map_element->properties.surface.slope = 0; map_element->properties.surface.grass_length = 1; map_element->properties.surface.ownership = 0; map_element_set_terrain(map_element, TERRAIN_GRASS); + map_element_set_terrain_edge(map_element, TERRAIN_EDGE_ROCK); } RCT2_GLOBAL(0x013B0E70, sint16) = 0; diff --git a/src/widget.c b/src/widget.c index 66762da333..cf4c44f959 100644 --- a/src/widget.c +++ b/src/widget.c @@ -776,6 +776,11 @@ static void widget_draw_image(rct_drawpixelinfo *dpi, rct_window *w, int widgetI } } +int widget_is_enabled(rct_window *w, int widgetIndex) +{ + return w->enabled_widgets & (1LL << widgetIndex); +} + int widget_is_disabled(rct_window *w, int widgetIndex) { return w->disabled_widgets & (1LL << widgetIndex); diff --git a/src/widget.h b/src/widget.h index fd4d385f14..96ac2e6d68 100644 --- a/src/widget.h +++ b/src/widget.h @@ -57,6 +57,7 @@ typedef enum { void widget_scroll_update_thumbs(rct_window *w, int widget_index); void widget_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex); +int widget_is_enabled(rct_window *w, int widgetIndex); int widget_is_disabled(rct_window *w, int widgetIndex); int widget_is_pressed(rct_window *w, int widgetIndex); int widget_is_highlighted(rct_window *w, int widgetIndex); diff --git a/src/window.c b/src/window.c index 24bf1ae9bc..317e7e5ae3 100644 --- a/src/window.c +++ b/src/window.c @@ -109,7 +109,7 @@ rct_window *window_create(int x, int y, int width, int height, uint32 *event_han if (RCT2_NEW_WINDOW == &(RCT2_FIRST_WINDOW[12])) { // Close least recently used window for (w = RCT2_FIRST_WINDOW; w < RCT2_NEW_WINDOW; w++) - if (!(w->flags & (0x01 | 0x02 | 0x200))) + if (!(w->flags & (WF_0 | WF_1 | WF_9))) break; window_close(w); @@ -118,16 +118,16 @@ rct_window *window_create(int x, int y, int width, int height, uint32 *event_han w = RCT2_NEW_WINDOW; // Flags - if (flags & 0x01) { + if (flags & WF_0) { for (; w >= RCT2_FIRST_WINDOW + 1; w--) { - if ((w - 1)->flags & 0x02) + if ((w - 1)->flags & WF_1) continue; - if ((w - 1)->flags & 0x01) + if ((w - 1)->flags & WF_0) break; } - } else if (!(flags & 0x02)) { + } else if (!(flags & WF_1)) { for (; w >= RCT2_FIRST_WINDOW + 1; w--) { - if (!((w - 1)->flags & 0x02)) + if (!((w - 1)->flags & WF_1)) break; } } @@ -143,7 +143,7 @@ rct_window *window_create(int x, int y, int width, int height, uint32 *event_han w->flags = flags; // Play sound - if (!(flags & (0x01 | 0x02))) + if (!(flags & (WF_0 | WF_1))) sound_play_panned(40, x + (width / 2)); w->number = 0; @@ -296,7 +296,7 @@ rct_window *window_find_from_point(int x, int y) if (x < w->x || x >= w->x + w->width || y < w->y || y >= w->y + w->height) continue; - if (w->flags & 0x20) { + if (w->flags & WF_5) { widget_index = window_find_widget_from_point(w, x, y); if (widget_index == -1) continue; diff --git a/src/window.h b/src/window.h index 10d2e2e1d1..0b163c5ded 100644 --- a/src/window.h +++ b/src/window.h @@ -29,8 +29,8 @@ union rct_window_event; typedef void wndproc(struct rct_window*, union rct_window_event*); -typedef sint8 rct_windowclass; -typedef sint16 rct_windownumber; +typedef uint8 rct_windowclass; +typedef uint16 rct_windownumber; typedef struct { rct_windowclass classification; @@ -75,6 +75,10 @@ typedef struct { uint16 flags; // 0x12 } rct_viewport; +/** + * Scroll structure + * size: 0x12 + */ typedef struct { uint16 flags; // 0x00 sint16 h_left; // 0x02 @@ -110,7 +114,7 @@ typedef struct rct_window { rct_windownumber number; // 0x03C uint16 flags; // 0x03E rct_scroll scrolls[3]; // 0x040 - uint8 var_076[0x400]; + uint8 var_076[1024]; sint16 var_476; sint16 pad_478; sint16 var_47A; @@ -182,9 +186,13 @@ typedef enum { WF_DISABLE_VP_SCROLL = 1 << 9, */ + WF_0 = (1 << 0), + WF_1 = (1 << 1), WF_TRANSPARENT = (1 << 4), + WF_5 = (1 << 5), WF_RESIZABLE = (1 << 8), - WF_10, + WF_9 = (1 << 9), + WF_10 = (1 << 10), WF_WHITE_BORDER_ONE = (1 << 12), WF_WHITE_BORDER_MASK = (1 << 12) | (1 << 13), } WINDOW_FLAGS; @@ -222,9 +230,9 @@ enum { INPUT_STATE_NORMAL = 1, INPUT_STATE_WIDGET_PRESSED = 2, INPUT_STATE_DRAGGING = 3, - INPUT_STATE_VIEWPORT_LEFT = 4, + INPUT_STATE_VIEWPORT_DRAG = 4, INPUT_STATE_DROPDOWN_ACTIVE = 5, - INPUT_STATE_VIEWPORT_RIGHT = 6, + INPUT_STATE_VIEWPORT_LEFT = 6, INPUT_STATE_SCROLL_LEFT = 7, INPUT_STATE_RESIZING = 8, }; @@ -236,6 +244,7 @@ enum { WC_TOOLTIP = 5, WC_DROPDOWN = 6, WC_ABOUT = 8, + WC_ERROR = 11, WC_RIDE = 12, WC_RIDE_CONSTRUCTION = 13, WC_RIDE_LIST = 15, diff --git a/src/window_dropdown.h b/src/window_dropdown.h index b193bbdf0d..14d47a8920 100644 --- a/src/window_dropdown.h +++ b/src/window_dropdown.h @@ -18,6 +18,9 @@ * along with this program. If not, see . *****************************************************************************/ +#ifndef _WINDOW_DROPDOWN_H_ +#define _WINDOW_DROPDOWN_H_ + #include "rct2.h" #define DROPDOWN_SEPARATOR 0 @@ -32,3 +35,5 @@ void window_dropdown_show_text(int x, int y, int extray, uint8 colour, uint8 fla void window_dropdown_show_text_custom_width(int x, int y, int extray, uint8 colour, uint8 flags, int num_items, int width); void window_dropdown_show_image(int x, int y, int extray, uint8 colour, uint8 flags, int numItems, int itemWidth, int itemHeight, int numColumns); void window_dropdown_close(); + +#endif \ No newline at end of file diff --git a/src/window_tooltip.c b/src/window_tooltip.c new file mode 100644 index 0000000000..c3cb6aab49 --- /dev/null +++ b/src/window_tooltip.c @@ -0,0 +1,217 @@ +/***************************************************************************** +* Copyright (c) 2014 Ted John +* OpenRCT2, an open source clone of Roller Coaster Tycoon 2. +* +* This file is part of OpenRCT2. +* +* OpenRCT2 is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. + +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. + +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*****************************************************************************/ + +#include +#include "addresses.h" +#include "strings.h" +#include "widget.h" +#include "window.h" + +enum { + WIDX_BACKGROUND +}; + +static rct_widget window_tooltip_widgets[] = { + { WWT_IMGBTN, 0, 0, 199, 0, 31, 0x0FFFFFFFF, STR_NONE }, + { WIDGETS_END }, +}; + +static void window_tooltip_emptysub() { } +static void window_tooltip_onclose(); +static void window_tooltip_update(); +static void window_tooltip_paint(); + +static uint32 window_tooltip_events[] = { + window_tooltip_onclose, + window_tooltip_emptysub, + window_tooltip_emptysub, + window_tooltip_emptysub, + window_tooltip_emptysub, + window_tooltip_emptysub, + window_tooltip_update, + window_tooltip_emptysub, + window_tooltip_emptysub, + window_tooltip_emptysub, + window_tooltip_emptysub, + window_tooltip_emptysub, + window_tooltip_emptysub, + window_tooltip_emptysub, + window_tooltip_emptysub, + window_tooltip_emptysub, + window_tooltip_emptysub, + window_tooltip_emptysub, + window_tooltip_emptysub, + window_tooltip_emptysub, + window_tooltip_emptysub, + window_tooltip_emptysub, + window_tooltip_emptysub, + window_tooltip_emptysub, + window_tooltip_emptysub, + window_tooltip_emptysub, + window_tooltip_paint, + window_tooltip_emptysub +}; + +void window_tooltip_reset(int x, int y) +{ + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_X, uint8) = x; + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_Y, uint8) = y; + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TIMEOUT, uint8) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_CLASS, uint8) = 255; + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = 1; + RCT2_GLOBAL(0x009DE518, uint32) &= ~(1 << 4); +} + +/** + * + * rct2: 0x006EA10D + */ +void window_tooltip_open(rct_window *widgetWindow, int widgetIndex, int x, int y) +{ + rct_window *w; + rct_widget *widget; + int width, height; + + if (widgetWindow == NULL || widgetIndex == -1) + return; + + widget = &widgetWindow->widgets[widgetIndex]; + RCT2_CALLPROC_X(widgetWindow->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, widgetWindow, 0, 0); + if (widget->tooltip == 0xFFFF) + return; + + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_CLASS, rct_windowclass) = widgetWindow->classification; + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_NUMBER, rct_windownumber) = widgetWindow->number; + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WIDGET_INDEX, uint16) = widgetIndex; + + int eax, ebx, ecx, edx, esi, edi, ebp; + eax = widgetIndex; + esi = widgetWindow; + RCT2_CALLFUNC_X(widgetWindow->event_handlers[WE_TOOLTIP], &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + if ((eax & 0xFFFF) == 0xFFFF) + return; + + w = window_find_by_id(WC_ERROR, 0); + if (w != NULL) + return; + + RCT2_GLOBAL(0x0142006C, sint32) = -1; + + format_string(0x0141ED68, widget->tooltip, 0x013CE952); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 224; + + esi = 0x0141ED68; + RCT2_CALLFUNC_X(0x006C23B1, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + ecx &= 0xFFFF; + if (ecx > 196) + ecx = 196; + + esi = 0x0141ED68; + edi = ecx + 1; + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 224; + RCT2_CALLFUNC_X(0x006C21E2, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + ecx &= 0xFFFF; + edi &= 0xFFFF; + + RCT2_GLOBAL(0x01420044, sint16) = edi; + width = ecx + 3; + height = ((edi + 1) * 10) + 4; + window_tooltip_widgets[WIDX_BACKGROUND].right = width; + window_tooltip_widgets[WIDX_BACKGROUND].bottom = height; + + memcpy(0x0141FE44, 0x0141ED68, 512); + + x = clamp(0, x - (width / 2), RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) - width); + y = clamp(22, y + 26, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) - height - 40); + + w = window_create(x, y, width, height, window_tooltip_events, WC_TOOLTIP, WF_TRANSPARENT | WF_1); + w->widgets = window_tooltip_widgets; + + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_NOT_SHOWN_TICKS, uint16) = 0; +} + +/** + * + * rct2: 0x006E98C6 + */ +void window_tooltip_close() +{ + window_close_by_id(WC_TOOLTIP, 0); + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TIMEOUT, uint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_CLASS, rct_windowclass) = 255; + RCT2_GLOBAL(0x0142006C, sint32) = -1; + RCT2_GLOBAL(0x009DE51E, uint8) = 0; +} + +/** + * + * rct2: 0x006EA578 + */ +static void window_tooltip_onclose() +{ + RCT2_GLOBAL(0x009BC3B0, uint8) = 0; +} + +/** + * + * rct2: 0x006EA580 + */ +static void window_tooltip_update() +{ + if (RCT2_GLOBAL(0x009DE51E, uint8) == 0) + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_NOT_SHOWN_TICKS, uint16) = 0; +} + +/** + * + * rct2: 0x006EA41D + */ +static void window_tooltip_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + + __asm mov w, esi + __asm mov dpi, edi + + int left = w->x; + int top = w->y; + int right = w->x + w->width - 1; + int bottom = w->y + w->height - 1; + + // Background + gfx_fill_rect(dpi, left + 1, top + 1, right - 1, bottom - 1, 0x0200002D); + gfx_fill_rect(dpi, left + 1, top + 1, right - 1, bottom - 1, 0x02000084); + + // Sides + gfx_fill_rect(dpi, left + 0, top + 2, left + 0, bottom - 2, 0x0200002F); + gfx_fill_rect(dpi, right + 0, top + 2, right + 0, bottom - 2, 0x0200002F); + gfx_fill_rect(dpi, left + 2, bottom + 0, right - 2, bottom + 0, 0x0200002F); + gfx_fill_rect(dpi, left + 2, top + 0, right - 2, top + 0, 0x0200002F); + + // Corners + gfx_draw_pixel(dpi, left + 1, top + 1, 0x0200002F); + gfx_draw_pixel(dpi, right - 1, top + 1, 0x0200002F); + gfx_draw_pixel(dpi, left + 1, bottom - 1, 0x0200002F); + gfx_draw_pixel(dpi, right - 1, bottom - 1, 0x0200002F); + + // Text + RCT2_CALLPROC_X(0x006C1DB7, 0, 0, w->x + ((w->width + 1) / 2) - 1, w->y + 1, 0x0141FE44, dpi, RCT2_GLOBAL(0x01420044, uint16)); +} \ No newline at end of file diff --git a/src/window_tooltip.h b/src/window_tooltip.h new file mode 100644 index 0000000000..cf05351929 --- /dev/null +++ b/src/window_tooltip.h @@ -0,0 +1,31 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of OpenRCT2. + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#ifndef _WINDOW_TOOLTIP_H_ +#define _WINDOW_TOOLTIP_H_ + +#include "rct2.h" +#include "window.h" + +void window_tooltip_reset(int x, int y); +void window_tooltip_open(rct_window *widgetWindow, int widgetIndex, int x, int y); +void window_tooltip_close(); + +#endif \ No newline at end of file