2022-05-19 01:51:26 -07:00
|
|
|
#include "window_manager_private.h"
|
|
|
|
|
2022-09-15 02:38:23 -07:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
#include "color.h"
|
|
|
|
#include "draw.h"
|
2022-10-04 23:23:27 -07:00
|
|
|
#include "input.h"
|
2022-10-03 06:42:34 -07:00
|
|
|
#include "kb.h"
|
2022-05-19 01:51:26 -07:00
|
|
|
#include "memory.h"
|
2022-10-03 02:41:33 -07:00
|
|
|
#include "mouse.h"
|
2022-10-05 00:35:05 -07:00
|
|
|
#include "svga.h"
|
2022-05-19 01:51:26 -07:00
|
|
|
#include "text_font.h"
|
|
|
|
#include "window_manager.h"
|
|
|
|
|
2022-09-23 05:43:44 -07:00
|
|
|
namespace fallout {
|
|
|
|
|
2023-07-19 23:39:15 -07:00
|
|
|
/// Maximum number of timed messages.
|
|
|
|
static constexpr int kTimedMsgs = 5;
|
|
|
|
|
2023-07-22 20:08:23 -07:00
|
|
|
static int get_num_i(int win, int* value, int max_chars_wcursor, bool clear, bool allow_negative, int x, int y);
|
2023-07-19 23:39:15 -07:00
|
|
|
static void tm_watch_msgs();
|
|
|
|
static void tm_kill_msg();
|
|
|
|
static void tm_kill_out_of_order(int queueIndex);
|
|
|
|
static void tm_click_response(int btn, int keyCode);
|
|
|
|
static bool tm_index_active(int queueIndex);
|
2022-07-04 23:20:56 -07:00
|
|
|
|
2022-05-19 01:51:26 -07:00
|
|
|
// 0x51E414
|
2022-07-04 23:20:56 -07:00
|
|
|
static int _wd = -1;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x51E418
|
2022-07-29 06:04:05 -07:00
|
|
|
static MenuBar* _curr_menu = NULL;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x51E41C
|
2023-07-19 23:39:15 -07:00
|
|
|
static bool tm_watch_active = false;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
2023-07-19 23:39:15 -07:00
|
|
|
// NOTE: Also anonymous in the original code.
|
|
|
|
//
|
2022-05-19 01:51:26 -07:00
|
|
|
// 0x6B2340
|
2023-07-19 23:39:15 -07:00
|
|
|
static struct {
|
|
|
|
bool taken;
|
|
|
|
int y;
|
|
|
|
} tm_location[kTimedMsgs];
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x6B2368
|
2023-07-19 23:39:15 -07:00
|
|
|
static int tm_text_x;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x6B236C
|
2023-07-19 23:39:15 -07:00
|
|
|
static int tm_h;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
2023-07-19 23:39:15 -07:00
|
|
|
// NOTE: Also anonymous in the original code.
|
|
|
|
//
|
2022-05-19 01:51:26 -07:00
|
|
|
// 0x6B2370
|
2023-07-19 23:39:15 -07:00
|
|
|
static struct {
|
|
|
|
unsigned int created;
|
|
|
|
int id;
|
|
|
|
int location;
|
|
|
|
} tm_queue[kTimedMsgs];
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x6B23AC
|
2023-07-19 23:39:15 -07:00
|
|
|
static unsigned int tm_persistence;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x6B23B0
|
2023-07-19 23:39:15 -07:00
|
|
|
static int scr_center_x;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x6B23B4
|
2023-07-19 23:39:15 -07:00
|
|
|
static int tm_text_y;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x6B23B8
|
2023-07-19 23:39:15 -07:00
|
|
|
static int tm_kill;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x6B23BC
|
2023-07-19 23:39:15 -07:00
|
|
|
static int tm_add;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// x
|
|
|
|
//
|
|
|
|
// 0x6B23C0
|
2022-07-04 23:20:56 -07:00
|
|
|
static int _curry;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// y
|
|
|
|
//
|
|
|
|
// 0x6B23C4
|
2022-07-04 23:20:56 -07:00
|
|
|
static int _currx;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x6B23D0
|
|
|
|
char gProgramWindowTitle[256];
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
// 0x4DA6C0
|
2023-04-10 23:01:14 -07:00
|
|
|
int _win_list_select(const char* title, char** fileList, int fileListLength, ListSelectionHandler* callback, int x, int y, int color)
|
2022-07-29 06:04:05 -07:00
|
|
|
{
|
2023-04-10 23:01:14 -07:00
|
|
|
return _win_list_select_at(title, fileList, fileListLength, callback, x, y, color, 0);
|
2022-07-29 06:04:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// 0x4DA70C
|
2023-04-10 23:01:14 -07:00
|
|
|
int _win_list_select_at(const char* title, char** items, int itemsLength, ListSelectionHandler* callback, int x, int y, int color, int start)
|
2022-07-29 06:04:05 -07:00
|
|
|
{
|
|
|
|
if (!gWindowSystemInitialized) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int listViewWidth = _win_width_needed(items, itemsLength);
|
|
|
|
int windowWidth = listViewWidth + 16;
|
|
|
|
|
|
|
|
int titleWidth = fontGetStringWidth(title);
|
|
|
|
if (titleWidth > windowWidth) {
|
|
|
|
windowWidth = titleWidth;
|
|
|
|
listViewWidth = titleWidth - 16;
|
|
|
|
}
|
|
|
|
|
|
|
|
windowWidth += 20;
|
|
|
|
|
|
|
|
int win;
|
|
|
|
int windowHeight;
|
|
|
|
int listViewCapacity = 10;
|
|
|
|
for (int heightMultiplier = 13; heightMultiplier > 8; heightMultiplier--) {
|
|
|
|
windowHeight = heightMultiplier * fontGetLineHeight() + 22;
|
2022-12-12 23:04:05 -08:00
|
|
|
win = windowCreate(x, y, windowWidth, windowHeight, 256, WINDOW_MODAL | WINDOW_MOVE_ON_TOP);
|
2022-07-29 06:04:05 -07:00
|
|
|
if (win != -1) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
listViewCapacity--;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (win == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
Window* window = windowGetWindow(win);
|
|
|
|
Rect* windowRect = &(window->rect);
|
|
|
|
unsigned char* windowBuffer = window->buffer;
|
|
|
|
|
|
|
|
bufferDrawRect(windowBuffer,
|
|
|
|
windowWidth,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
windowWidth - 1,
|
|
|
|
windowHeight - 1,
|
|
|
|
_colorTable[0]);
|
|
|
|
bufferDrawRectShadowed(windowBuffer,
|
|
|
|
windowWidth,
|
|
|
|
1,
|
|
|
|
1,
|
|
|
|
windowWidth - 2,
|
|
|
|
windowHeight - 2,
|
|
|
|
_colorTable[_GNW_wcolor[1]],
|
|
|
|
_colorTable[_GNW_wcolor[2]]);
|
|
|
|
|
|
|
|
bufferFill(windowBuffer + windowWidth * 5 + 5,
|
|
|
|
windowWidth - 11,
|
|
|
|
fontGetLineHeight() + 3,
|
|
|
|
windowWidth,
|
|
|
|
_colorTable[_GNW_wcolor[0]]);
|
|
|
|
|
|
|
|
fontDrawText(windowBuffer + windowWidth / 2 + 8 * windowWidth - fontGetStringWidth(title) / 2,
|
|
|
|
title,
|
|
|
|
windowWidth,
|
|
|
|
windowWidth,
|
|
|
|
_colorTable[_GNW_wcolor[3]]);
|
|
|
|
|
|
|
|
bufferDrawRectShadowed(windowBuffer,
|
|
|
|
windowWidth,
|
|
|
|
5,
|
|
|
|
5,
|
|
|
|
windowWidth - 6,
|
|
|
|
fontGetLineHeight() + 8,
|
|
|
|
_colorTable[_GNW_wcolor[2]],
|
|
|
|
_colorTable[_GNW_wcolor[1]]);
|
|
|
|
|
|
|
|
int listViewX = 8;
|
|
|
|
int listViewY = fontGetLineHeight() + 16;
|
|
|
|
unsigned char* listViewBuffer = windowBuffer + windowWidth * listViewY + listViewX;
|
|
|
|
int listViewMaxY = listViewCapacity * fontGetLineHeight() + listViewY;
|
|
|
|
|
|
|
|
bufferFill(listViewBuffer + windowWidth * (-2) + (-3),
|
|
|
|
listViewWidth + listViewX - 2,
|
|
|
|
listViewCapacity * fontGetLineHeight() + 2,
|
|
|
|
windowWidth,
|
|
|
|
_colorTable[_GNW_wcolor[0]]);
|
|
|
|
|
2023-04-10 23:01:14 -07:00
|
|
|
int scrollOffset = start;
|
|
|
|
if (start < 0 || start >= itemsLength) {
|
2022-07-29 06:04:05 -07:00
|
|
|
scrollOffset = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Relative to `scrollOffset`.
|
|
|
|
int selectedItemIndex;
|
|
|
|
if (itemsLength - scrollOffset < listViewCapacity) {
|
|
|
|
int newScrollOffset = itemsLength - listViewCapacity;
|
|
|
|
if (newScrollOffset < 0) {
|
|
|
|
newScrollOffset = 0;
|
|
|
|
}
|
|
|
|
int oldScrollOffset = scrollOffset;
|
|
|
|
scrollOffset = newScrollOffset;
|
|
|
|
selectedItemIndex = oldScrollOffset - newScrollOffset;
|
|
|
|
} else {
|
|
|
|
selectedItemIndex = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
_win_text(win,
|
2023-04-10 23:01:14 -07:00
|
|
|
items + start,
|
2022-07-29 06:04:05 -07:00
|
|
|
itemsLength < listViewCapacity ? itemsLength : listViewCapacity,
|
|
|
|
listViewWidth,
|
|
|
|
listViewX,
|
|
|
|
listViewY,
|
2023-04-10 23:01:14 -07:00
|
|
|
color | 0x2000000);
|
2022-07-29 06:04:05 -07:00
|
|
|
|
|
|
|
_lighten_buf(listViewBuffer + windowWidth * selectedItemIndex * fontGetLineHeight(),
|
|
|
|
listViewWidth,
|
|
|
|
fontGetLineHeight(),
|
|
|
|
windowWidth);
|
|
|
|
|
|
|
|
bufferDrawRectShadowed(windowBuffer,
|
|
|
|
windowWidth,
|
|
|
|
5,
|
|
|
|
listViewY - 3,
|
|
|
|
listViewWidth + 10,
|
|
|
|
listViewMaxY,
|
|
|
|
_colorTable[_GNW_wcolor[2]],
|
|
|
|
_colorTable[_GNW_wcolor[1]]);
|
|
|
|
|
|
|
|
_win_register_text_button(win,
|
|
|
|
windowWidth - 25,
|
|
|
|
listViewY - 3,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
KEY_ARROW_UP,
|
|
|
|
-1,
|
|
|
|
"\x18",
|
|
|
|
0);
|
|
|
|
|
|
|
|
_win_register_text_button(win,
|
|
|
|
windowWidth - 25,
|
|
|
|
listViewMaxY - fontGetLineHeight() - 5,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
KEY_ARROW_DOWN,
|
|
|
|
-1,
|
|
|
|
"\x19",
|
|
|
|
0);
|
|
|
|
|
|
|
|
_win_register_text_button(win,
|
|
|
|
windowWidth / 2 - 32,
|
|
|
|
windowHeight - 8 - fontGetLineHeight() - 6,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
KEY_ESCAPE,
|
|
|
|
"Done",
|
|
|
|
0);
|
|
|
|
|
|
|
|
int scrollbarX = windowWidth - 21;
|
|
|
|
int scrollbarY = listViewY + fontGetLineHeight() + 7;
|
|
|
|
int scrollbarKnobSize = 14;
|
|
|
|
int scrollbarHeight = listViewMaxY - scrollbarY;
|
|
|
|
unsigned char* scrollbarBuffer = windowBuffer + windowWidth * scrollbarY + scrollbarX;
|
|
|
|
|
|
|
|
bufferFill(scrollbarBuffer,
|
|
|
|
scrollbarKnobSize + 1,
|
|
|
|
scrollbarHeight - fontGetLineHeight() - 8,
|
|
|
|
windowWidth,
|
|
|
|
_colorTable[_GNW_wcolor[0]]);
|
|
|
|
|
|
|
|
buttonCreate(win,
|
|
|
|
scrollbarX,
|
|
|
|
scrollbarY,
|
|
|
|
scrollbarKnobSize + 1,
|
|
|
|
scrollbarHeight - fontGetLineHeight() - 8,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
2048,
|
|
|
|
-1,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
0);
|
|
|
|
|
|
|
|
bufferDrawRectShadowed(windowBuffer,
|
|
|
|
windowWidth,
|
|
|
|
windowWidth - 22,
|
|
|
|
scrollbarY - 1,
|
|
|
|
scrollbarX + scrollbarKnobSize + 1,
|
|
|
|
listViewMaxY - fontGetLineHeight() - 9,
|
|
|
|
_colorTable[_GNW_wcolor[2]],
|
|
|
|
_colorTable[_GNW_wcolor[1]]);
|
|
|
|
bufferDrawRectShadowed(windowBuffer,
|
|
|
|
windowWidth,
|
|
|
|
scrollbarX,
|
|
|
|
scrollbarY,
|
|
|
|
scrollbarX + scrollbarKnobSize,
|
|
|
|
scrollbarY + scrollbarKnobSize,
|
|
|
|
_colorTable[_GNW_wcolor[1]],
|
|
|
|
_colorTable[_GNW_wcolor[2]]);
|
|
|
|
|
|
|
|
_lighten_buf(scrollbarBuffer, scrollbarKnobSize, scrollbarKnobSize, windowWidth);
|
|
|
|
|
|
|
|
for (int index = 0; index < listViewCapacity; index++) {
|
|
|
|
buttonCreate(win,
|
|
|
|
listViewX,
|
|
|
|
listViewY + index * fontGetLineHeight(),
|
|
|
|
listViewWidth,
|
|
|
|
fontGetLineHeight(),
|
|
|
|
512 + index,
|
|
|
|
-1,
|
|
|
|
1024 + index,
|
|
|
|
-1,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
0);
|
|
|
|
}
|
|
|
|
|
|
|
|
buttonCreate(win,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
windowWidth,
|
|
|
|
fontGetLineHeight() + 8,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
2023-07-20 01:13:01 -07:00
|
|
|
BUTTON_DRAG_HANDLE);
|
2022-07-29 06:04:05 -07:00
|
|
|
|
|
|
|
windowRefresh(win);
|
|
|
|
|
|
|
|
int absoluteSelectedItemIndex = -1;
|
|
|
|
|
|
|
|
// Relative to `scrollOffset`.
|
|
|
|
int previousSelectedItemIndex = -1;
|
|
|
|
while (1) {
|
2022-10-07 14:54:27 -07:00
|
|
|
sharedFpsLimiter.mark();
|
|
|
|
|
2022-10-05 00:11:47 -07:00
|
|
|
int keyCode = inputGetInput();
|
2022-07-29 06:04:05 -07:00
|
|
|
int mouseX;
|
|
|
|
int mouseY;
|
|
|
|
mouseGetPosition(&mouseX, &mouseY);
|
|
|
|
|
|
|
|
if (keyCode == KEY_RETURN || (keyCode >= 1024 && keyCode < listViewCapacity + 1024)) {
|
|
|
|
if (selectedItemIndex != -1) {
|
|
|
|
absoluteSelectedItemIndex = scrollOffset + selectedItemIndex;
|
|
|
|
if (absoluteSelectedItemIndex < itemsLength) {
|
|
|
|
if (callback == NULL) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
callback(items, absoluteSelectedItemIndex);
|
|
|
|
}
|
|
|
|
absoluteSelectedItemIndex = -1;
|
|
|
|
}
|
|
|
|
} else if (keyCode == 2048) {
|
|
|
|
if (window->rect.top + scrollbarY > mouseY) {
|
|
|
|
keyCode = KEY_PAGE_UP;
|
|
|
|
} else if (window->rect.top + scrollbarKnobSize + scrollbarY < mouseY) {
|
|
|
|
keyCode = KEY_PAGE_DOWN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (keyCode == KEY_ESCAPE) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (keyCode >= 512 && keyCode < listViewCapacity + 512) {
|
|
|
|
int itemIndex = keyCode - 512;
|
|
|
|
if (itemIndex != selectedItemIndex && itemIndex < itemsLength) {
|
|
|
|
previousSelectedItemIndex = selectedItemIndex;
|
|
|
|
selectedItemIndex = itemIndex;
|
|
|
|
keyCode = -3;
|
|
|
|
} else {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
switch (keyCode) {
|
|
|
|
case KEY_HOME:
|
|
|
|
if (scrollOffset > 0) {
|
|
|
|
keyCode = -4;
|
|
|
|
scrollOffset = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case KEY_ARROW_UP:
|
|
|
|
if (selectedItemIndex > 0) {
|
|
|
|
keyCode = -3;
|
|
|
|
previousSelectedItemIndex = selectedItemIndex;
|
|
|
|
selectedItemIndex -= 1;
|
|
|
|
} else {
|
|
|
|
if (scrollOffset > 0) {
|
|
|
|
keyCode = -4;
|
|
|
|
scrollOffset -= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case KEY_PAGE_UP:
|
|
|
|
if (scrollOffset > 0) {
|
|
|
|
scrollOffset -= listViewCapacity;
|
|
|
|
if (scrollOffset < 0) {
|
|
|
|
scrollOffset = 0;
|
|
|
|
}
|
|
|
|
keyCode = -4;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case KEY_END:
|
|
|
|
if (scrollOffset < itemsLength - listViewCapacity) {
|
|
|
|
keyCode = -4;
|
|
|
|
scrollOffset = itemsLength - listViewCapacity;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case KEY_ARROW_DOWN:
|
|
|
|
if (selectedItemIndex < listViewCapacity - 1 && selectedItemIndex < itemsLength - 1) {
|
|
|
|
keyCode = -3;
|
|
|
|
previousSelectedItemIndex = selectedItemIndex;
|
|
|
|
selectedItemIndex += 1;
|
|
|
|
} else {
|
|
|
|
if (scrollOffset + listViewCapacity < itemsLength) {
|
|
|
|
keyCode = -4;
|
|
|
|
scrollOffset += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case KEY_PAGE_DOWN:
|
|
|
|
if (scrollOffset < itemsLength - listViewCapacity) {
|
|
|
|
scrollOffset += listViewCapacity;
|
|
|
|
if (scrollOffset > itemsLength - listViewCapacity) {
|
|
|
|
scrollOffset = itemsLength - listViewCapacity;
|
|
|
|
}
|
|
|
|
keyCode = -4;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (itemsLength > listViewCapacity) {
|
|
|
|
if ((keyCode >= 'a' && keyCode <= 'z')
|
|
|
|
|| (keyCode >= 'A' && keyCode <= 'Z')) {
|
|
|
|
int found = _find_first_letter(keyCode, items, itemsLength);
|
|
|
|
if (found != -1) {
|
|
|
|
scrollOffset = found;
|
|
|
|
if (scrollOffset > itemsLength - listViewCapacity) {
|
|
|
|
scrollOffset = itemsLength - listViewCapacity;
|
|
|
|
}
|
|
|
|
keyCode = -4;
|
|
|
|
selectedItemIndex = found - scrollOffset;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (keyCode == -4) {
|
|
|
|
bufferFill(listViewBuffer,
|
|
|
|
listViewWidth,
|
|
|
|
listViewMaxY - listViewY,
|
|
|
|
windowWidth,
|
|
|
|
_colorTable[_GNW_wcolor[0]]);
|
|
|
|
|
|
|
|
_win_text(win,
|
|
|
|
items + scrollOffset,
|
|
|
|
itemsLength < listViewCapacity ? itemsLength : listViewCapacity,
|
|
|
|
listViewWidth,
|
|
|
|
listViewX,
|
|
|
|
listViewY,
|
2023-04-10 23:01:14 -07:00
|
|
|
color | 0x2000000);
|
2022-07-29 06:04:05 -07:00
|
|
|
|
|
|
|
_lighten_buf(listViewBuffer + windowWidth * selectedItemIndex * fontGetLineHeight(),
|
|
|
|
listViewWidth,
|
|
|
|
fontGetLineHeight(),
|
|
|
|
windowWidth);
|
|
|
|
|
|
|
|
if (itemsLength > listViewCapacity) {
|
|
|
|
bufferFill(windowBuffer + windowWidth * scrollbarY + scrollbarX,
|
|
|
|
scrollbarKnobSize + 1,
|
|
|
|
scrollbarKnobSize + 1,
|
|
|
|
windowWidth,
|
|
|
|
_colorTable[_GNW_wcolor[0]]);
|
|
|
|
|
|
|
|
scrollbarY = (scrollOffset * (listViewMaxY - listViewY - 2 * fontGetLineHeight() - 16 - scrollbarKnobSize - 1)) / (itemsLength - listViewCapacity)
|
|
|
|
+ listViewY + fontGetLineHeight() + 7;
|
|
|
|
|
|
|
|
bufferDrawRectShadowed(windowBuffer,
|
|
|
|
windowWidth,
|
|
|
|
scrollbarX,
|
|
|
|
scrollbarY,
|
|
|
|
scrollbarX + scrollbarKnobSize,
|
|
|
|
scrollbarY + scrollbarKnobSize,
|
|
|
|
_colorTable[_GNW_wcolor[1]],
|
|
|
|
_colorTable[_GNW_wcolor[2]]);
|
|
|
|
|
|
|
|
_lighten_buf(windowBuffer + windowWidth * scrollbarY + scrollbarX,
|
|
|
|
scrollbarKnobSize,
|
|
|
|
scrollbarKnobSize,
|
|
|
|
windowWidth);
|
|
|
|
|
|
|
|
_GNW_win_refresh(window, windowRect, NULL);
|
|
|
|
}
|
|
|
|
} else if (keyCode == -3) {
|
|
|
|
Rect itemRect;
|
|
|
|
itemRect.left = windowRect->left + listViewX;
|
|
|
|
itemRect.right = itemRect.left + listViewWidth;
|
|
|
|
|
|
|
|
if (previousSelectedItemIndex != -1) {
|
|
|
|
itemRect.top = windowRect->top + listViewY + previousSelectedItemIndex * fontGetLineHeight();
|
|
|
|
itemRect.bottom = itemRect.top + fontGetLineHeight();
|
|
|
|
|
|
|
|
bufferFill(listViewBuffer + windowWidth * previousSelectedItemIndex * fontGetLineHeight(),
|
|
|
|
listViewWidth,
|
|
|
|
fontGetLineHeight(),
|
|
|
|
windowWidth,
|
|
|
|
_colorTable[_GNW_wcolor[0]]);
|
|
|
|
|
2023-04-10 23:01:14 -07:00
|
|
|
int textColor;
|
|
|
|
if ((color & 0xFF00) != 0) {
|
|
|
|
int colorIndex = (color & 0xFF) - 1;
|
|
|
|
textColor = (color & ~0xFFFF) | _colorTable[_GNW_wcolor[colorIndex]];
|
2022-07-29 06:04:05 -07:00
|
|
|
} else {
|
2023-04-10 23:01:14 -07:00
|
|
|
textColor = color;
|
2022-07-29 06:04:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fontDrawText(listViewBuffer + windowWidth * previousSelectedItemIndex * fontGetLineHeight(),
|
|
|
|
items[scrollOffset + previousSelectedItemIndex],
|
|
|
|
windowWidth,
|
|
|
|
windowWidth,
|
2023-04-10 23:01:14 -07:00
|
|
|
textColor);
|
2022-07-29 06:04:05 -07:00
|
|
|
|
|
|
|
_GNW_win_refresh(window, &itemRect, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (selectedItemIndex != -1) {
|
|
|
|
itemRect.top = windowRect->top + listViewY + selectedItemIndex * fontGetLineHeight();
|
|
|
|
itemRect.bottom = itemRect.top + fontGetLineHeight();
|
|
|
|
|
|
|
|
_lighten_buf(listViewBuffer + windowWidth * selectedItemIndex * fontGetLineHeight(),
|
|
|
|
listViewWidth,
|
|
|
|
fontGetLineHeight(),
|
|
|
|
windowWidth);
|
|
|
|
|
|
|
|
_GNW_win_refresh(window, &itemRect, NULL);
|
|
|
|
}
|
|
|
|
}
|
2022-10-07 14:54:27 -07:00
|
|
|
|
|
|
|
renderPresent();
|
|
|
|
sharedFpsLimiter.throttle();
|
2022-07-29 06:04:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
windowDestroy(win);
|
|
|
|
|
|
|
|
return absoluteSelectedItemIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x4DB478
|
|
|
|
int _win_get_str(char* dest, int length, const char* title, int x, int y)
|
|
|
|
{
|
|
|
|
if (!gWindowSystemInitialized) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int titleWidth = fontGetStringWidth(title) + 12;
|
|
|
|
if (titleWidth < fontGetMonospacedCharacterWidth() * length) {
|
|
|
|
titleWidth = fontGetMonospacedCharacterWidth() * length;
|
|
|
|
}
|
|
|
|
|
|
|
|
int windowWidth = titleWidth + 16;
|
|
|
|
if (windowWidth < 160) {
|
|
|
|
windowWidth = 160;
|
|
|
|
}
|
|
|
|
|
|
|
|
int windowHeight = 5 * fontGetLineHeight() + 16;
|
|
|
|
|
2022-12-12 23:04:05 -08:00
|
|
|
int win = windowCreate(x, y, windowWidth, windowHeight, 256, WINDOW_MODAL | WINDOW_MOVE_ON_TOP);
|
2022-07-29 06:04:05 -07:00
|
|
|
if (win == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
windowDrawBorder(win);
|
|
|
|
|
|
|
|
unsigned char* windowBuffer = windowGetBuffer(win);
|
|
|
|
|
|
|
|
bufferFill(windowBuffer + windowWidth * (fontGetLineHeight() + 14) + 14,
|
|
|
|
windowWidth - 28,
|
|
|
|
fontGetLineHeight() + 2,
|
|
|
|
windowWidth,
|
|
|
|
_colorTable[_GNW_wcolor[0]]);
|
|
|
|
fontDrawText(windowBuffer + windowWidth * 8 + 8, title, windowWidth, windowWidth, _colorTable[_GNW_wcolor[4]]);
|
|
|
|
|
|
|
|
bufferDrawRectShadowed(windowBuffer,
|
|
|
|
windowWidth,
|
|
|
|
14,
|
|
|
|
fontGetLineHeight() + 14,
|
|
|
|
windowWidth - 14,
|
|
|
|
2 * fontGetLineHeight() + 16,
|
|
|
|
_colorTable[_GNW_wcolor[2]],
|
|
|
|
_colorTable[_GNW_wcolor[1]]);
|
|
|
|
|
|
|
|
_win_register_text_button(win,
|
|
|
|
windowWidth / 2 - 72,
|
|
|
|
windowHeight - 8 - fontGetLineHeight() - 6,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
KEY_RETURN,
|
|
|
|
"Done",
|
|
|
|
0);
|
|
|
|
|
|
|
|
_win_register_text_button(win,
|
|
|
|
windowWidth / 2 + 8,
|
|
|
|
windowHeight - 8 - fontGetLineHeight() - 6,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
KEY_ESCAPE,
|
|
|
|
"Cancel",
|
|
|
|
0);
|
|
|
|
|
|
|
|
windowRefresh(win);
|
|
|
|
|
2023-07-21 01:22:57 -07:00
|
|
|
int rc = _win_input_str(win,
|
2022-07-29 06:04:05 -07:00
|
|
|
dest,
|
|
|
|
length,
|
|
|
|
16,
|
|
|
|
fontGetLineHeight() + 16,
|
|
|
|
_colorTable[_GNW_wcolor[3]],
|
|
|
|
_colorTable[_GNW_wcolor[0]]);
|
|
|
|
|
|
|
|
windowDestroy(win);
|
|
|
|
|
2023-07-21 01:22:57 -07:00
|
|
|
return rc;
|
2022-07-29 06:04:05 -07:00
|
|
|
}
|
|
|
|
|
2023-07-19 11:27:20 -07:00
|
|
|
// 0x4DB920
|
|
|
|
int win_yes_no(const char* question, int x, int y, int color)
|
|
|
|
{
|
|
|
|
if (!gWindowSystemInitialized) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int height = 3 * fontGetLineHeight() + 16;
|
|
|
|
int width = std::max(fontGetStringWidth(question) + 16, 144) + 16;
|
|
|
|
|
|
|
|
int win = windowCreate(x, y, width, height, 0x100, WINDOW_MODAL | WINDOW_MOVE_ON_TOP);
|
|
|
|
if (win == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
windowDrawBorder(win);
|
|
|
|
|
|
|
|
unsigned char* windowBuffer = windowGetWindow(win)->buffer;
|
|
|
|
|
|
|
|
int textColor;
|
|
|
|
if ((color & 0xFF00) != 0) {
|
|
|
|
int colorIndex = (color & 0xFF) - 1;
|
|
|
|
textColor = (color & ~0xFFFF) | _colorTable[_GNW_wcolor[colorIndex]];
|
|
|
|
} else {
|
|
|
|
textColor = color;
|
|
|
|
}
|
|
|
|
|
|
|
|
fontDrawText(windowBuffer + 8 * width + 16,
|
|
|
|
question,
|
|
|
|
width,
|
|
|
|
width,
|
|
|
|
textColor);
|
|
|
|
|
|
|
|
_win_register_text_button(win,
|
|
|
|
width / 2 - 64,
|
|
|
|
height - fontGetLineHeight() - 14,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
'y',
|
|
|
|
"Yes",
|
|
|
|
0);
|
|
|
|
_win_register_text_button(win,
|
|
|
|
width / 2 + 16,
|
|
|
|
height - fontGetLineHeight() - 14,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
'n',
|
|
|
|
"No",
|
|
|
|
0);
|
|
|
|
windowRefresh(win);
|
|
|
|
|
|
|
|
// NOTE: Original code is slightly different but does the same thing.
|
|
|
|
int rc = -1;
|
|
|
|
while (rc == -1) {
|
|
|
|
sharedFpsLimiter.mark();
|
|
|
|
|
|
|
|
switch (inputGetInput()) {
|
|
|
|
case KEY_ESCAPE:
|
|
|
|
case 'n':
|
|
|
|
case 'N':
|
|
|
|
rc = 0;
|
|
|
|
break;
|
|
|
|
case KEY_RETURN:
|
|
|
|
case KEY_SPACE:
|
|
|
|
case 'y':
|
|
|
|
case 'Y':
|
|
|
|
rc = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
renderPresent();
|
|
|
|
sharedFpsLimiter.throttle();
|
|
|
|
}
|
|
|
|
|
|
|
|
windowDestroy(win);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
// 0x4DBA98
|
2023-04-10 23:01:14 -07:00
|
|
|
int _win_msg(const char* string, int x, int y, int color)
|
2022-07-29 06:04:05 -07:00
|
|
|
{
|
|
|
|
if (!gWindowSystemInitialized) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int windowHeight = 3 * fontGetLineHeight() + 16;
|
|
|
|
|
|
|
|
int windowWidth = fontGetStringWidth(string) + 16;
|
|
|
|
if (windowWidth < 80) {
|
|
|
|
windowWidth = 80;
|
|
|
|
}
|
|
|
|
|
|
|
|
windowWidth += 16;
|
|
|
|
|
2022-12-12 23:04:05 -08:00
|
|
|
int win = windowCreate(x, y, windowWidth, windowHeight, 256, WINDOW_MODAL | WINDOW_MOVE_ON_TOP);
|
2022-07-29 06:04:05 -07:00
|
|
|
if (win == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
windowDrawBorder(win);
|
|
|
|
|
|
|
|
Window* window = windowGetWindow(win);
|
|
|
|
unsigned char* windowBuffer = window->buffer;
|
|
|
|
|
2023-04-10 23:01:14 -07:00
|
|
|
int textColor;
|
|
|
|
if ((color & 0xFF00) != 0) {
|
2023-07-19 02:01:20 -07:00
|
|
|
int colorIndex = (color & 0xFF) - 1;
|
|
|
|
textColor = (color & ~0xFFFF) | _colorTable[_GNW_wcolor[colorIndex]];
|
2022-07-29 06:04:05 -07:00
|
|
|
} else {
|
2023-04-10 23:01:14 -07:00
|
|
|
textColor = color;
|
2022-07-29 06:04:05 -07:00
|
|
|
}
|
|
|
|
|
2023-04-10 23:01:14 -07:00
|
|
|
fontDrawText(windowBuffer + windowWidth * 8 + 16, string, windowWidth, windowWidth, textColor);
|
2022-07-29 06:04:05 -07:00
|
|
|
|
|
|
|
_win_register_text_button(win,
|
|
|
|
windowWidth / 2 - 32,
|
|
|
|
windowHeight - 8 - fontGetLineHeight() - 6,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
KEY_ESCAPE,
|
|
|
|
"Done",
|
|
|
|
0);
|
|
|
|
|
|
|
|
windowRefresh(win);
|
|
|
|
|
2022-10-05 00:11:47 -07:00
|
|
|
while (inputGetInput() != KEY_ESCAPE) {
|
2022-10-07 14:54:27 -07:00
|
|
|
sharedFpsLimiter.mark();
|
|
|
|
renderPresent();
|
|
|
|
sharedFpsLimiter.throttle();
|
2022-07-29 06:04:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
windowDestroy(win);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x4DBBC4
|
2023-04-10 23:01:14 -07:00
|
|
|
int _win_pull_down(char** items, int itemsLength, int x, int y, int color)
|
2022-07-29 06:04:05 -07:00
|
|
|
{
|
|
|
|
if (!gWindowSystemInitialized) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
Rect rect;
|
2023-04-10 23:01:14 -07:00
|
|
|
int win = _create_pull_down(items, itemsLength, x, y, color, _colorTable[_GNW_wcolor[0]], &rect);
|
2022-07-29 06:04:05 -07:00
|
|
|
if (win == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2023-04-10 23:01:14 -07:00
|
|
|
return process_pull_down(win, &rect, items, itemsLength, color, _colorTable[_GNW_wcolor[0]], NULL, -1);
|
2022-07-29 06:04:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// 0x4DBC34
|
2023-04-10 23:01:14 -07:00
|
|
|
int _create_pull_down(char** stringList, int stringListLength, int x, int y, int foregroundColor, int backgroundColor, Rect* rect)
|
2022-07-29 06:04:05 -07:00
|
|
|
{
|
|
|
|
int windowHeight = stringListLength * fontGetLineHeight() + 16;
|
|
|
|
int windowWidth = _win_width_needed(stringList, stringListLength) + 4;
|
|
|
|
if (windowHeight < 2 || windowWidth < 2) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2023-04-10 23:01:14 -07:00
|
|
|
int win = windowCreate(x, y, windowWidth, windowHeight, backgroundColor, WINDOW_MODAL | WINDOW_MOVE_ON_TOP);
|
2022-07-29 06:04:05 -07:00
|
|
|
if (win == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2023-04-10 23:01:14 -07:00
|
|
|
_win_text(win, stringList, stringListLength, windowWidth - 4, 2, 8, foregroundColor);
|
2022-07-29 06:04:05 -07:00
|
|
|
windowDrawRect(win, 0, 0, windowWidth - 1, windowHeight - 1, _colorTable[0]);
|
2023-04-10 23:01:14 -07:00
|
|
|
windowDrawRect(win, 1, 1, windowWidth - 2, windowHeight - 2, foregroundColor);
|
2022-07-29 06:04:05 -07:00
|
|
|
windowRefresh(win);
|
|
|
|
windowGetRect(win, rect);
|
|
|
|
|
|
|
|
return win;
|
|
|
|
}
|
|
|
|
|
2022-05-19 01:51:26 -07:00
|
|
|
// 0x4DC30C
|
2022-07-29 06:04:05 -07:00
|
|
|
int _win_debug(char* string)
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
if (!gWindowSystemInitialized) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2023-07-19 02:05:39 -07:00
|
|
|
// CE: Debug window metrics were designed for default DOS-style font (0).
|
|
|
|
// We don't expect caller to properly set one, so without manually forcing
|
|
|
|
// it debug window might contain mixed fonts.
|
|
|
|
int oldFont = fontGetCurrent();
|
|
|
|
fontSetCurrent(0);
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
int lineHeight = fontGetLineHeight();
|
|
|
|
|
|
|
|
if (_wd == -1) {
|
2022-12-12 23:04:05 -08:00
|
|
|
_wd = windowCreate(80, 80, 300, 192, 256, WINDOW_MOVE_ON_TOP);
|
2022-07-29 06:04:05 -07:00
|
|
|
if (_wd == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
windowDrawBorder(_wd);
|
|
|
|
|
|
|
|
Window* window = windowGetWindow(_wd);
|
|
|
|
unsigned char* windowBuffer = window->buffer;
|
|
|
|
|
|
|
|
windowFill(_wd, 8, 8, 284, lineHeight, 0x100 | 1);
|
|
|
|
|
|
|
|
windowDrawText(_wd,
|
|
|
|
"Debug",
|
|
|
|
0,
|
|
|
|
(300 - fontGetStringWidth("Debug")) / 2,
|
|
|
|
8,
|
|
|
|
0x2000000 | 0x100 | 4);
|
|
|
|
|
|
|
|
bufferDrawRectShadowed(windowBuffer,
|
|
|
|
300,
|
|
|
|
8,
|
|
|
|
8,
|
|
|
|
291,
|
|
|
|
lineHeight + 8,
|
|
|
|
_colorTable[_GNW_wcolor[2]],
|
|
|
|
_colorTable[_GNW_wcolor[1]]);
|
|
|
|
|
|
|
|
windowFill(_wd, 9, 26, 282, 135, 0x100 | 1);
|
|
|
|
|
|
|
|
bufferDrawRectShadowed(windowBuffer,
|
|
|
|
300,
|
|
|
|
8,
|
|
|
|
25,
|
|
|
|
291,
|
|
|
|
lineHeight + 145,
|
|
|
|
_colorTable[_GNW_wcolor[2]],
|
|
|
|
_colorTable[_GNW_wcolor[1]]);
|
|
|
|
|
|
|
|
_currx = 9;
|
|
|
|
_curry = 26;
|
|
|
|
|
|
|
|
int btn = _win_register_text_button(_wd,
|
|
|
|
(300 - fontGetStringWidth("Close")) / 2,
|
|
|
|
192 - 8 - lineHeight - 6,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
"Close",
|
|
|
|
0);
|
|
|
|
buttonSetMouseCallbacks(btn, NULL, NULL, NULL, _win_debug_delete);
|
|
|
|
|
|
|
|
buttonCreate(_wd,
|
|
|
|
8,
|
|
|
|
8,
|
|
|
|
284,
|
|
|
|
lineHeight,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
2023-07-20 01:13:01 -07:00
|
|
|
BUTTON_DRAG_HANDLE);
|
2022-07-29 06:04:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
char temp[2];
|
|
|
|
temp[1] = '\0';
|
|
|
|
|
|
|
|
char* pch = string;
|
|
|
|
while (*pch != '\0') {
|
|
|
|
int characterWidth = fontGetCharacterWidth(*pch);
|
|
|
|
if (*pch == '\n' || _currx + characterWidth > 291) {
|
|
|
|
_currx = 9;
|
|
|
|
_curry += lineHeight;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (160 - _curry < lineHeight) {
|
|
|
|
Window* window = windowGetWindow(_wd);
|
|
|
|
unsigned char* windowBuffer = window->buffer;
|
|
|
|
blitBufferToBuffer(windowBuffer + lineHeight * 300 + 300 * 26 + 9,
|
|
|
|
282,
|
|
|
|
134 - lineHeight - 1,
|
|
|
|
300,
|
|
|
|
windowBuffer + 300 * 26 + 9,
|
|
|
|
300);
|
|
|
|
_curry -= lineHeight;
|
|
|
|
windowFill(_wd, 9, _curry, 282, lineHeight, 0x100 | 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*pch != '\n') {
|
|
|
|
temp[0] = *pch;
|
|
|
|
windowDrawText(_wd, temp, 0, _currx, _curry, 0x2000000 | 0x100 | 4);
|
|
|
|
_currx += characterWidth + fontGetLetterSpacing();
|
|
|
|
}
|
|
|
|
|
|
|
|
pch++;
|
|
|
|
}
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
windowRefresh(_wd);
|
|
|
|
|
2023-07-19 02:05:39 -07:00
|
|
|
// CE: Restore font.
|
|
|
|
fontSetCurrent(oldFont);
|
|
|
|
|
2022-05-19 01:51:26 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x4DC65C
|
2022-07-29 06:04:05 -07:00
|
|
|
void _win_debug_delete(int btn, int keyCode)
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
windowDestroy(_wd);
|
|
|
|
_wd = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x4DC674
|
2023-04-10 23:01:14 -07:00
|
|
|
int _win_register_menu_bar(int win, int x, int y, int width, int height, int foregroundColor, int backgroundColor)
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
Window* window = windowGetWindow(win);
|
|
|
|
|
|
|
|
if (!gWindowSystemInitialized) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (window == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
if (window->menuBar != NULL) {
|
2022-05-19 01:51:26 -07:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int right = x + width;
|
|
|
|
if (right > window->width) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int bottom = y + height;
|
|
|
|
if (bottom > window->height) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
MenuBar* menuBar = window->menuBar = (MenuBar*)internal_malloc(sizeof(MenuBar));
|
|
|
|
if (menuBar == NULL) {
|
2022-05-19 01:51:26 -07:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
menuBar->win = win;
|
|
|
|
menuBar->rect.left = x;
|
|
|
|
menuBar->rect.top = y;
|
|
|
|
menuBar->rect.right = right - 1;
|
|
|
|
menuBar->rect.bottom = bottom - 1;
|
|
|
|
menuBar->pulldownsLength = 0;
|
2023-04-10 23:01:14 -07:00
|
|
|
menuBar->foregroundColor = foregroundColor;
|
2022-07-29 06:04:05 -07:00
|
|
|
menuBar->backgroundColor = backgroundColor;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
windowFill(win, x, y, width, height, backgroundColor);
|
2023-04-10 23:01:14 -07:00
|
|
|
windowDrawRect(win, x, y, right - 1, bottom - 1, foregroundColor);
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x4DC768
|
2023-04-10 23:01:14 -07:00
|
|
|
int _win_register_menu_pulldown(int win, int x, char* title, int keyCode, int itemsLength, char** items, int foregroundColor, int backgroundColor)
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
Window* window = windowGetWindow(win);
|
|
|
|
|
|
|
|
if (!gWindowSystemInitialized) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (window == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
MenuBar* menuBar = window->menuBar;
|
|
|
|
if (menuBar == NULL) {
|
2022-05-19 01:51:26 -07:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
if (window->menuBar->pulldownsLength == 15) {
|
2022-05-19 01:51:26 -07:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
int titleX = menuBar->rect.left + x;
|
|
|
|
int titleY = (menuBar->rect.top + menuBar->rect.bottom - fontGetLineHeight()) / 2;
|
2022-05-19 01:51:26 -07:00
|
|
|
int btn = buttonCreate(win,
|
2022-07-29 06:04:05 -07:00
|
|
|
titleX,
|
|
|
|
titleY,
|
|
|
|
fontGetStringWidth(title),
|
2022-05-19 01:51:26 -07:00
|
|
|
fontGetLineHeight(),
|
|
|
|
-1,
|
|
|
|
-1,
|
2022-07-29 06:04:05 -07:00
|
|
|
keyCode,
|
2022-05-19 01:51:26 -07:00
|
|
|
-1,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
0);
|
|
|
|
if (btn == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2023-04-10 23:01:14 -07:00
|
|
|
windowDrawText(win, title, 0, titleX, titleY, window->menuBar->foregroundColor | 0x2000000);
|
2022-07-29 06:04:05 -07:00
|
|
|
|
|
|
|
MenuPulldown* pulldown = &(window->menuBar->pulldowns[window->menuBar->pulldownsLength]);
|
|
|
|
pulldown->rect.left = titleX;
|
|
|
|
pulldown->rect.top = titleY;
|
|
|
|
pulldown->rect.right = fontGetStringWidth(title) + titleX - 1;
|
|
|
|
pulldown->rect.bottom = fontGetLineHeight() + titleY - 1;
|
|
|
|
pulldown->keyCode = keyCode;
|
|
|
|
pulldown->itemsLength = itemsLength;
|
|
|
|
pulldown->items = items;
|
2023-04-10 23:01:14 -07:00
|
|
|
pulldown->foregroundColor = foregroundColor;
|
|
|
|
pulldown->backgroundColor = backgroundColor;
|
2022-07-29 06:04:05 -07:00
|
|
|
|
|
|
|
window->menuBar->pulldownsLength++;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
// 0x4DC8D0
|
|
|
|
void _win_delete_menu_bar(int win)
|
|
|
|
{
|
|
|
|
Window* window = windowGetWindow(win);
|
|
|
|
|
|
|
|
if (!gWindowSystemInitialized) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (window == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (window->menuBar == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
windowFill(win,
|
|
|
|
window->menuBar->rect.left,
|
|
|
|
window->menuBar->rect.top,
|
|
|
|
rectGetWidth(&(window->menuBar->rect)),
|
|
|
|
rectGetHeight(&(window->menuBar->rect)),
|
2022-12-07 05:39:30 -08:00
|
|
|
window->color);
|
2022-07-29 06:04:05 -07:00
|
|
|
|
|
|
|
internal_free(window->menuBar);
|
|
|
|
window->menuBar = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x4DC9F0
|
|
|
|
int _find_first_letter(int ch, char** stringList, int stringListLength)
|
|
|
|
{
|
|
|
|
if (ch >= 'A' && ch <= 'Z') {
|
|
|
|
ch += ' ';
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int index = 0; index < stringListLength; index++) {
|
|
|
|
char* string = stringList[index];
|
|
|
|
if (string[0] == ch || string[0] == ch - ' ') {
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-05-19 01:51:26 -07:00
|
|
|
// 0x4DCA30
|
|
|
|
int _win_width_needed(char** fileNameList, int fileNameListLength)
|
|
|
|
{
|
|
|
|
int maxWidth = 0;
|
|
|
|
|
|
|
|
for (int index = 0; index < fileNameListLength; index++) {
|
|
|
|
int width = fontGetStringWidth(fileNameList[index]);
|
|
|
|
if (width > maxWidth) {
|
|
|
|
maxWidth = width;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return maxWidth;
|
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
// 0x4DCA5C
|
|
|
|
int _win_input_str(int win, char* dest, int maxLength, int x, int y, int textColor, int backgroundColor)
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
2022-07-29 06:04:05 -07:00
|
|
|
Window* window = windowGetWindow(win);
|
|
|
|
unsigned char* buffer = window->buffer + window->width * y + x;
|
|
|
|
|
2022-10-03 00:19:22 -07:00
|
|
|
size_t cursorPos = strlen(dest);
|
2022-07-29 06:04:05 -07:00
|
|
|
dest[cursorPos] = '_';
|
|
|
|
dest[cursorPos + 1] = '\0';
|
|
|
|
|
|
|
|
int lineHeight = fontGetLineHeight();
|
|
|
|
int stringWidth = fontGetStringWidth(dest);
|
|
|
|
bufferFill(buffer, stringWidth, lineHeight, window->width, backgroundColor);
|
|
|
|
fontDrawText(buffer, dest, stringWidth, window->width, textColor);
|
|
|
|
|
|
|
|
Rect dirtyRect;
|
|
|
|
dirtyRect.left = window->rect.left + x;
|
|
|
|
dirtyRect.top = window->rect.top + y;
|
|
|
|
dirtyRect.right = dirtyRect.left + stringWidth;
|
|
|
|
dirtyRect.bottom = dirtyRect.top + lineHeight;
|
|
|
|
_GNW_win_refresh(window, &dirtyRect, NULL);
|
|
|
|
|
|
|
|
// NOTE: This loop is slightly different compared to other input handling
|
|
|
|
// loops. Cursor position is managed inside an incrementing loop. Cursor is
|
|
|
|
// decremented in the loop body when key is not handled.
|
|
|
|
bool isFirstKey = true;
|
|
|
|
for (; cursorPos <= maxLength; cursorPos++) {
|
2022-10-07 14:54:27 -07:00
|
|
|
sharedFpsLimiter.mark();
|
|
|
|
|
2022-10-05 00:11:47 -07:00
|
|
|
int keyCode = inputGetInput();
|
2022-07-29 06:04:05 -07:00
|
|
|
if (keyCode != -1) {
|
|
|
|
if (keyCode == KEY_ESCAPE) {
|
|
|
|
dest[cursorPos] = '\0';
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (keyCode == KEY_BACKSPACE) {
|
|
|
|
if (cursorPos > 0) {
|
|
|
|
stringWidth = fontGetStringWidth(dest);
|
|
|
|
|
|
|
|
if (isFirstKey) {
|
|
|
|
bufferFill(buffer, stringWidth, lineHeight, window->width, backgroundColor);
|
|
|
|
|
|
|
|
dirtyRect.left = window->rect.left + x;
|
|
|
|
dirtyRect.top = window->rect.top + y;
|
|
|
|
dirtyRect.right = dirtyRect.left + stringWidth;
|
|
|
|
dirtyRect.bottom = dirtyRect.top + lineHeight;
|
|
|
|
_GNW_win_refresh(window, &dirtyRect, NULL);
|
|
|
|
|
|
|
|
dest[0] = '_';
|
|
|
|
dest[1] = '\0';
|
|
|
|
cursorPos = 1;
|
|
|
|
} else {
|
|
|
|
dest[cursorPos] = ' ';
|
|
|
|
dest[cursorPos - 1] = '_';
|
|
|
|
}
|
|
|
|
|
|
|
|
bufferFill(buffer, stringWidth, lineHeight, window->width, backgroundColor);
|
|
|
|
fontDrawText(buffer, dest, stringWidth, window->width, textColor);
|
|
|
|
|
|
|
|
dirtyRect.left = window->rect.left + x;
|
|
|
|
dirtyRect.top = window->rect.top + y;
|
|
|
|
dirtyRect.right = dirtyRect.left + stringWidth;
|
|
|
|
dirtyRect.bottom = dirtyRect.top + lineHeight;
|
|
|
|
_GNW_win_refresh(window, &dirtyRect, NULL);
|
|
|
|
|
|
|
|
dest[cursorPos] = '\0';
|
|
|
|
cursorPos -= 2;
|
|
|
|
|
|
|
|
isFirstKey = false;
|
|
|
|
} else {
|
|
|
|
cursorPos--;
|
|
|
|
}
|
|
|
|
} else if (keyCode == KEY_RETURN) {
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
if (cursorPos == maxLength) {
|
|
|
|
cursorPos = maxLength - 1;
|
|
|
|
} else {
|
|
|
|
if (keyCode > 0 && keyCode < 256) {
|
|
|
|
dest[cursorPos] = keyCode;
|
|
|
|
dest[cursorPos + 1] = '_';
|
|
|
|
dest[cursorPos + 2] = '\0';
|
|
|
|
|
|
|
|
int stringWidth = fontGetStringWidth(dest);
|
|
|
|
bufferFill(buffer, stringWidth, lineHeight, window->width, backgroundColor);
|
|
|
|
fontDrawText(buffer, dest, stringWidth, window->width, textColor);
|
|
|
|
|
|
|
|
dirtyRect.left = window->rect.left + x;
|
|
|
|
dirtyRect.top = window->rect.top + y;
|
|
|
|
dirtyRect.right = dirtyRect.left + stringWidth;
|
|
|
|
dirtyRect.bottom = dirtyRect.top + lineHeight;
|
|
|
|
_GNW_win_refresh(window, &dirtyRect, NULL);
|
|
|
|
|
|
|
|
isFirstKey = false;
|
|
|
|
} else {
|
|
|
|
cursorPos--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
cursorPos--;
|
|
|
|
}
|
2022-10-07 14:54:27 -07:00
|
|
|
|
|
|
|
renderPresent();
|
|
|
|
sharedFpsLimiter.throttle();
|
2022-07-29 06:04:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
dest[cursorPos] = '\0';
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
// 0x4DBD04
|
2023-04-10 23:01:14 -07:00
|
|
|
int process_pull_down(int win, Rect* rect, char** items, int itemsLength, int foregroundColor, int backgroundColor, MenuBar* menuBar, int pulldownIndex)
|
2022-07-29 06:04:05 -07:00
|
|
|
{
|
2023-07-21 00:50:33 -07:00
|
|
|
if (menuBar != NULL) {
|
|
|
|
unsigned char* parentWindowBuffer = windowGetWindow(menuBar->win)->buffer;
|
|
|
|
MenuPulldown* pulldown = &(menuBar->pulldowns[pulldownIndex]);
|
|
|
|
|
|
|
|
int x = pulldown->rect.left;
|
|
|
|
int y = pulldown->rect.top;
|
|
|
|
int width = pulldown->rect.right - x + 1;
|
|
|
|
int height = pulldown->rect.bottom - y + 1;
|
|
|
|
|
|
|
|
int color1 = menuBar->foregroundColor;
|
|
|
|
if ((color1 & 0xFF00) != 0) {
|
|
|
|
int colorIndex = (color1 & 0xFF) - 1;
|
|
|
|
color1 = (color1 & ~0xFFFF) | _colorTable[_GNW_wcolor[colorIndex]];
|
|
|
|
}
|
|
|
|
|
|
|
|
int color2 = menuBar->backgroundColor;
|
|
|
|
if ((color2 & 0xFF00) != 0) {
|
|
|
|
int colorIndex = (color2 & 0xFF) - 1;
|
|
|
|
color2 = (color2 & ~0xFFFF) | _colorTable[_GNW_wcolor[colorIndex]];
|
|
|
|
}
|
|
|
|
|
|
|
|
_swap_color_buf(parentWindowBuffer + width * y + x,
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
windowGetWidth(menuBar->win),
|
|
|
|
color1,
|
|
|
|
color2);
|
|
|
|
windowRefreshRect(menuBar->win, &(pulldown->rect));
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned char* windowBuffer = windowGetWindow(win)->buffer;
|
|
|
|
int width = rectGetWidth(rect);
|
|
|
|
int height = rectGetHeight(rect);
|
|
|
|
|
|
|
|
int focusedIndex = -1;
|
|
|
|
int rc;
|
|
|
|
int mx1;
|
|
|
|
int my1;
|
|
|
|
int mx2;
|
|
|
|
int my2;
|
|
|
|
int input;
|
|
|
|
|
|
|
|
mouseGetPosition(&mx1, &my1);
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
sharedFpsLimiter.mark();
|
|
|
|
|
|
|
|
input = inputGetInput();
|
|
|
|
if (input != -1) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
mouseGetPosition(&mx2, &my2);
|
|
|
|
|
|
|
|
if (mx2 < mx1 - 4
|
|
|
|
|| mx2 > mx1 + 4
|
|
|
|
|| my2 < my1 - 4
|
|
|
|
|| my2 > my1 + 4) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
renderPresent();
|
|
|
|
sharedFpsLimiter.throttle();
|
|
|
|
}
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
sharedFpsLimiter.mark();
|
|
|
|
|
|
|
|
mouseGetPosition(&mx2, &my2);
|
|
|
|
|
|
|
|
if (input == -2) {
|
|
|
|
if (menuBar != NULL) {
|
|
|
|
if (_mouse_click_in(menuBar->rect.left, menuBar->rect.top, menuBar->rect.right, menuBar->rect.bottom)) {
|
|
|
|
int index;
|
|
|
|
for (index = 0; index < menuBar->pulldownsLength; index++) {
|
|
|
|
MenuPulldown* pulldown = &(menuBar->pulldowns[index]);
|
|
|
|
if (_mouse_click_in(pulldown->rect.left, pulldown->rect.top, pulldown->rect.right, pulldown->rect.bottom)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (index < menuBar->pulldownsLength && index != pulldownIndex) {
|
|
|
|
rc = -2 - index;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((mouseGetEvent() & MOUSE_EVENT_LEFT_BUTTON_UP) != 0
|
|
|
|
|| ((mouseGetEvent() & MOUSE_EVENT_LEFT_BUTTON_DOWN) != 0
|
|
|
|
&& (mouseGetEvent() & MOUSE_EVENT_LEFT_BUTTON_REPEAT) == 0)) {
|
|
|
|
if (_mouse_click_in(rect->left, rect->top + 8, rect->right, rect->bottom - 9)) {
|
|
|
|
rc = focusedIndex;
|
|
|
|
} else {
|
|
|
|
rc = -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool done = false;
|
|
|
|
switch (input) {
|
|
|
|
case KEY_ESCAPE:
|
|
|
|
rc = -1;
|
|
|
|
done = true;
|
|
|
|
break;
|
|
|
|
case KEY_RETURN:
|
|
|
|
rc = focusedIndex;
|
|
|
|
done = true;
|
|
|
|
break;
|
|
|
|
case KEY_ARROW_LEFT:
|
|
|
|
if (menuBar != NULL && pulldownIndex > 0) {
|
|
|
|
rc = -2 - (pulldownIndex - 1);
|
|
|
|
done = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case KEY_ARROW_RIGHT:
|
|
|
|
if (menuBar != NULL && pulldownIndex < menuBar->pulldownsLength - 1) {
|
|
|
|
rc = -2 - (pulldownIndex + 1);
|
|
|
|
done = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case KEY_ARROW_UP:
|
|
|
|
while (focusedIndex > 0) {
|
|
|
|
focusedIndex--;
|
|
|
|
|
|
|
|
if (items[focusedIndex][0] != '\0') {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
input = -3;
|
|
|
|
break;
|
|
|
|
case KEY_ARROW_DOWN:
|
|
|
|
while (focusedIndex < itemsLength - 1) {
|
|
|
|
focusedIndex++;
|
|
|
|
|
|
|
|
if (items[focusedIndex][0] != '\0') {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
input = -3;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (mx2 != mx1 || my2 != my1) {
|
|
|
|
if (_mouse_click_in(rect->left, rect->top + 8, rect->right, rect->bottom - 9)) {
|
|
|
|
input = (my2 - rect->top - 8) / fontGetLineHeight();
|
|
|
|
if (input != -1) {
|
|
|
|
focusedIndex = items[input][0] != '\0' ? input : -1;
|
|
|
|
input = -3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mx1 = mx2;
|
|
|
|
my1 = my2;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (done) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (input == -3) {
|
|
|
|
windowFill(win, 2, 8, width - 4, height - 16, backgroundColor);
|
|
|
|
_win_text(win, items, itemsLength, width - 4, 2, 8, foregroundColor);
|
|
|
|
|
|
|
|
if (focusedIndex != -1) {
|
|
|
|
_lighten_buf(windowBuffer + (focusedIndex * fontGetLineHeight() + 8) * width + 2,
|
|
|
|
width - 4,
|
|
|
|
fontGetLineHeight(),
|
|
|
|
width);
|
|
|
|
}
|
|
|
|
|
|
|
|
windowRefresh(win);
|
|
|
|
}
|
|
|
|
|
|
|
|
input = inputGetInput();
|
|
|
|
|
|
|
|
renderPresent();
|
|
|
|
sharedFpsLimiter.throttle();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (menuBar != NULL) {
|
|
|
|
unsigned char* parentWindowBuffer = windowGetWindow(menuBar->win)->buffer;
|
|
|
|
MenuPulldown* pulldown = &(menuBar->pulldowns[pulldownIndex]);
|
|
|
|
|
|
|
|
int x = pulldown->rect.left;
|
|
|
|
int y = pulldown->rect.top;
|
|
|
|
int width = pulldown->rect.right - x + 1;
|
|
|
|
int height = pulldown->rect.bottom - y + 1;
|
|
|
|
|
|
|
|
int color1 = menuBar->foregroundColor;
|
|
|
|
if ((color1 & 0xFF00) != 0) {
|
|
|
|
int colorIndex = (color1 & 0xFF) - 1;
|
|
|
|
color1 = (color1 & ~0xFFFF) | _colorTable[_GNW_wcolor[colorIndex]];
|
|
|
|
}
|
|
|
|
|
|
|
|
int color2 = menuBar->backgroundColor;
|
|
|
|
if ((color2 & 0xFF00) != 0) {
|
|
|
|
int colorIndex = (color2 & 0xFF) - 1;
|
|
|
|
color2 = (color2 & ~0xFFFF) | _colorTable[_GNW_wcolor[colorIndex]];
|
|
|
|
}
|
|
|
|
|
|
|
|
_swap_color_buf(parentWindowBuffer + width * y + x,
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
windowGetWidth(menuBar->win),
|
|
|
|
color1,
|
|
|
|
color2);
|
|
|
|
windowRefreshRect(menuBar->win, &(pulldown->rect));
|
|
|
|
|
|
|
|
renderPresent();
|
|
|
|
}
|
|
|
|
|
|
|
|
windowDestroy(win);
|
|
|
|
|
|
|
|
return rc;
|
2022-07-29 06:04:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// 0x4DC930
|
|
|
|
int _GNW_process_menu(MenuBar* menuBar, int pulldownIndex)
|
|
|
|
{
|
|
|
|
if (_curr_menu != NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
_curr_menu = menuBar;
|
|
|
|
|
|
|
|
int keyCode;
|
|
|
|
Rect rect;
|
|
|
|
do {
|
|
|
|
MenuPulldown* pulldown = &(menuBar->pulldowns[pulldownIndex]);
|
|
|
|
int win = _create_pull_down(pulldown->items,
|
|
|
|
pulldown->itemsLength,
|
|
|
|
pulldown->rect.left,
|
|
|
|
menuBar->rect.bottom + 1,
|
2023-04-10 23:01:14 -07:00
|
|
|
pulldown->foregroundColor,
|
|
|
|
pulldown->backgroundColor,
|
2022-07-29 06:04:05 -07:00
|
|
|
&rect);
|
|
|
|
if (win == -1) {
|
|
|
|
_curr_menu = NULL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2023-04-10 23:01:14 -07:00
|
|
|
keyCode = process_pull_down(win, &rect, pulldown->items, pulldown->itemsLength, pulldown->foregroundColor, pulldown->backgroundColor, menuBar, pulldownIndex);
|
2022-07-29 06:04:05 -07:00
|
|
|
if (keyCode < -1) {
|
|
|
|
pulldownIndex = -2 - keyCode;
|
|
|
|
}
|
|
|
|
} while (keyCode < -1);
|
|
|
|
|
|
|
|
if (keyCode != -1) {
|
|
|
|
inputEventQueueReset();
|
|
|
|
enqueueInputEvent(keyCode);
|
|
|
|
keyCode = menuBar->pulldowns[pulldownIndex].keyCode;
|
|
|
|
}
|
|
|
|
|
|
|
|
_curr_menu = NULL;
|
|
|
|
|
|
|
|
return keyCode;
|
|
|
|
}
|
|
|
|
|
2023-04-10 23:01:14 -07:00
|
|
|
// Calculates max length of string needed to represent `value` or `value2`.
|
2022-05-19 01:51:26 -07:00
|
|
|
//
|
|
|
|
// 0x4DD03C
|
2023-04-10 23:01:14 -07:00
|
|
|
size_t _calc_max_field_chars_wcursor(int value1, int value2)
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
2022-05-21 08:22:03 -07:00
|
|
|
char* str = (char*)internal_malloc(17);
|
2022-05-19 01:51:26 -07:00
|
|
|
if (str == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2023-04-10 23:01:14 -07:00
|
|
|
snprintf(str, 17, "%d", value1);
|
2022-10-03 00:19:22 -07:00
|
|
|
size_t len1 = strlen(str);
|
2022-05-19 01:51:26 -07:00
|
|
|
|
2023-04-10 23:01:14 -07:00
|
|
|
snprintf(str, 17, "%d", value2);
|
2022-10-03 00:19:22 -07:00
|
|
|
size_t len2 = strlen(str);
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
internal_free(str);
|
|
|
|
|
2022-05-28 04:45:48 -07:00
|
|
|
return std::max(len1, len2) + 1;
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2023-07-22 20:08:23 -07:00
|
|
|
// 0x4DD0AC
|
|
|
|
int get_num_i(int win, int* value, int max_chars_wcursor, bool clear, bool allow_negative, int x, int y)
|
|
|
|
{
|
|
|
|
bool first_press = false;
|
|
|
|
|
|
|
|
Window* window = windowGetWindow(win);
|
|
|
|
if (window == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int original = *value;
|
|
|
|
|
|
|
|
int width = max_chars_wcursor * fontGetMonospacedCharacterWidth();
|
|
|
|
int height = fontGetLineHeight();
|
|
|
|
|
|
|
|
char* string = (char*)internal_malloc(max_chars_wcursor + 1);
|
|
|
|
|
|
|
|
if (clear) {
|
|
|
|
string[0] = '\0';
|
|
|
|
} else {
|
|
|
|
snprintf(string,
|
|
|
|
max_chars_wcursor + 1,
|
|
|
|
"%d",
|
|
|
|
*value);
|
|
|
|
}
|
|
|
|
|
|
|
|
int cursorPos = strlen(string);
|
|
|
|
string[cursorPos] = '_';
|
|
|
|
string[cursorPos + 1] = '\0';
|
|
|
|
|
|
|
|
windowDrawText(win, string, width, x, y, 0x100 | 4);
|
|
|
|
|
|
|
|
Rect rect;
|
|
|
|
rect.left = x;
|
|
|
|
rect.top = y;
|
|
|
|
rect.right = x + width;
|
|
|
|
rect.bottom = y + height;
|
|
|
|
windowRefreshRect(win, &rect);
|
|
|
|
|
|
|
|
bool done = false;
|
|
|
|
while (cursorPos <= max_chars_wcursor && !done) {
|
|
|
|
sharedFpsLimiter.mark();
|
|
|
|
|
|
|
|
int input = inputGetInput();
|
|
|
|
if (input == KEY_RETURN) {
|
|
|
|
done = true;
|
|
|
|
} else if (input == KEY_BACKSPACE) {
|
|
|
|
if (cursorPos > 0) {
|
|
|
|
int stringWidth = fontGetStringWidth(string);
|
|
|
|
if (first_press) {
|
|
|
|
string[0] = '_';
|
|
|
|
string[1] = '\0';
|
|
|
|
cursorPos = 1;
|
|
|
|
first_press = false;
|
|
|
|
} else {
|
|
|
|
string[cursorPos - 1] = '_';
|
|
|
|
string[cursorPos] = '\0';
|
|
|
|
cursorPos--;
|
|
|
|
}
|
|
|
|
|
|
|
|
windowFill(win, x, y, stringWidth, height, 0x100 | 1);
|
|
|
|
windowDrawText(win, string, width, x, y, 0x100 | 4);
|
|
|
|
windowRefreshRect(win, &rect);
|
|
|
|
}
|
|
|
|
} else if (input == KEY_ESCAPE) {
|
|
|
|
*value = original;
|
|
|
|
internal_free(string);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
} else if (input == KEY_ARROW_LEFT) {
|
|
|
|
if (cursorPos > 0) {
|
|
|
|
int stringWidth = fontGetStringWidth(string);
|
|
|
|
string[cursorPos - 1] = '_';
|
|
|
|
string[cursorPos] = '\0';
|
|
|
|
windowFill(win, x, y, stringWidth, height, 0x100 | 1);
|
|
|
|
windowDrawText(win, string, width, x, y, 0x100 | 4);
|
|
|
|
windowRefreshRect(win, &rect);
|
|
|
|
|
|
|
|
first_press = false;
|
|
|
|
cursorPos--;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (cursorPos != max_chars_wcursor - 1) {
|
|
|
|
if ((input == '-' && allow_negative)
|
|
|
|
|| (input >= '0' && input <= '9')) {
|
|
|
|
string[cursorPos] = input;
|
|
|
|
string[cursorPos + 1] = '_';
|
|
|
|
string[cursorPos + 2] = '\0';
|
|
|
|
|
|
|
|
int stringWidth = fontGetStringWidth(string);
|
|
|
|
windowFill(win, x, y, stringWidth, height, 0x100 | 1);
|
|
|
|
windowDrawText(win, string, width, x, y, 0x100 | 4);
|
|
|
|
windowRefreshRect(win, &rect);
|
|
|
|
|
|
|
|
first_press = false;
|
|
|
|
cursorPos++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
renderPresent();
|
|
|
|
sharedFpsLimiter.throttle();
|
|
|
|
}
|
|
|
|
|
|
|
|
*value = atoi(string);
|
|
|
|
internal_free(string);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-05-19 01:51:26 -07:00
|
|
|
// 0x4DD3EC
|
|
|
|
void _GNW_intr_init()
|
|
|
|
{
|
2023-07-19 23:39:15 -07:00
|
|
|
int spacing;
|
|
|
|
int top;
|
|
|
|
int index;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
2023-07-19 23:39:15 -07:00
|
|
|
tm_persistence = 3000;
|
|
|
|
tm_add = 0;
|
|
|
|
tm_kill = -1;
|
|
|
|
scr_center_x = _scr_size.right / 2;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
if (_scr_size.bottom >= 479) {
|
2023-07-19 23:39:15 -07:00
|
|
|
tm_text_y = 16;
|
|
|
|
tm_text_x = 16;
|
2022-05-19 01:51:26 -07:00
|
|
|
} else {
|
2023-07-19 23:39:15 -07:00
|
|
|
tm_text_y = 10;
|
|
|
|
tm_text_x = 10;
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2023-07-19 23:39:15 -07:00
|
|
|
tm_h = 2 * tm_text_y + fontGetLineHeight();
|
2022-05-19 01:51:26 -07:00
|
|
|
|
2023-07-19 23:39:15 -07:00
|
|
|
spacing = _scr_size.bottom / 8;
|
|
|
|
top = _scr_size.bottom / 4;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
2023-07-19 23:39:15 -07:00
|
|
|
for (index = 0; index < kTimedMsgs; index++) {
|
|
|
|
tm_location[index].y = spacing * index + top;
|
|
|
|
tm_location[index].taken = false;
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x4DD4A4
|
|
|
|
void _GNW_intr_exit()
|
|
|
|
{
|
2023-07-19 23:39:15 -07:00
|
|
|
tickersRemove(tm_watch_msgs);
|
|
|
|
while (tm_kill != -1) {
|
|
|
|
tm_kill_msg();
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-19 22:53:26 -07:00
|
|
|
// 0x4DD4C8
|
|
|
|
int win_timed_msg(const char* msg, int color)
|
|
|
|
{
|
|
|
|
if (!gWindowSystemInitialized) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2023-07-19 23:39:15 -07:00
|
|
|
if (tm_add == tm_kill) {
|
2023-07-19 22:53:26 -07:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2023-07-19 23:39:15 -07:00
|
|
|
int width = fontGetStringWidth(msg) + 2 * tm_text_x;
|
|
|
|
int x = scr_center_x - width / 2;
|
|
|
|
int height = tm_h;
|
2023-07-19 22:53:26 -07:00
|
|
|
int y;
|
|
|
|
|
|
|
|
int index;
|
2023-07-19 23:39:15 -07:00
|
|
|
for (index = 0; index < kTimedMsgs; index++) {
|
|
|
|
if (!tm_location[index].taken) {
|
|
|
|
tm_location[index].taken = true;
|
|
|
|
y = tm_location[index].y;
|
2023-07-19 22:53:26 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-19 23:39:15 -07:00
|
|
|
if (index == kTimedMsgs) {
|
2023-07-19 22:53:26 -07:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int win = windowCreate(x, y, width, height, 0x100 | 1, WINDOW_MOVE_ON_TOP);
|
|
|
|
windowDrawBorder(win);
|
2023-07-19 23:39:15 -07:00
|
|
|
windowDrawText(win, msg, 0, tm_text_x, tm_text_y, color);
|
2023-07-19 22:53:26 -07:00
|
|
|
|
|
|
|
int btn = buttonCreate(win,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
0);
|
2023-07-19 23:39:15 -07:00
|
|
|
buttonSetMouseCallbacks(btn, NULL, NULL, NULL, tm_click_response);
|
2023-07-19 22:53:26 -07:00
|
|
|
|
|
|
|
windowRefresh(win);
|
|
|
|
|
2023-07-19 23:39:15 -07:00
|
|
|
tm_queue[tm_add].id = win;
|
|
|
|
tm_queue[tm_add].created = getTicks();
|
|
|
|
tm_queue[tm_add].location = index;
|
2023-07-19 22:53:26 -07:00
|
|
|
|
2023-07-19 23:39:15 -07:00
|
|
|
tm_add++;
|
|
|
|
if (tm_add == kTimedMsgs) {
|
|
|
|
tm_add = 0;
|
|
|
|
} else if (tm_kill == -1) {
|
|
|
|
tm_kill = 0;
|
|
|
|
tickersAdd(tm_watch_msgs);
|
2023-07-19 22:53:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-05-19 01:51:26 -07:00
|
|
|
// 0x4DD66C
|
2023-07-19 23:39:15 -07:00
|
|
|
void tm_watch_msgs()
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
2023-07-19 23:39:15 -07:00
|
|
|
if (tm_watch_active) {
|
2022-05-19 01:51:26 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-07-19 23:39:15 -07:00
|
|
|
tm_watch_active = true;
|
|
|
|
while (tm_kill != -1) {
|
|
|
|
if (getTicksSince(tm_queue[tm_kill].created) < tm_persistence) {
|
2022-05-19 01:51:26 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2023-07-19 23:39:15 -07:00
|
|
|
tm_kill_msg();
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
2023-07-19 23:39:15 -07:00
|
|
|
tm_watch_active = false;
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// 0x4DD6C0
|
2023-07-19 23:39:15 -07:00
|
|
|
void tm_kill_msg()
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
2023-07-19 23:39:15 -07:00
|
|
|
if (tm_kill != -1) {
|
|
|
|
windowDestroy(tm_queue[tm_kill].id);
|
|
|
|
tm_location[tm_queue[tm_kill].location].taken = false;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
2023-07-19 23:39:15 -07:00
|
|
|
tm_kill++;
|
|
|
|
if (tm_kill == kTimedMsgs) {
|
|
|
|
tm_kill = 0;
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2023-07-19 23:39:15 -07:00
|
|
|
if (tm_kill == tm_add) {
|
|
|
|
tm_add = 0;
|
|
|
|
tm_kill = -1;
|
|
|
|
tickersRemove(tm_watch_msgs);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x4DD744
|
2023-07-19 23:39:15 -07:00
|
|
|
void tm_kill_out_of_order(int queue_index)
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
2023-07-19 23:39:15 -07:00
|
|
|
int copy_from;
|
|
|
|
int copy_to;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
2023-07-19 23:39:15 -07:00
|
|
|
if (tm_kill == -1) {
|
2022-05-19 01:51:26 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-07-19 23:39:15 -07:00
|
|
|
if (!tm_index_active(queue_index)) {
|
2022-05-19 01:51:26 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-07-19 23:39:15 -07:00
|
|
|
windowDestroy(tm_queue[queue_index].id);
|
2022-05-19 01:51:26 -07:00
|
|
|
|
2023-07-19 23:39:15 -07:00
|
|
|
tm_location[tm_queue[queue_index].location].taken = false;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
2023-07-19 23:39:15 -07:00
|
|
|
copy_to = queue_index;
|
|
|
|
while (copy_to != tm_kill) {
|
|
|
|
copy_from = copy_to - 1;
|
|
|
|
if (copy_from < 0) {
|
|
|
|
copy_from = kTimedMsgs - 1;
|
|
|
|
}
|
2022-05-19 01:51:26 -07:00
|
|
|
|
2023-07-19 23:39:15 -07:00
|
|
|
tm_queue[copy_to] = tm_queue[copy_from];
|
|
|
|
copy_to = copy_from;
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2023-07-19 23:39:15 -07:00
|
|
|
tm_kill++;
|
|
|
|
if (tm_kill == kTimedMsgs) {
|
|
|
|
tm_kill = 0;
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2023-07-19 23:39:15 -07:00
|
|
|
if (tm_add == tm_kill) {
|
|
|
|
tm_add = 0;
|
|
|
|
tm_kill = -1;
|
|
|
|
tickersRemove(tm_watch_msgs);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x4DD82C
|
2023-07-19 23:39:15 -07:00
|
|
|
void tm_click_response(int btn, int keyCode)
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
int win;
|
2023-07-19 23:39:15 -07:00
|
|
|
int queue_index;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
2023-07-19 23:39:15 -07:00
|
|
|
if (tm_kill == -1) {
|
2022-05-19 01:51:26 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
win = buttonGetWindowId(btn);
|
2023-07-19 23:39:15 -07:00
|
|
|
queue_index = tm_kill;
|
|
|
|
while (win != tm_queue[queue_index].id) {
|
|
|
|
queue_index++;
|
|
|
|
if (queue_index == kTimedMsgs) {
|
|
|
|
queue_index = 0;
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2023-07-19 23:39:15 -07:00
|
|
|
if (queue_index == tm_kill || !tm_index_active(queue_index)) {
|
2022-05-19 01:51:26 -07:00
|
|
|
return;
|
2023-07-19 23:39:15 -07:00
|
|
|
}
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2023-07-19 23:39:15 -07:00
|
|
|
tm_kill_out_of_order(queue_index);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// 0x4DD870
|
2023-07-19 23:39:15 -07:00
|
|
|
bool tm_index_active(int queue_index)
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
2023-07-19 23:39:15 -07:00
|
|
|
if (tm_kill == tm_add) {
|
|
|
|
return true;
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
2023-07-19 23:39:15 -07:00
|
|
|
|
|
|
|
if (tm_kill < tm_add) {
|
|
|
|
return queue_index >= tm_kill && queue_index < tm_add;
|
|
|
|
}
|
|
|
|
|
|
|
|
return queue_index < tm_add || queue_index >= tm_kill;
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
2022-09-23 05:43:44 -07:00
|
|
|
|
|
|
|
} // namespace fallout
|