2014-04-02 05:56:26 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
#include "addresses.h"
|
2014-04-03 18:52:25 +02:00
|
|
|
#include "audio.h"
|
2014-04-04 22:46:26 +02:00
|
|
|
#include "gfx.h"
|
2014-04-03 04:08:06 +02:00
|
|
|
#include "rct2.h"
|
2014-04-03 20:49:00 +02:00
|
|
|
#include "widget.h"
|
2014-04-02 05:56:26 +02:00
|
|
|
#include "window.h"
|
2014-04-08 18:52:39 +02:00
|
|
|
#include "viewport.h"
|
2014-04-02 05:56:26 +02:00
|
|
|
|
|
|
|
#define RCT2_FIRST_WINDOW (RCT2_ADDRESS(RCT2_ADDRESS_WINDOW_LIST, rct_window))
|
|
|
|
#define RCT2_LAST_WINDOW (RCT2_GLOBAL(RCT2_ADDRESS_NEW_WINDOW_PTR, rct_window*) - 1)
|
2014-04-03 04:08:06 +02:00
|
|
|
#define RCT2_NEW_WINDOW (RCT2_GLOBAL(RCT2_ADDRESS_NEW_WINDOW_PTR, rct_window*))
|
2014-04-02 05:56:26 +02:00
|
|
|
|
2014-04-08 20:49:04 +02:00
|
|
|
static int window_draw_split(rct_window *w, int left, int top, int right, int bottom);
|
|
|
|
|
2014-04-08 18:52:39 +02:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* rct2: 0x006ED7B0
|
|
|
|
*/
|
|
|
|
void window_dispatch_update_all()
|
2014-04-02 05:56:26 +02:00
|
|
|
{
|
|
|
|
rct_window *w;
|
|
|
|
|
|
|
|
RCT2_GLOBAL(0x01423604, sint32)++;
|
|
|
|
RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_NOT_SHOWN_TICKS, sint16)++;
|
2014-04-09 03:39:28 +02:00
|
|
|
for (w = RCT2_LAST_WINDOW; w >= RCT2_FIRST_WINDOW; w--)
|
2014-04-02 05:56:26 +02:00
|
|
|
RCT2_CALLPROC_X(w->event_handlers[WE_UPDATE], 0, 0, 0, 0, w, 0, 0);
|
|
|
|
|
|
|
|
RCT2_CALLPROC_EBPSAFE(0x006EE411);
|
2014-04-03 04:08:06 +02:00
|
|
|
}
|
|
|
|
|
2014-04-08 18:52:39 +02:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* rct2: 0x006E77A1
|
|
|
|
*/
|
|
|
|
void window_update_all()
|
|
|
|
{
|
|
|
|
rct_window* w;
|
|
|
|
|
|
|
|
RCT2_GLOBAL(0x009E3CD8, sint32)++;
|
|
|
|
// if (RCT2_GLOBAL(0x009E3CD8, sint32) == 224 && RCT2_GLOBAL(0x009ABDF2, sint8) != 0)
|
|
|
|
// RCT2_CALLPROC(0x004067E3); // ddwindow_move_to_top_corner
|
|
|
|
|
|
|
|
if (RCT2_GLOBAL(0x009ABDF2, sint8) == 0)
|
|
|
|
return;
|
|
|
|
|
2014-04-10 19:41:35 +02:00
|
|
|
gfx_draw_all_dirty_blocks();
|
2014-04-08 18:52:39 +02:00
|
|
|
|
|
|
|
for (w = RCT2_FIRST_WINDOW; w < RCT2_NEW_WINDOW; w++)
|
|
|
|
if (w->viewport != NULL)
|
|
|
|
viewport_update_position(w);
|
|
|
|
|
|
|
|
// 1000 tick update
|
|
|
|
RCT2_GLOBAL(0x009DEB7C, sint16) += RCT2_GLOBAL(0x009DE588, sint16);
|
|
|
|
if (RCT2_GLOBAL(0x009DEB7C, sint16) >= 1000) {
|
|
|
|
RCT2_GLOBAL(0x009DEB7C, sint16) = 0;
|
|
|
|
for (w = RCT2_LAST_WINDOW; w >= RCT2_FIRST_WINDOW; w--)
|
|
|
|
RCT2_CALLPROC_X(w->event_handlers[WE_UNKNOWN_07], 0, 0, 0, 0, w, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Border flash invalidation
|
|
|
|
for (w = RCT2_LAST_WINDOW; w >= RCT2_FIRST_WINDOW; w--) {
|
|
|
|
if (w->flags & WF_WHITE_BORDER_MASK) {
|
|
|
|
w->flags -= WF_WHITE_BORDER_ONE;
|
|
|
|
if (!(w->flags & WF_WHITE_BORDER_MASK))
|
|
|
|
window_invalidate(w);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RCT2_CALLPROC_X(0x006E7868, 0, 0, 0, 0, 0, RCT2_ADDRESS(RCT2_ADDRESS_SCREEN_DPI, rct_drawpixelinfo), 0); // process_mouse_wheel_input();
|
|
|
|
}
|
|
|
|
|
2014-04-03 04:08:06 +02:00
|
|
|
/**
|
|
|
|
* Opens a new window.
|
|
|
|
* rct2: 0x006EACA4
|
|
|
|
*
|
|
|
|
* @param x (ax)
|
|
|
|
* @param y (eax >> 16)
|
|
|
|
* @param width (bx)
|
|
|
|
* @param height (ebx >> 16)
|
|
|
|
* @param events (edx)
|
|
|
|
* @param flags (ch)
|
|
|
|
* @param class (cl)
|
|
|
|
*/
|
|
|
|
rct_window *window_create(int x, int y, int width, int height, uint32 *event_handlers, rct_windowclass cls, uint16 flags)
|
|
|
|
{
|
2014-04-03 18:52:25 +02:00
|
|
|
rct_window *w;
|
2014-04-03 04:08:06 +02:00
|
|
|
|
|
|
|
// Check if there are any window slots left
|
|
|
|
if (RCT2_NEW_WINDOW == &(RCT2_FIRST_WINDOW[12])) {
|
|
|
|
// Close least recently used window
|
|
|
|
for (w = RCT2_FIRST_WINDOW; w < RCT2_NEW_WINDOW; w++)
|
2014-04-09 15:43:27 +02:00
|
|
|
if (!(w->flags & (0x01 | 0x02 | 0x200)))
|
2014-04-03 04:08:06 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
window_close(w);
|
|
|
|
}
|
|
|
|
|
|
|
|
w = RCT2_NEW_WINDOW;
|
|
|
|
|
|
|
|
// Flags
|
|
|
|
if (flags & 0x01) {
|
2014-04-09 15:43:27 +02:00
|
|
|
for (; w >= RCT2_FIRST_WINDOW + 1; w--) {
|
|
|
|
if ((w - 1)->flags & 0x02)
|
|
|
|
continue;
|
|
|
|
if ((w - 1)->flags & 0x01)
|
2014-04-03 04:08:06 +02:00
|
|
|
break;
|
2014-04-09 15:43:27 +02:00
|
|
|
}
|
|
|
|
} else if (!(flags & 0x02)) {
|
|
|
|
for (; w >= RCT2_FIRST_WINDOW + 1; w--) {
|
2014-04-03 04:08:06 +02:00
|
|
|
if (!((w - 1)->flags & 0x02))
|
|
|
|
break;
|
2014-04-09 15:43:27 +02:00
|
|
|
}
|
2014-04-03 04:08:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Move w to new window slot
|
|
|
|
if (w != RCT2_NEW_WINDOW)
|
|
|
|
*RCT2_NEW_WINDOW = *w;
|
|
|
|
|
|
|
|
// Setup window
|
|
|
|
w->classification = cls;
|
|
|
|
w->var_4B8 = -1;
|
|
|
|
w->var_4B9 = -1;
|
2014-04-09 15:43:27 +02:00
|
|
|
w->flags = flags;
|
2014-04-03 04:08:06 +02:00
|
|
|
|
|
|
|
// Play sound
|
2014-04-09 15:43:27 +02:00
|
|
|
if (!(flags & (0x01 | 0x02)))
|
2014-04-03 18:52:25 +02:00
|
|
|
sound_play_panned(40, x + (width / 2));
|
2014-04-03 04:08:06 +02:00
|
|
|
|
|
|
|
w->number = 0;
|
|
|
|
w->x = x;
|
|
|
|
w->y = y;
|
|
|
|
w->width = width;
|
|
|
|
w->height = height;
|
|
|
|
w->viewport = NULL;
|
|
|
|
w->event_handlers = event_handlers;
|
|
|
|
w->enabled_widgets = 0;
|
|
|
|
w->disabled_widgets = 0;
|
|
|
|
w->pressed_widgets = 0;
|
|
|
|
w->var_020 = 0;
|
|
|
|
w->var_480 = 0;
|
|
|
|
w->var_482 = 0;
|
|
|
|
w->var_484 = 0;
|
|
|
|
w->var_486 = 0;
|
|
|
|
w->var_488 = 0;
|
2014-04-16 03:05:49 +02:00
|
|
|
w->page = 0;
|
2014-04-03 04:08:06 +02:00
|
|
|
w->var_48C = 0;
|
|
|
|
w->var_48E = 0;
|
|
|
|
w->var_490 = 0;
|
|
|
|
w->var_492 = 0;
|
|
|
|
w->var_4AC = 0;
|
|
|
|
w->var_4AE = 0;
|
|
|
|
RCT2_NEW_WINDOW++;
|
|
|
|
|
2014-04-09 15:43:27 +02:00
|
|
|
window_invalidate(w);
|
2014-04-03 04:08:06 +02:00
|
|
|
return w;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Closes the specified window.
|
|
|
|
* rct2: 0x006ECD4C
|
|
|
|
*
|
|
|
|
* @param window The window to close (esi).
|
|
|
|
*/
|
|
|
|
void window_close(rct_window* window)
|
|
|
|
{
|
|
|
|
int num_windows;
|
|
|
|
|
|
|
|
if (window == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Call close event of window
|
2014-04-08 18:52:39 +02:00
|
|
|
RCT2_CALLPROC_X(window->event_handlers[WE_CLOSE], 0, 0, 0, 0, window, 0, 0);
|
2014-04-03 04:08:06 +02:00
|
|
|
|
|
|
|
window = window_find_by_id(window->classification, window->number);
|
|
|
|
|
|
|
|
// Remove viewport
|
|
|
|
if (window->viewport != NULL) {
|
|
|
|
window->viewport->width = 0;
|
|
|
|
window->viewport = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Invalidate the window (area)
|
|
|
|
window_invalidate(window);
|
|
|
|
|
|
|
|
// Remove window from list and reshift all windows
|
|
|
|
RCT2_NEW_WINDOW--;
|
|
|
|
num_windows = (RCT2_NEW_WINDOW - window);
|
|
|
|
if (num_windows > 0)
|
|
|
|
memmove(window, window + 1, num_windows * sizeof(rct_window));
|
|
|
|
|
2014-04-08 18:52:39 +02:00
|
|
|
viewport_update_pointers();
|
2014-04-03 04:08:06 +02:00
|
|
|
}
|
|
|
|
|
2014-04-09 15:43:27 +02:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* rct2: 0x006ECCF4
|
|
|
|
* @param cls (cl)
|
|
|
|
* @param number (dx)
|
|
|
|
*/
|
|
|
|
void window_close_by_id(rct_windowclass cls, rct_windownumber number)
|
|
|
|
{
|
|
|
|
rct_window* w;
|
|
|
|
|
|
|
|
if (cls & 0x80) {
|
|
|
|
for (w = RCT2_FIRST_WINDOW; w < RCT2_NEW_WINDOW; w++) {
|
|
|
|
if (w->classification == cls) {
|
|
|
|
window_close(w);
|
|
|
|
w = RCT2_FIRST_WINDOW - 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (w = RCT2_FIRST_WINDOW; w < RCT2_NEW_WINDOW; w++) {
|
|
|
|
if (w->classification == cls && w->number == number) {
|
|
|
|
window_close(w);
|
|
|
|
w = RCT2_FIRST_WINDOW - 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-03 04:08:06 +02:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* rct2: 0x006EA8A0
|
|
|
|
* @param cls (cl)
|
|
|
|
* @param number (dx)
|
|
|
|
*/
|
|
|
|
rct_window *window_find_by_id(rct_windowclass cls, rct_windownumber number)
|
|
|
|
{
|
|
|
|
rct_window *w;
|
|
|
|
|
|
|
|
if (cls & 0x80) {
|
|
|
|
for (w = RCT2_FIRST_WINDOW; w < RCT2_NEW_WINDOW; w++)
|
|
|
|
if (w->classification == cls)
|
|
|
|
return w;
|
|
|
|
} else {
|
|
|
|
for (w = RCT2_FIRST_WINDOW; w < RCT2_NEW_WINDOW; w++)
|
|
|
|
if (w->classification == cls && w->number == number)
|
|
|
|
return w;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-04-14 04:09:51 +02:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* rct2: 0x006EA845
|
|
|
|
*/
|
|
|
|
rct_window *window_find_from_point(int x, int y)
|
|
|
|
{
|
|
|
|
rct_window *w, *w2;
|
|
|
|
rct_widget *widget;
|
|
|
|
int widget_index;
|
|
|
|
|
|
|
|
for (w = RCT2_LAST_WINDOW; w >= RCT2_FIRST_WINDOW; w--) {
|
|
|
|
if (x < w->x || x >= w->x + w->width || y < w->y || y >= w->y + w->height)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (w->flags & 0x20) {
|
|
|
|
widget_index = window_find_widget_from_point(w, x, y);
|
|
|
|
if (widget_index == -1)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
widget = &w->widgets[widget_index];
|
|
|
|
}
|
|
|
|
|
|
|
|
return w;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* rct2: 0x006EA594
|
|
|
|
* x (ax)
|
|
|
|
* y (bx)
|
|
|
|
* returns widget_index (edx)
|
|
|
|
* EDI NEEDS TO BE SET TO w->widgets[widget_index] AFTER
|
|
|
|
*/
|
|
|
|
int window_find_widget_from_point(rct_window *w, int x, int y)
|
|
|
|
{
|
|
|
|
rct_widget *widget;
|
|
|
|
int i, widget_index;
|
|
|
|
|
|
|
|
// Invalidate the window
|
|
|
|
RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, w, 0, 0);
|
|
|
|
|
|
|
|
// Find the widget at point x, y
|
|
|
|
widget_index = -1;
|
|
|
|
RCT2_GLOBAL(0x01420074, uint8) = -1;
|
|
|
|
for (i = 0;; i++) {
|
|
|
|
widget = &w->widgets[i];
|
|
|
|
if (widget->type == WWT_LAST) {
|
|
|
|
break;
|
|
|
|
} else if (widget->type != WWT_EMPTY) {
|
|
|
|
if (widget->type == WWT_SCROLL)
|
|
|
|
RCT2_GLOBAL(0x01420074, uint8)++;
|
|
|
|
|
|
|
|
if (x >= w->x + widget->left && x <= w->x + widget->right &&
|
|
|
|
y >= w->y + widget->top && y <= w->y + widget->bottom
|
|
|
|
) {
|
|
|
|
widget_index = i;
|
|
|
|
RCT2_GLOBAL(0x01420075, uint8) = RCT2_GLOBAL(0x01420074, uint8);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return next widget if a dropdown
|
|
|
|
if (widget_index != -1)
|
|
|
|
if (w->widgets[widget_index].type == WWT_DROPDOWN)
|
|
|
|
widget_index++;
|
|
|
|
|
|
|
|
// Return the widget index
|
|
|
|
return widget_index;
|
|
|
|
}
|
|
|
|
|
2014-04-03 04:08:06 +02:00
|
|
|
/**
|
|
|
|
* Invalidates the specified window.
|
|
|
|
* rct2: 0x006EB31A
|
|
|
|
*
|
|
|
|
* @param window The window to invalidate (esi).
|
|
|
|
*/
|
|
|
|
void window_invalidate(rct_window *window)
|
|
|
|
{
|
2014-04-04 22:46:26 +02:00
|
|
|
if (window != NULL)
|
|
|
|
gfx_set_dirty_blocks(window->x, window->y, window->x + window->width, window->y + window->height);
|
|
|
|
}
|
2014-04-03 04:08:06 +02:00
|
|
|
|
2014-04-04 22:46:26 +02:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* rct2: 0x006EC3AC
|
|
|
|
*
|
|
|
|
* @param cls (ax)
|
|
|
|
* @param number (bx)
|
|
|
|
*/
|
|
|
|
void window_invalidate_by_id(uint16 cls, rct_windownumber number)
|
|
|
|
{
|
|
|
|
rct_window* w;
|
|
|
|
rct_widget* widget;
|
|
|
|
uint8 widgetIndex;
|
|
|
|
|
|
|
|
if (cls & 0x80) {
|
|
|
|
widgetIndex = cls >> 8;
|
|
|
|
cls &= 0x7F;
|
|
|
|
for (w = RCT2_FIRST_WINDOW; w < RCT2_NEW_WINDOW; w++) {
|
|
|
|
if (w->classification == cls && w->number == number) {
|
|
|
|
widget = &w->widgets[widgetIndex];
|
|
|
|
if (widget->left != -2) {
|
|
|
|
gfx_set_dirty_blocks(w->x + widget->left, w->y + widget->top,
|
|
|
|
w->x + widget->right + 1, w->y + widget->bottom + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (cls & 0x40) {
|
|
|
|
cls &= 0xBF;
|
|
|
|
for (w = RCT2_FIRST_WINDOW; w < RCT2_NEW_WINDOW; w++)
|
|
|
|
if (w->classification == cls)
|
|
|
|
window_invalidate(w);
|
|
|
|
} else {
|
|
|
|
for (w = RCT2_FIRST_WINDOW; w < RCT2_NEW_WINDOW; w++)
|
|
|
|
if (w->classification == cls && w->number == number)
|
|
|
|
window_invalidate(w);
|
|
|
|
}
|
2014-04-03 04:08:06 +02:00
|
|
|
}
|
|
|
|
|
2014-04-14 22:25:20 +02:00
|
|
|
void widget_invalidate(rct_windowclass cls, rct_windownumber number, int widgetIndex)
|
|
|
|
{
|
|
|
|
window_invalidate_by_id((widgetIndex << 8) | 0x80 | cls, number);
|
|
|
|
}
|
|
|
|
|
2014-04-03 04:08:06 +02:00
|
|
|
/**
|
2014-04-09 03:39:28 +02:00
|
|
|
* Initialises scroll widgets to their virtual size.
|
2014-04-03 04:08:06 +02:00
|
|
|
* rct2: 0x006EAEB8
|
|
|
|
*
|
|
|
|
* @param window The window (esi).
|
|
|
|
*/
|
|
|
|
void window_init_scroll_widgets(rct_window *w)
|
|
|
|
{
|
2014-04-03 20:49:00 +02:00
|
|
|
rct_widget* widget;
|
|
|
|
rct_scroll* scroll;
|
|
|
|
int widget_index, scroll_index;
|
|
|
|
|
|
|
|
widget_index = 0;
|
|
|
|
scroll_index = 0;
|
|
|
|
for (widget = w->widgets; widget->type != WWT_LAST; widget++) {
|
|
|
|
if (widget->type != WWT_SCROLL) {
|
|
|
|
widget_index++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
scroll = &w->scrolls[scroll_index];
|
|
|
|
|
|
|
|
{
|
|
|
|
int _eax = 0, _ebx = scroll_index * sizeof(rct_scroll), _ecx = 0, _edx = 0, _esi = w, _edi = widget_index * sizeof(rct_widget), _ebp = 0;
|
|
|
|
RCT2_CALLFUNC_X(w->event_handlers[WE_SCROLL_GETSIZE], & _eax, &_ebx, &_ecx, &_edx, &_esi, &_edi, &_ebp);
|
|
|
|
|
|
|
|
scroll->h_left = 0;
|
|
|
|
scroll->h_right = _ecx + 1;
|
|
|
|
scroll->v_top = 0;
|
|
|
|
scroll->v_bottom = _edx + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (widget->image & 0x01)
|
|
|
|
scroll->flags |= HSCROLLBAR_VISIBLE;
|
|
|
|
if (widget->image & 0x02)
|
|
|
|
scroll->flags |= VSCROLLBAR_VISIBLE;
|
|
|
|
|
|
|
|
widget_scroll_update_thumbs(w, widget_index);
|
|
|
|
|
|
|
|
widget_index++;
|
|
|
|
scroll_index++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int window_get_scroll_data_index(rct_window *w, int widget_index)
|
|
|
|
{
|
|
|
|
int i, result;
|
|
|
|
|
|
|
|
result = 0;
|
|
|
|
for (i = 0; i < widget_index; i++) {
|
|
|
|
if (w->widgets[i].type == WWT_SCROLL)
|
|
|
|
result++;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* rct2: 0x006ED78A
|
|
|
|
* cls (cl)
|
|
|
|
* number (dx)
|
|
|
|
*/
|
|
|
|
rct_window *window_bring_to_front_by_id(rct_windowclass cls, rct_windownumber number)
|
|
|
|
{
|
|
|
|
rct_window* w;
|
|
|
|
|
|
|
|
w = window_find_by_id(cls, number);
|
|
|
|
if (w != NULL) {
|
|
|
|
w->flags |= WF_WHITE_BORDER_MASK;
|
|
|
|
window_invalidate(w);
|
|
|
|
w = window_bring_to_front(w);
|
|
|
|
}
|
|
|
|
|
|
|
|
return w;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* rct2: 0x006ECDA4
|
|
|
|
*/
|
|
|
|
rct_window *window_bring_to_front(rct_window *w)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
rct_window* v, t;
|
|
|
|
|
|
|
|
if (w->flags & 0x03)
|
|
|
|
return w;
|
|
|
|
|
|
|
|
for (v = RCT2_LAST_WINDOW; v >= RCT2_FIRST_WINDOW; v--)
|
|
|
|
if (!(v->flags & 2))
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (v >= RCT2_FIRST_WINDOW && w != v) {
|
|
|
|
do {
|
|
|
|
t = *w;
|
|
|
|
*w = *(w + 1);
|
|
|
|
*(w + 1) = t;
|
|
|
|
w++;
|
|
|
|
} while (w != v);
|
|
|
|
|
|
|
|
window_invalidate(w);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (w->x + w->width < 20) {
|
|
|
|
i = 20 - w->x;
|
|
|
|
w->x += i;
|
|
|
|
if (w->viewport != NULL)
|
|
|
|
w->viewport->x += i;
|
|
|
|
window_invalidate(w);
|
|
|
|
}
|
|
|
|
|
|
|
|
return w;
|
2014-04-08 18:52:39 +02:00
|
|
|
}
|
|
|
|
|
2014-04-13 23:23:56 +02:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* rct2: 0x006EE6EA
|
|
|
|
*/
|
|
|
|
void window_push_others_below(rct_window *w1)
|
|
|
|
{
|
|
|
|
int push_amount;
|
|
|
|
rct_window* w2;
|
|
|
|
|
|
|
|
// Enumerate through all other windows
|
|
|
|
for (w2 = RCT2_FIRST_WINDOW; w2 < RCT2_NEW_WINDOW; w2++) {
|
|
|
|
if (w1 == w2)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// ?
|
|
|
|
if (w2->flags & 3)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Check if w2 intersects with w1
|
|
|
|
if (w2->x > (w1->x + w1->width) || w2->x + w2->width < w1->x)
|
|
|
|
continue;
|
|
|
|
if (w2->y > (w1->y + w1->height) || w2->y + w2->height < w1->y)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Check if there is room to push it down
|
|
|
|
if (w1->y + w1->height + 80 >= RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Invalidate the window's current area
|
|
|
|
window_invalidate(w2);
|
|
|
|
|
|
|
|
push_amount = w1->y + w1->height - w2->y + 3;
|
|
|
|
w2->y += push_amount;
|
|
|
|
|
|
|
|
// Invalidate the window's new area
|
|
|
|
window_invalidate(w2);
|
|
|
|
|
|
|
|
// Update viewport position if necessary
|
|
|
|
if (w2->viewport != NULL)
|
|
|
|
w2->viewport->y += push_amount;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-09 18:06:47 +02:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* rct2: 0x006EE2E4
|
|
|
|
*/
|
|
|
|
rct_window *window_get_main()
|
|
|
|
{
|
|
|
|
rct_window* w;
|
|
|
|
|
|
|
|
for (w = RCT2_FIRST_WINDOW; w < RCT2_NEW_WINDOW; w++)
|
|
|
|
if (w->classification == WC_MAIN_WINDOW)
|
|
|
|
return w;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-04-11 18:38:15 +02:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* rct2: 0x006E7C9C
|
|
|
|
*/
|
|
|
|
void window_scroll_to_location(rct_window *w, int x, int y, int z)
|
|
|
|
{
|
|
|
|
RCT2_CALLPROC_X(0x006E7C9C, x, 0, y, z , w, 0, 0);
|
|
|
|
}
|
|
|
|
|
2014-04-10 16:14:47 +02:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* rct2: 0x0068881A
|
|
|
|
*/
|
|
|
|
void window_rotate_camera(rct_window *w)
|
|
|
|
{
|
|
|
|
RCT2_CALLPROC_X(0x0068881A, 0, 0, 0, 0, w, 0, 0);
|
|
|
|
}
|
|
|
|
|
2014-04-08 18:52:39 +02:00
|
|
|
/**
|
|
|
|
* Draws a window that is in the specified region.
|
|
|
|
* rct2: 0x006E756C
|
|
|
|
* left (ax)
|
|
|
|
* top (bx)
|
|
|
|
* right (dx)
|
|
|
|
* bottom (bp)
|
|
|
|
*/
|
|
|
|
void window_draw(rct_window *w, int left, int top, int right, int bottom)
|
|
|
|
{
|
2014-04-08 20:49:04 +02:00
|
|
|
rct_window* v;
|
|
|
|
rct_drawpixelinfo *dpi, copy;
|
|
|
|
int overflow;
|
|
|
|
|
|
|
|
char *copyBits;
|
|
|
|
int copyLeft;
|
|
|
|
int copyWidth;
|
|
|
|
int copyPitch;
|
|
|
|
|
|
|
|
// RCT2_CALLPROC_X(0x006E756C, left, top, 0, right, w, 0, bottom);
|
|
|
|
// return;
|
|
|
|
|
|
|
|
// Split window into only the regions that require drawing
|
|
|
|
if (window_draw_split(w, left, top, right, bottom))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Clamp region
|
|
|
|
left = max(left, w->x);
|
|
|
|
top = max(top, w->y);
|
|
|
|
right = min(right, w->x + w->width);
|
|
|
|
bottom = min(bottom, w->y + w->height);
|
|
|
|
if (left >= right)
|
|
|
|
return;
|
|
|
|
if (top >= bottom)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Draw the window in this region
|
|
|
|
for (v = w; v < RCT2_NEW_WINDOW; v++) {
|
|
|
|
// Don't draw overlapping opaque windows, they won't have changed
|
|
|
|
if (w != v && !(v->flags & WF_TRANSPARENT))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
copy = *RCT2_ADDRESS(RCT2_ADDRESS_WINDOW_DPI, rct_drawpixelinfo);
|
|
|
|
dpi = ©
|
|
|
|
|
|
|
|
// Clamp left to 0
|
|
|
|
overflow = left - dpi->x;
|
|
|
|
if (overflow > 0) {
|
|
|
|
dpi->x += overflow;
|
|
|
|
dpi->width -= overflow;
|
|
|
|
if (dpi->width <= 0)
|
|
|
|
continue;
|
|
|
|
dpi->pitch += overflow;
|
|
|
|
dpi->bits += overflow;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Clamp width to right
|
|
|
|
overflow = dpi->x + dpi->width - right;
|
|
|
|
if (overflow > 0) {
|
|
|
|
dpi->width -= overflow;
|
|
|
|
if (dpi->width <= 0)
|
|
|
|
continue;
|
|
|
|
dpi->pitch += overflow;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Clamp top to 0
|
|
|
|
overflow = top - dpi->y;
|
|
|
|
if (overflow > 0) {
|
|
|
|
dpi->y += overflow;
|
|
|
|
dpi->height -= overflow;
|
|
|
|
if (dpi->height <= 0)
|
|
|
|
continue;
|
|
|
|
dpi->bits += (dpi->width + dpi->pitch) * overflow;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Clamp height to bottom
|
|
|
|
overflow = dpi->y + dpi->height - bottom;
|
|
|
|
if (overflow > 0) {
|
|
|
|
dpi->height -= overflow;
|
|
|
|
if (dpi->height <= 0)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
RCT2_GLOBAL(0x01420070, sint32) = v->x;
|
|
|
|
|
|
|
|
// Text colouring
|
|
|
|
RCT2_GLOBAL(0x0141F740, uint8) = v->colours[0] & 0x7F;
|
|
|
|
RCT2_GLOBAL(0x0141F741, uint8) = v->colours[1] & 0x7F;
|
|
|
|
RCT2_GLOBAL(0x0141F742, uint8) = v->colours[2] & 0x7F;
|
|
|
|
RCT2_GLOBAL(0x0141F743, uint8) = v->colours[3] & 0x7F;
|
|
|
|
|
|
|
|
// Invalidate the window
|
|
|
|
RCT2_CALLPROC_X(v->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, v, 0, 0);
|
|
|
|
|
|
|
|
// Paint the window
|
|
|
|
RCT2_CALLPROC_X(v->event_handlers[WE_PAINT], 0, 0, 0, 0, v, dpi, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Splits a drawing of a window into regions that can be seen and are not hidden
|
|
|
|
* by other opaque overlapping windows.
|
|
|
|
*/
|
|
|
|
static int window_draw_split(rct_window *w, int left, int top, int right, int bottom)
|
|
|
|
{
|
|
|
|
rct_window* topwindow;
|
|
|
|
|
|
|
|
// Divide the draws up for only the visible regions of the window recursively
|
|
|
|
for (topwindow = w + 1; topwindow < RCT2_NEW_WINDOW; topwindow++) {
|
|
|
|
// Check if this window overlaps w
|
|
|
|
if (topwindow->x >= right || topwindow->y >= bottom)
|
|
|
|
continue;
|
|
|
|
if (topwindow->x + topwindow->width <= left || topwindow->y + topwindow->height <= top)
|
|
|
|
continue;
|
|
|
|
if (topwindow->flags & WF_TRANSPARENT)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// A window overlaps w, split up the draw into two regions where the window starts to overlap
|
|
|
|
if (topwindow->x > left) {
|
|
|
|
// Split draw at topwindow.left
|
|
|
|
window_draw(w, left, top, topwindow->x, bottom);
|
|
|
|
window_draw(w, topwindow->x, top, right, bottom);
|
|
|
|
} else if (topwindow->x + topwindow->width < right) {
|
|
|
|
// Split draw at topwindow.right
|
|
|
|
window_draw(w, left, top, topwindow->x + topwindow->width, bottom);
|
|
|
|
window_draw(w, topwindow->x + topwindow->width, top, right, bottom);
|
|
|
|
} else if (topwindow->y > top) {
|
|
|
|
// Split draw at topwindow.top
|
|
|
|
window_draw(w, left, top, right, topwindow->y);
|
|
|
|
window_draw(w, left, topwindow->y, right, bottom);
|
|
|
|
} else if (topwindow->y + topwindow->height < bottom) {
|
|
|
|
// Split draw at topwindow.bottom
|
|
|
|
window_draw(w, left, top, right, topwindow->y + topwindow->height);
|
|
|
|
window_draw(w, left, topwindow->y + topwindow->height, right, bottom);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Drawing for this region should be done now, exit
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// No windows overlap
|
|
|
|
return 0;
|
2014-04-09 15:43:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* rct2: 0x006EB15C
|
|
|
|
*
|
|
|
|
* @param window (esi)
|
|
|
|
* @param dpi (edi)
|
|
|
|
*/
|
|
|
|
void window_draw_widgets(rct_window *w, rct_drawpixelinfo *dpi)
|
|
|
|
{
|
2014-04-09 23:35:29 +02:00
|
|
|
rct_widget *widget;
|
|
|
|
int widgetIndex;
|
|
|
|
|
|
|
|
// RCT2_CALLPROC_X(0x006EB15C, 0, 0, 0, 0, w, dpi, 0);
|
|
|
|
// return;
|
|
|
|
|
|
|
|
if ((w->flags & WF_TRANSPARENT) && !(w->flags & 0x20))
|
|
|
|
gfx_fill_rect(dpi, w->x, w->y, w->x + w->width - 1, w->y + w->height - 1, 0x2000000 | 51);
|
|
|
|
|
|
|
|
widgetIndex = 0;
|
|
|
|
for (widget = w->widgets; widget->type != WWT_LAST; widget++) {
|
|
|
|
// Check if widget is outside the draw region
|
|
|
|
if (w->x + widget->left < dpi->x + dpi->width && w->x + widget->right > dpi->x)
|
|
|
|
if (w->y + widget->top < dpi->y + dpi->height && w->y + widget->bottom > dpi->y)
|
|
|
|
widget_draw(dpi, w, widgetIndex);
|
|
|
|
|
|
|
|
widgetIndex++;
|
|
|
|
}
|
2014-04-02 05:56:26 +02:00
|
|
|
}
|