mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2024-12-22 16:30:23 +00:00
DJUI: Made inputbox usable
Added keyboard support to inputbox Fixed how inputbox text is clipped Added on_enter_press callback for inputbox Added ability to set clipboard text Adjusted how components can be focused, and when they lose focus Erased most of the text input stuff in controller_keyboard Disabled major parts of old chat system Disabled major parts of old menu system
This commit is contained in:
parent
e424b9f9f3
commit
b4418bbd4f
19 changed files with 445 additions and 339 deletions
18
developer/flags.sh
Normal file
18
developer/flags.sh
Normal file
|
@ -0,0 +1,18 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
function compiler() {
|
||||
make clean
|
||||
make RENDER_API=$1 WINDOW_API=$2 AUDIO_API=$3 CONTROLLER_API=$4
|
||||
mv ./build/us_pc/sm64.us.f3dex2e.exe ./build/us_pc/$5.exe
|
||||
}
|
||||
|
||||
compiler GL_LEGACY SDL1 SDL1 SDL1 legacy_1
|
||||
compiler GL SDL1 SDL1 SDL1 gl_1
|
||||
compiler D3D11 DXGI SDL1 SDL1 d3d11_1
|
||||
compiler D3D12 DXGI SDL1 SDL1 d3d12_1
|
||||
|
||||
compiler GL_LEGACY SDL2 SDL2 SDL2 legacy_2
|
||||
compiler GL SDL1 SDL2 SDL2 gl_2
|
||||
compiler D3D11 DXGI SDL2 SDL2 d3d11_2
|
||||
compiler D3D12 DXGI SDL2 SDL2 d3d12_2
|
|
@ -127,33 +127,17 @@ void chat_add_message(char* ascii, enum ChatMessageType chatMessageType) {
|
|||
|
||||
static void chat_stop_input(void) {
|
||||
sInChatInput = FALSE;
|
||||
keyboard_stop_text_input();
|
||||
}
|
||||
|
||||
static void chat_send_input(void) {
|
||||
sInChatInput = FALSE;
|
||||
keyboard_stop_text_input();
|
||||
if (strlen(gTextInput) == 0) { return; }
|
||||
chat_add_message(gTextInput, CMT_LOCAL);
|
||||
// our message has the same color as our shirt
|
||||
network_send_chat(gTextInput, get_player_color(gNetworkPlayerLocal->globalIndex, 0));
|
||||
}
|
||||
|
||||
void chat_start_input(void) {
|
||||
sInChatInput = TRUE;
|
||||
keyboard_start_text_input(TIM_SINGLE_LINE, CHAT_DIALOG_MAX - 3, chat_stop_input, chat_send_input);
|
||||
}
|
||||
|
||||
void render_chat(void) {
|
||||
u8 count = 0;
|
||||
if (sInChatInput) {
|
||||
struct ChatMessage inputMessage = { 0 };
|
||||
inputMessage.type = CMT_INPUT;
|
||||
inputMessage.dialog[0] = 0xFD;
|
||||
inputMessage.dialog[1] = 0x9E;
|
||||
str_ascii_to_dialog(gTextInput, &inputMessage.dialog[2], MIN(strlen(gTextInput), CHAT_DIALOG_MAX - 3));
|
||||
inputMessage.life = CHAT_LIFE_MAX;
|
||||
render_chat_message(&inputMessage, count++);
|
||||
}
|
||||
|
||||
u8 index = onMessageIndex;
|
||||
|
|
|
@ -227,7 +227,7 @@ static Gfx gd_texture1_dummy_aligner1[] = { // @ 801A8728
|
|||
gsSPEndDisplayList(),
|
||||
};
|
||||
|
||||
ALIGNED8 static u8 gd_texture_hand_open[] = {
|
||||
ALIGNED8 u8 gd_texture_hand_open[] = {
|
||||
#include "textures/intro_raw/hand_open.rgba16.inc.c"
|
||||
};
|
||||
|
||||
|
@ -235,7 +235,7 @@ static Gfx gd_texture2_dummy_aligner1[] = {
|
|||
gsSPEndDisplayList()
|
||||
};
|
||||
|
||||
ALIGNED8 static u8 gd_texture_hand_closed[] = {
|
||||
ALIGNED8 u8 gd_texture_hand_closed[] = {
|
||||
#include "textures/intro_raw/hand_closed.rgba16.inc.c"
|
||||
};
|
||||
|
||||
|
|
|
@ -178,75 +178,15 @@ static void connect_menu_draw_strings(void) {
|
|||
|
||||
print_generic_ascii_string(30, 175, "Type in or paste the host's IP.");
|
||||
print_generic_ascii_string(30, 160, "Note - the host must forward a port on their router.");
|
||||
|
||||
if (keyboard_in_text_input()) {
|
||||
if (strlen(gTextInput) >= 7) {
|
||||
print_generic_ascii_string(30, 100, "Press (ENTER) to connect.");
|
||||
} else {
|
||||
print_generic_ascii_string(30, 100, "Press (ESC) to cancel.");
|
||||
}
|
||||
}
|
||||
|
||||
gDPSetEnvColor(gDisplayListHead++, 130, 222, 140, gMenuStringAlpha);
|
||||
print_generic_ascii_string(30, 130, gTextInput);
|
||||
}
|
||||
|
||||
static void connect_menu_on_connection_attempt(void) {
|
||||
play_sound(SOUND_GENERAL_COIN, gDefaultSoundArgs);
|
||||
|
||||
keyboard_stop_text_input();
|
||||
if (gNetworkType != NT_NONE) { return; }
|
||||
|
||||
char delims[2] = " ";
|
||||
|
||||
// copy input
|
||||
char buffer[MAX_TEXT_INPUT] = { 0 };
|
||||
strncpy(buffer, gTextInput, MAX_TEXT_INPUT);
|
||||
char* text = buffer;
|
||||
|
||||
// trim whitespace
|
||||
while (*text == ' ') { text++; }
|
||||
|
||||
// grab IP
|
||||
char* ip = strtok(text, delims);
|
||||
if (ip == NULL) { custom_menu_close(); return; }
|
||||
strncpy(configJoinIp, ip, MAX_CONFIG_STRING);
|
||||
|
||||
// grab port
|
||||
char* port = strtok(NULL, delims);
|
||||
if (port != NULL) {
|
||||
unsigned int intPort = atoi(port);
|
||||
if (intPort == 0 || intPort > 65535) { configJoinPort = DEFAULT_PORT; custom_menu_close(); return; }
|
||||
configJoinPort = intPort;
|
||||
}
|
||||
else {
|
||||
configJoinPort = DEFAULT_PORT;
|
||||
}
|
||||
|
||||
network_set_system(NS_SOCKET);
|
||||
network_init(NT_CLIENT);
|
||||
|
||||
}
|
||||
|
||||
static void connect_menu_on_click(void) {
|
||||
sConnectionJoinError[0] = '\0';
|
||||
|
||||
keyboard_start_text_input(TIM_IP, MAX_TEXT_INPUT, custom_menu_close, connect_menu_on_connection_attempt);
|
||||
|
||||
// fill in our last attempt
|
||||
if (configJoinPort == 0 || configJoinPort > 65535) { configJoinPort = DEFAULT_PORT; }
|
||||
|
||||
// only print custom port
|
||||
if (configJoinPort == DEFAULT_PORT) {
|
||||
sprintf(gTextInput, "%s", configJoinIp);
|
||||
}
|
||||
else {
|
||||
sprintf(gTextInput, "%s %d", configJoinIp, configJoinPort);
|
||||
}
|
||||
}
|
||||
|
||||
static void connect_menu_on_close(void) {
|
||||
keyboard_stop_text_input();
|
||||
network_shutdown();
|
||||
}
|
||||
|
||||
|
|
|
@ -20,19 +20,6 @@
|
|||
#include "game/chat.h"
|
||||
#include "src/pc/djui/djui.h"
|
||||
|
||||
// TODO: use some common lookup header
|
||||
#define SCANCODE_BACKSPACE 0x0E
|
||||
#define SCANCODE_ESCAPE 0x01
|
||||
#define SCANCODE_ENTER 0x1C
|
||||
#define SCANCODE_V 0x2F
|
||||
#define SCANCODE_INSERT 0x152
|
||||
#define SCANCODE_CTRL1 0x1D
|
||||
#define SCANCODE_CTRL2 0x11D
|
||||
#define SCANCODE_SHIFT1 0x2A
|
||||
#define SCANCODE_SHIFT2 0x36
|
||||
#define SCANCODE_ALT1 0x38
|
||||
#define SCANCODE_ALT2 0x138
|
||||
|
||||
static int keyboard_buttons_down;
|
||||
|
||||
#define MAX_KEYBINDS 64
|
||||
|
@ -41,16 +28,6 @@ static int num_keybinds = 0;
|
|||
|
||||
static u32 keyboard_lastkey = VK_INVALID;
|
||||
|
||||
char gTextInput[MAX_TEXT_INPUT];
|
||||
static u8 sInTextInput = false;
|
||||
static u8 sMaxTextInput = 0;
|
||||
static clock_t sIgnoreTextInput = 0;
|
||||
|
||||
u8 held_ctrl, held_shift, held_alt;
|
||||
static enum TextInputMode sTextInputMode;
|
||||
void (*textInputOnEscape)(void) = NULL;
|
||||
void (*textInputOnEnter)(void) = NULL;
|
||||
|
||||
static int keyboard_map_scancode(int scancode) {
|
||||
int ret = 0;
|
||||
for (int i = 0; i < num_keybinds; i++) {
|
||||
|
@ -61,70 +38,16 @@ static int keyboard_map_scancode(int scancode) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void keyboard_alter_modifier(int scancode, bool down) {
|
||||
if (down) {
|
||||
switch (scancode) {
|
||||
case SCANCODE_CTRL1: held_ctrl |= (1 << 0); break;
|
||||
case SCANCODE_CTRL2: held_ctrl |= (1 << 1); break;
|
||||
case SCANCODE_SHIFT1: held_shift |= (1 << 0); break;
|
||||
case SCANCODE_SHIFT2: held_shift |= (1 << 1); break;
|
||||
case SCANCODE_ALT1: held_alt |= (1 << 0); break;
|
||||
case SCANCODE_ALT2: held_alt |= (1 << 1); break;
|
||||
}
|
||||
} else {
|
||||
switch (scancode) {
|
||||
case SCANCODE_CTRL1: held_ctrl &= ~(1 << 0); break;
|
||||
case SCANCODE_CTRL2: held_ctrl &= ~(1 << 1); break;
|
||||
case SCANCODE_SHIFT1: held_shift &= ~(1 << 0); break;
|
||||
case SCANCODE_SHIFT2: held_shift &= ~(1 << 1); break;
|
||||
case SCANCODE_ALT1: held_alt &= ~(1 << 0); break;
|
||||
case SCANCODE_ALT2: held_alt &= ~(1 << 1); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool keyboard_on_key_down(int scancode) {
|
||||
// alter the held value of modifier keys
|
||||
keyboard_alter_modifier(scancode, true);
|
||||
|
||||
djui_interactable_on_key_down(scancode);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (!sInTextInput) {
|
||||
debug_keyboard_on_key_down(scancode);
|
||||
}
|
||||
debug_keyboard_on_key_down(scancode);
|
||||
#endif
|
||||
if (sInTextInput) {
|
||||
// perform text-input-specific actions
|
||||
switch (scancode & 0xFF) {
|
||||
case SCANCODE_BACKSPACE:
|
||||
gTextInput[max(strlen(gTextInput) - 1, 0)] = '\0';
|
||||
break;
|
||||
case SCANCODE_ESCAPE:
|
||||
if (textInputOnEscape != NULL) { textInputOnEscape(); }
|
||||
break;
|
||||
case SCANCODE_ENTER:
|
||||
if (textInputOnEnter != NULL) { textInputOnEnter(); }
|
||||
break;
|
||||
case SCANCODE_V:
|
||||
if (held_ctrl) { keyboard_on_text_input(wm_api->get_clipboard_text()); }
|
||||
break;
|
||||
case SCANCODE_INSERT:
|
||||
if (held_shift) { keyboard_on_text_input(wm_api->get_clipboard_text()); }
|
||||
break;
|
||||
}
|
||||
|
||||
// ignore any normal key down event if we're in text-input mode
|
||||
// see if interactable captures this scancode
|
||||
if (djui_interactable_on_key_down(scancode)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!held_alt && (scancode == (int)configKeyChat[0])) {
|
||||
if (sSelectedFileNum != 0) {
|
||||
sIgnoreTextInput = clock() + CLOCKS_PER_SEC * 0.01f;
|
||||
chat_start_input();
|
||||
}
|
||||
}
|
||||
|
||||
int mapped = keyboard_map_scancode(scancode);
|
||||
keyboard_buttons_down |= mapped;
|
||||
keyboard_lastkey = scancode;
|
||||
|
@ -132,16 +55,8 @@ bool keyboard_on_key_down(int scancode) {
|
|||
}
|
||||
|
||||
bool keyboard_on_key_up(int scancode) {
|
||||
// alter the held value of modifier keys
|
||||
keyboard_alter_modifier(scancode, false);
|
||||
|
||||
djui_interactable_on_key_up(scancode);
|
||||
|
||||
if (sInTextInput) {
|
||||
// ignore any key up event if we're in text-input mode
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int mapped = keyboard_map_scancode(scancode);
|
||||
keyboard_buttons_down &= ~mapped;
|
||||
if (keyboard_lastkey == (u32) scancode)
|
||||
|
@ -153,87 +68,8 @@ void keyboard_on_all_keys_up(void) {
|
|||
keyboard_buttons_down = 0;
|
||||
}
|
||||
|
||||
char* keyboard_start_text_input(enum TextInputMode inInputMode, u8 inMaxTextInput, void (*onEscape)(void), void (*onEnter)(void)) {
|
||||
// set text-input events
|
||||
textInputOnEscape = onEscape;
|
||||
textInputOnEnter = onEnter;
|
||||
sMaxTextInput = inMaxTextInput;
|
||||
|
||||
// clear buffer
|
||||
for (int i = 0; i < MAX_TEXT_INPUT; i++) { gTextInput[i] = '\0'; }
|
||||
|
||||
// clear held-value for modifiers
|
||||
held_ctrl = 0;
|
||||
held_shift = 0;
|
||||
held_alt = 0;
|
||||
|
||||
// start allowing text input
|
||||
wm_api->start_text_input();
|
||||
sTextInputMode = inInputMode;
|
||||
sInTextInput = true;
|
||||
}
|
||||
|
||||
void keyboard_stop_text_input(void) {
|
||||
// stop allowing text input
|
||||
sInTextInput = false;
|
||||
wm_api->stop_text_input();
|
||||
}
|
||||
|
||||
bool keyboard_in_text_input(void) { return sInTextInput; }
|
||||
|
||||
static bool keyboard_allow_character_input(char c) {
|
||||
switch (sTextInputMode) {
|
||||
case TIM_IP:
|
||||
// IP only allows numbers, periods, and spaces
|
||||
return (c >= '0' && c <= '9')
|
||||
|| (c == '.')
|
||||
|| (c == ' ');
|
||||
|
||||
case TIM_MULTI_LINE:
|
||||
// multi-line allows new-line character
|
||||
if (c == '\n') { return true; }
|
||||
// intentional fall-through
|
||||
|
||||
case TIM_SINGLE_LINE:
|
||||
// allow all characters that we can display in-game
|
||||
return (c >= '0' && c <= '9')
|
||||
|| (c >= 'a' && c <= 'z')
|
||||
|| (c >= 'A' && c <= 'Z')
|
||||
|| (c == '\'') || (c == '.')
|
||||
|| (c == ',') || (c == '-')
|
||||
|| (c == '(') || (c == ')')
|
||||
|| (c == '&') || (c == '!')
|
||||
|| (c == '%') || (c == '?')
|
||||
|| (c == '"') || (c == '~')
|
||||
|| (c == '*') || (c == ' ');
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void keyboard_on_text_input(char* text) {
|
||||
if (sIgnoreTextInput != 0 && clock() <= sIgnoreTextInput) {
|
||||
sIgnoreTextInput = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sInTextInput) { return; }
|
||||
// sanity check input
|
||||
if (text == NULL) { return; }
|
||||
|
||||
int i = strlen(gTextInput);
|
||||
while (*text != '\0') {
|
||||
// make sure we don't overrun the buffer
|
||||
if (i >= MAX_TEXT_INPUT) { break; }
|
||||
if (i >= sMaxTextInput) { break; }
|
||||
|
||||
// copy over character if we're allowed to input it
|
||||
if (keyboard_allow_character_input(*text)) {
|
||||
gTextInput[i++] = *text;
|
||||
}
|
||||
|
||||
text++;
|
||||
}
|
||||
djui_interactable_on_text_input(text);
|
||||
}
|
||||
|
||||
static void keyboard_add_binds(int mask, unsigned int *scancode) {
|
||||
|
|
|
@ -6,26 +6,32 @@
|
|||
|
||||
# define VK_BASE_KEYBOARD 0x0000
|
||||
|
||||
#define SCANCODE_ESCAPE 1
|
||||
#define SCANCODE_BACKSPACE 14
|
||||
#define SCANCODE_ENTER 28
|
||||
#define SCANCODE_CONTROL_LEFT 29
|
||||
#define SCANCODE_SHIFT_LEFT 42
|
||||
#define SCANCODE_A 30
|
||||
#define SCANCODE_X 45
|
||||
#define SCANCODE_C 46
|
||||
#define SCANCODE_V 47
|
||||
#define SCANCODE_SHIFT_RIGHT 54
|
||||
#define SCANCODE_CONTROL_RIGHT 285
|
||||
#define SCANCODE_HOME 327
|
||||
#define SCANCODE_LEFT 331
|
||||
#define SCANCODE_RIGHT 333
|
||||
#define SCANCODE_END 335
|
||||
#define SCANCODE_INSERT 338
|
||||
#define SCANCODE_DELETE 339
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MAX_TEXT_INPUT 255
|
||||
extern char gTextInput[];
|
||||
|
||||
enum TextInputMode {
|
||||
TIM_IP,
|
||||
TIM_MULTI_LINE,
|
||||
TIM_SINGLE_LINE,
|
||||
};
|
||||
|
||||
bool keyboard_on_key_down(int scancode);
|
||||
bool keyboard_on_key_up(int scancode);
|
||||
void keyboard_on_all_keys_up(void);
|
||||
void keyboard_on_text_input(char* text);
|
||||
char* keyboard_start_text_input(enum TextInputMode, u8 inMaxTextInput, void (*onEscape)(void), void (*onEnter)(void));
|
||||
void keyboard_stop_text_input(void);
|
||||
bool keyboard_in_text_input(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -159,9 +159,11 @@ static void controller_sdl_read(OSContPad *pad) {
|
|||
|
||||
u32 mouse = SDL_GetRelativeMouseState(&mouse_x, &mouse_y);
|
||||
|
||||
for (u32 i = 0; i < num_mouse_binds; ++i)
|
||||
if (mouse & SDL_BUTTON(mouse_binds[i][0]))
|
||||
pad->button |= mouse_binds[i][1];
|
||||
if (!gInteractableOverridePad) {
|
||||
for (u32 i = 0; i < num_mouse_binds; ++i)
|
||||
if (mouse & SDL_BUTTON(mouse_binds[i][0]))
|
||||
pad->button |= mouse_binds[i][1];
|
||||
}
|
||||
|
||||
// remember buttons that changed from 0 to 1
|
||||
last_mouse = (mouse_buttons ^ mouse) & mouse;
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
|
||||
#include "game/level_update.h"
|
||||
|
||||
#include "pc/djui/djui.h"
|
||||
|
||||
// mouse buttons are also in the controller namespace (why), just offset 0x100
|
||||
#define VK_OFS_SDL_MOUSE 0x0100
|
||||
#define VK_BASE_SDL_MOUSE (VK_BASE_SDL_GAMEPAD + VK_OFS_SDL_MOUSE)
|
||||
|
@ -163,10 +165,11 @@ static void controller_sdl_read(OSContPad *pad) {
|
|||
|
||||
u32 mouse = SDL_GetRelativeMouseState(&mouse_x, &mouse_y);
|
||||
|
||||
for (u32 i = 0; i < num_mouse_binds; ++i)
|
||||
if (mouse & SDL_BUTTON(mouse_binds[i][0]))
|
||||
pad->button |= mouse_binds[i][1];
|
||||
|
||||
if (!gInteractableOverridePad) {
|
||||
for (u32 i = 0; i < num_mouse_binds; ++i)
|
||||
if (mouse & SDL_BUTTON(mouse_binds[i][0]))
|
||||
pad->button |= mouse_binds[i][1];
|
||||
}
|
||||
// remember buttons that changed from 0 to 1
|
||||
last_mouse = (mouse_buttons ^ mouse) & mouse;
|
||||
mouse_buttons = mouse;
|
||||
|
|
|
@ -37,14 +37,6 @@ static void djui_checkbox_on_cursor_down_end(struct DjuiBase* base) {
|
|||
djui_checkbox_set_default_style(base);
|
||||
}
|
||||
|
||||
static void djui_checkbox_on_focus_begin(struct DjuiBase* base) {
|
||||
struct DjuiCheckbox* checkbox = (struct DjuiCheckbox*)base;
|
||||
djui_base_set_border_color(&checkbox->rect->base, 20, 170, 255, 255);
|
||||
djui_base_set_color(&checkbox->rect->base, 255, 255, 255, 32);
|
||||
djui_base_set_color(&checkbox->text->base, 229, 241, 251, 255);
|
||||
djui_base_set_color(&checkbox->rectValue->base, 255, 255, 255, 255);
|
||||
}
|
||||
|
||||
static void djui_checkbox_destroy(struct DjuiBase* base) {
|
||||
struct DjuiCheckbox* checkbox = (struct DjuiCheckbox*)base;
|
||||
free(checkbox);
|
||||
|
|
|
@ -1,15 +1,9 @@
|
|||
#include "djui.h"
|
||||
#include "pc/controller/controller_mouse.h"
|
||||
#include "pc/controller/controller_sdl.h"
|
||||
|
||||
#include "src/pc/controller/controller_sdl.h"
|
||||
#include "src/pc/controller/controller_mouse.h"
|
||||
|
||||
ALIGNED8 static u8 texture_hand_open[] = {
|
||||
#include "textures/intro_raw/hand_open.rgba16.inc.c"
|
||||
};
|
||||
|
||||
ALIGNED8 static u8 texture_hand_closed[] = {
|
||||
#include "textures/intro_raw/hand_closed.rgba16.inc.c"
|
||||
};
|
||||
extern ALIGNED8 u8 gd_texture_hand_open[];
|
||||
extern ALIGNED8 u8 gd_texture_hand_closed[];
|
||||
|
||||
static struct DjuiImage* sMouseCursor = NULL;
|
||||
|
||||
|
@ -22,7 +16,11 @@ f32 gCursorX = 0;
|
|||
f32 gCursorY = 0;
|
||||
|
||||
void djui_cursor_set_visible(bool visible) {
|
||||
djui_base_set_visible(&sMouseCursor->base, visible);
|
||||
if (sMouseCursor) {
|
||||
djui_base_set_visible(&sMouseCursor->base, visible);
|
||||
}
|
||||
sSavedMouseX = mouse_window_x;
|
||||
sSavedMouseY = mouse_window_y;
|
||||
}
|
||||
|
||||
bool djui_cursor_inside_base(struct DjuiBase* base) {
|
||||
|
@ -42,11 +40,7 @@ static void djui_cursor_base_hover_location(struct DjuiBase* base, f32* x, f32*
|
|||
void djui_cursor_input_controlled_center(struct DjuiBase* base) {
|
||||
if (!sCursorMouseControlled) {
|
||||
sInputControlledBase = base;
|
||||
if (sMouseCursor != NULL) {
|
||||
djui_base_set_visible(&sMouseCursor->base, (base != NULL));
|
||||
}
|
||||
sSavedMouseX = mouse_window_x;
|
||||
sSavedMouseY = mouse_window_y;
|
||||
djui_cursor_set_visible(base != NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,12 +103,11 @@ void djui_cursor_update(void) {
|
|||
controller_sdl_read_mouse_window();
|
||||
|
||||
// check if mouse is in control again
|
||||
if (!sCursorMouseControlled) {
|
||||
if (!sCursorMouseControlled || (sMouseCursor && !sMouseCursor->base.visible)) {
|
||||
f32 dist = sqrtf(powf(mouse_window_x - sSavedMouseX, 2) + powf(mouse_window_y - sSavedMouseY, 2));
|
||||
if (dist > 5) {
|
||||
sCursorMouseControlled = true;
|
||||
djui_interactable_set_input_focus(NULL);
|
||||
djui_base_set_visible(&sMouseCursor->base, true);
|
||||
djui_cursor_set_visible(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -131,16 +124,16 @@ void djui_cursor_update(void) {
|
|||
|
||||
// set cursor sprite
|
||||
if ((gInteractablePad.button & PAD_BUTTON_A) || (mouse_window_buttons & MOUSE_BUTTON_1)) {
|
||||
djui_image_set_image(sMouseCursor, texture_hand_closed, 32, 32, 16);
|
||||
djui_image_set_image(sMouseCursor, gd_texture_hand_closed, 32, 32, 16);
|
||||
} else {
|
||||
djui_image_set_image(sMouseCursor, texture_hand_open, 32, 32, 16);
|
||||
djui_image_set_image(sMouseCursor, gd_texture_hand_open, 32, 32, 16);
|
||||
}
|
||||
#endif
|
||||
djui_base_render(&sMouseCursor->base);
|
||||
}
|
||||
|
||||
void djui_cursor_create(void) {
|
||||
sMouseCursor = djui_image_create(NULL, texture_hand_open, 32, 32, 16);
|
||||
sMouseCursor = djui_image_create(NULL, gd_texture_hand_open, 32, 32, 16);
|
||||
djui_base_set_location(&sMouseCursor->base, 0, 0);
|
||||
djui_base_set_size(&sMouseCursor->base, 64, 64);
|
||||
}
|
|
@ -1,15 +1,24 @@
|
|||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "djui.h"
|
||||
#include "pc/gfx/gfx_window_manager_api.h"
|
||||
#include "pc/pc_main.h"
|
||||
#include "game/segment2.h"
|
||||
#include "pc/controller/controller_keyboard.h"
|
||||
|
||||
#define DJUI_INPUTBOX_YOFF (-2)
|
||||
#define DJUI_INPUTBOX_MAX_BLINK 50
|
||||
#define DJUI_INPUTBOX_MID_BLINK (DJUI_INPUTBOX_MAX_BLINK / 2)
|
||||
#define DJUI_INPUTBOX_CURSOR_WIDTH (2.0f / 32.0f)
|
||||
|
||||
static u8 sHeldShift = 0;
|
||||
static u8 sHeldControl = 0;
|
||||
static u8 sCursorBlink = 0;
|
||||
|
||||
void djui_inputbox_hook_enter_press(struct DjuiInputbox* inputbox, void (*on_enter_press)(void)) {
|
||||
inputbox->on_enter_press = on_enter_press;
|
||||
}
|
||||
|
||||
static void djui_inputbox_set_default_style(struct DjuiBase* base) {
|
||||
struct DjuiInputbox* inputbox = (struct DjuiInputbox*)base;
|
||||
djui_base_set_border_color(base, 150, 150, 150, 255);
|
||||
|
@ -51,6 +60,7 @@ static void djui_inputbox_on_cursor_down_begin(struct DjuiBase* base, bool input
|
|||
inputbox->selection[0] = index;
|
||||
inputbox->selection[1] = index;
|
||||
sCursorBlink = 0;
|
||||
djui_interactable_set_input_focus(base);
|
||||
}
|
||||
|
||||
static void djui_inputbox_on_cursor_down(struct DjuiBase* base) {
|
||||
|
@ -63,6 +73,236 @@ static void djui_inputbox_on_cursor_down_end(struct DjuiBase* base) {
|
|||
djui_inputbox_set_default_style(base);
|
||||
}
|
||||
|
||||
static u16 djui_inputbox_jump_word_left(char* msg, u16 len, u16 i) {
|
||||
if (i == 0) { return i; }
|
||||
|
||||
s32 lastI = i;
|
||||
bool seenNonSpace = false;
|
||||
while (true) {
|
||||
if (msg[i] == ' ' && seenNonSpace) { i = lastI; break; }
|
||||
lastI = i;
|
||||
i--;
|
||||
if (i <= 0) { i = 0; break; }
|
||||
if (msg[i] != ' ') { seenNonSpace = true; }
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static u16 djui_inputbox_jump_word_right(char *msg, u16 len, u16 i) {
|
||||
if (i >= len) { return len; }
|
||||
|
||||
bool seenSpace = false;
|
||||
while (true) {
|
||||
i++;
|
||||
if (i >= len) { i = len; break; }
|
||||
if (msg[i] != ' ' && seenSpace) { break; }
|
||||
if (msg[i] == ' ') { seenSpace = true; }
|
||||
};
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static void djui_inputbox_delete_selection(struct DjuiInputbox *inputbox) {
|
||||
u16 *sel = inputbox->selection;
|
||||
char *msg = inputbox->buffer;
|
||||
u16 len = strlen(msg);
|
||||
|
||||
if (sel[0] != sel[1]) {
|
||||
u16 s1 = fmin(sel[0], sel[1]);
|
||||
u16 s2 = fmax(sel[0], sel[1]);
|
||||
memmove(&msg[s1], &msg[s2], (len + 1) - s2);
|
||||
sel[0] = s1;
|
||||
sel[1] = s1;
|
||||
}
|
||||
}
|
||||
|
||||
static bool djui_inputbox_on_key_down(struct DjuiBase *base, int scancode) {
|
||||
struct DjuiInputbox *inputbox = (struct DjuiInputbox *) base;
|
||||
u16 *sel = inputbox->selection;
|
||||
char *msg = inputbox->buffer;
|
||||
u16 len = strlen(msg);
|
||||
u16 s1 = fmin(sel[0], sel[1]);
|
||||
u16 s2 = fmax(sel[0], sel[1]);
|
||||
|
||||
switch (scancode) {
|
||||
case SCANCODE_CONTROL_LEFT: sHeldControl |= (1 << 0); return true;
|
||||
case SCANCODE_CONTROL_RIGHT: sHeldControl |= (1 << 1); return true;
|
||||
case SCANCODE_SHIFT_LEFT: sHeldShift |= (1 << 0); return true;
|
||||
case SCANCODE_SHIFT_RIGHT: sHeldShift |= (1 << 1); return true;
|
||||
}
|
||||
|
||||
if (scancode == SCANCODE_LEFT) {
|
||||
if (sHeldControl) {
|
||||
sel[0] = djui_inputbox_jump_word_left(msg, len, sel[0]);
|
||||
} else if (sel[0] > 0) {
|
||||
sel[0]--;
|
||||
}
|
||||
if (!sHeldShift) { sel[1] = sel[0]; }
|
||||
sCursorBlink = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (scancode == SCANCODE_RIGHT) {
|
||||
if (sHeldControl) {
|
||||
sel[0] = djui_inputbox_jump_word_right(msg, len, sel[0]);
|
||||
} else if (sel[0] < len) {
|
||||
sel[0]++;
|
||||
}
|
||||
if (!sHeldShift) { sel[1] = sel[0]; }
|
||||
sCursorBlink = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (scancode == SCANCODE_HOME) {
|
||||
sel[0] = 0;
|
||||
if (!sHeldShift) { sel[1] = sel[0]; }
|
||||
sCursorBlink = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (scancode == SCANCODE_END) {
|
||||
sel[0] = len;
|
||||
if (!sHeldShift) { sel[1] = sel[0]; }
|
||||
sCursorBlink = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (scancode == SCANCODE_BACKSPACE) {
|
||||
if (sel[0] == sel[1]) {
|
||||
if (sHeldControl) {
|
||||
sel[0] = djui_inputbox_jump_word_left(msg, len, sel[0]);
|
||||
} else if (sel[0] > 0) {
|
||||
sel[0]--;
|
||||
}
|
||||
}
|
||||
if (sel[0] != sel[1]) {
|
||||
djui_inputbox_delete_selection(inputbox);
|
||||
}
|
||||
sCursorBlink = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (scancode == SCANCODE_DELETE) {
|
||||
if (sel[0] == sel[1]) {
|
||||
if (sHeldControl) {
|
||||
sel[1] = djui_inputbox_jump_word_right(msg, len, sel[1]);
|
||||
} else if (sel[1] < len) {
|
||||
sel[1]++;
|
||||
}
|
||||
}
|
||||
if (sel[0] != sel[1]) {
|
||||
djui_inputbox_delete_selection(inputbox);
|
||||
}
|
||||
sCursorBlink = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((sHeldControl && scancode == SCANCODE_V) || (sHeldShift && scancode == SCANCODE_INSERT)) {
|
||||
djui_interactable_on_text_input(wm_api->get_clipboard_text());
|
||||
sCursorBlink = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (sHeldControl && (scancode == SCANCODE_C || scancode == SCANCODE_X)) {
|
||||
if (sel[0] != sel[1]) {
|
||||
char clipboardText[256] = { 0 };
|
||||
snprintf(clipboardText, fmin(256, 1 + s2 - s1), "%s", &msg[s1]);
|
||||
wm_api->set_clipboard_text(clipboardText);
|
||||
if (scancode == SCANCODE_X) {
|
||||
djui_inputbox_delete_selection(inputbox);
|
||||
sCursorBlink = 0;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (sHeldControl && scancode == SCANCODE_A) {
|
||||
inputbox->selection[0] = len;
|
||||
inputbox->selection[1] = 0;
|
||||
sCursorBlink = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (scancode == SCANCODE_ESCAPE) {
|
||||
djui_interactable_set_input_focus(NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (scancode == SCANCODE_ENTER) {
|
||||
djui_interactable_set_input_focus(NULL);
|
||||
if (inputbox->on_enter_press) {
|
||||
inputbox->on_enter_press();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void djui_inputbox_on_key_up(struct DjuiBase *base, int scancode) {
|
||||
switch (scancode) {
|
||||
case SCANCODE_CONTROL_LEFT: sHeldControl &= ~(1 << 0); break;
|
||||
case SCANCODE_CONTROL_RIGHT: sHeldControl &= ~(1 << 1); break;
|
||||
case SCANCODE_SHIFT_LEFT: sHeldShift &= ~(1 << 0); break;
|
||||
case SCANCODE_SHIFT_RIGHT: sHeldShift &= ~(1 << 1); break;
|
||||
}
|
||||
}
|
||||
|
||||
static void djui_inputbox_on_focus_begin(struct DjuiBase* base) {
|
||||
sHeldControl = 0;
|
||||
sHeldShift = 0;
|
||||
wm_api->start_text_input();
|
||||
}
|
||||
|
||||
static void djui_inputbox_on_focus_end(struct DjuiBase* base) {
|
||||
wm_api->stop_text_input();
|
||||
}
|
||||
|
||||
static void djui_inputbox_on_text_input(struct DjuiBase *base, char* text) {
|
||||
struct DjuiInputbox *inputbox = (struct DjuiInputbox *) base;
|
||||
char* msg = inputbox->buffer;
|
||||
int msgLen = strlen(msg);
|
||||
int textLen = strlen(text);
|
||||
|
||||
// truncate
|
||||
if (textLen + msgLen >= inputbox->bufferSize) {
|
||||
int space = (inputbox->bufferSize - msgLen);
|
||||
if (space <= 1) { return; }
|
||||
text[space - 1] = '\0';
|
||||
textLen = space - 1;
|
||||
}
|
||||
|
||||
// erase selection
|
||||
if (inputbox->selection[0] != inputbox->selection[1]) {
|
||||
djui_inputbox_delete_selection(inputbox);
|
||||
}
|
||||
|
||||
// sanitize
|
||||
char *t = text;
|
||||
while (*t != '\0') {
|
||||
if (*t == '\n') { *t = ' '; }
|
||||
else if (*t == '\r') { *t = ' '; }
|
||||
else if (*t == ' ') { ; }
|
||||
else if (*t < '!' || *t > '~') { *t = '?'; }
|
||||
t++;
|
||||
}
|
||||
|
||||
// back up current message
|
||||
char* sMsg = malloc(sizeof(char) * (inputbox->bufferSize));
|
||||
memcpy(sMsg, msg, inputbox->bufferSize);
|
||||
|
||||
// insert text
|
||||
u16 sel = inputbox->selection[0];
|
||||
snprintf(&msg[sel], (inputbox->bufferSize - sel), "%s%s", text, &sMsg[sel]);
|
||||
free(sMsg);
|
||||
|
||||
// adjust cursor
|
||||
inputbox->selection[0] += strlen(text);
|
||||
inputbox->selection[1] = inputbox->selection[0];
|
||||
sCursorBlink = 0;
|
||||
}
|
||||
|
||||
static void djui_inputbox_render_char(struct DjuiInputbox* inputbox, char c, f32* drawX, f32* additionalShift) {
|
||||
struct DjuiBaseRect* comp = &inputbox->base.comp;
|
||||
struct DjuiFont* font = &gDjuiFonts[0];
|
||||
|
@ -74,16 +314,14 @@ static void djui_inputbox_render_char(struct DjuiInputbox* inputbox, char c, f32
|
|||
f32 charWidth = font->char_width(c);
|
||||
*drawX += charWidth * font->defaultFontScale;
|
||||
|
||||
if (c != ' ') {
|
||||
if (djui_gfx_add_clipping_specific(&inputbox->base, font->rotatedUV, dX, dY, dW, dH)) {
|
||||
*additionalShift += charWidth;
|
||||
return;
|
||||
if (c != ' ' && !djui_gfx_add_clipping_specific(&inputbox->base, font->rotatedUV, dX, dY, dW, dH)) {
|
||||
if (*additionalShift > 0) {
|
||||
create_dl_translation_matrix(DJUI_MTX_NOPUSH, *additionalShift, 0, 0);
|
||||
*additionalShift = 0;
|
||||
}
|
||||
font->render_char(c);
|
||||
}
|
||||
|
||||
create_dl_translation_matrix(DJUI_MTX_NOPUSH, charWidth + *additionalShift, 0, 0);
|
||||
*additionalShift = 0;
|
||||
*additionalShift += charWidth;
|
||||
}
|
||||
|
||||
static void djui_inputbox_render_selection(struct DjuiInputbox* inputbox) {
|
||||
|
@ -109,7 +347,7 @@ static void djui_inputbox_render_selection(struct DjuiInputbox* inputbox) {
|
|||
|
||||
// render only cursor when there is no selection width
|
||||
if (selection[0] == selection[1]) {
|
||||
if (sCursorBlink < DJUI_INPUTBOX_MID_BLINK) {
|
||||
if (sCursorBlink < DJUI_INPUTBOX_MID_BLINK && djui_interactable_is_input_focus(&inputbox->base)) {
|
||||
create_dl_translation_matrix(DJUI_MTX_PUSH, x - DJUI_INPUTBOX_CURSOR_WIDTH / 2.0f, -0.1f, 0);
|
||||
create_dl_scale_matrix(DJUI_MTX_NOPUSH, DJUI_INPUTBOX_CURSOR_WIDTH, 0.8f, 1.0f);
|
||||
gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, 255);
|
||||
|
@ -139,7 +377,7 @@ static void djui_inputbox_render_selection(struct DjuiInputbox* inputbox) {
|
|||
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
|
||||
|
||||
// render selection cursor
|
||||
if (sCursorBlink < DJUI_INPUTBOX_MID_BLINK) {
|
||||
if (sCursorBlink < DJUI_INPUTBOX_MID_BLINK && djui_interactable_is_input_focus(&inputbox->base)) {
|
||||
f32 cX = (inputbox->selection[0] < inputbox->selection[1]) ? x : (x + width);
|
||||
create_dl_translation_matrix(DJUI_MTX_PUSH, cX - DJUI_INPUTBOX_CURSOR_WIDTH / 2.0f, -0.1f, 0);
|
||||
create_dl_scale_matrix(DJUI_MTX_NOPUSH, DJUI_INPUTBOX_CURSOR_WIDTH, 0.8f, 1.0f);
|
||||
|
@ -237,13 +475,10 @@ static void djui_inputbox_destroy(struct DjuiBase* base) {
|
|||
struct DjuiInputbox* djui_inputbox_create(struct DjuiBase* parent, u16 bufferSize) {
|
||||
struct DjuiInputbox* inputbox = malloc(sizeof(struct DjuiInputbox));
|
||||
struct DjuiBase* base = &inputbox->base;
|
||||
inputbox->viewX = 0;
|
||||
inputbox->selection[0] = 0;
|
||||
inputbox->selection[1] = 0;
|
||||
memset(inputbox, 0, sizeof(struct DjuiInputbox));
|
||||
inputbox->bufferSize = bufferSize;
|
||||
inputbox->buffer = malloc(sizeof(char) * bufferSize);
|
||||
memset(inputbox->buffer, 0, sizeof(char) * bufferSize);
|
||||
sprintf(inputbox->buffer, "testing string hello world there it is");
|
||||
|
||||
djui_base_init(parent, base, djui_inputbox_render, djui_inputbox_destroy);
|
||||
djui_base_set_size(base, 200, 32);
|
||||
|
@ -251,6 +486,9 @@ struct DjuiInputbox* djui_inputbox_create(struct DjuiBase* parent, u16 bufferSiz
|
|||
djui_interactable_create(base);
|
||||
djui_interactable_hook_hover(base, djui_inputbox_on_hover, djui_inputbox_on_hover_end);
|
||||
djui_interactable_hook_cursor_down(base, djui_inputbox_on_cursor_down_begin, djui_inputbox_on_cursor_down, djui_inputbox_on_cursor_down_end);
|
||||
djui_interactable_hook_key(base, djui_inputbox_on_key_down, djui_inputbox_on_key_up);
|
||||
djui_interactable_hook_focus(base, djui_inputbox_on_focus_begin, NULL, djui_inputbox_on_focus_end);
|
||||
djui_interactable_hook_text_input(base, djui_inputbox_on_text_input);
|
||||
|
||||
djui_inputbox_set_default_style(base);
|
||||
|
||||
|
|
|
@ -8,6 +8,9 @@ struct DjuiInputbox {
|
|||
u16 bufferSize;
|
||||
u16 selection[2];
|
||||
f32 viewX;
|
||||
void (*on_enter_press)(void);
|
||||
};
|
||||
|
||||
void djui_inputbox_hook_enter_press(struct DjuiInputbox* inputbox, void (*on_enter_press)(void));
|
||||
|
||||
struct DjuiInputbox* djui_inputbox_create(struct DjuiBase* parent, u16 bufferSize);
|
||||
|
|
|
@ -26,11 +26,12 @@ static bool sIgnoreInteractableUntilCursorReleased = false;
|
|||
|
||||
static struct DjuiBase* sInteractableFocus = NULL;
|
||||
static struct DjuiBase* sInteractableBinding = NULL;
|
||||
static struct DjuiBase* sHovered = NULL;
|
||||
static struct DjuiBase* sMouseDown = NULL;
|
||||
bool gInteractableOverridePad = false;
|
||||
OSContPad gInteractablePad = { 0 };
|
||||
OSContPad sLastInteractablePad = { 0 };
|
||||
static struct DjuiBase* sHovered = NULL;
|
||||
static struct DjuiBase* sMouseDown = NULL;
|
||||
bool gInteractableOverridePad = false;
|
||||
OSContPad gInteractablePad = { 0 };
|
||||
static OSContPad sLastInteractablePad = { 0 };
|
||||
static int sLastMouseButtons = 0;
|
||||
|
||||
static void djui_interactable_on_click(struct DjuiBase* base) {
|
||||
if (base == NULL) { return; }
|
||||
|
@ -166,17 +167,46 @@ void djui_interactable_set_input_focus(struct DjuiBase* base) {
|
|||
djui_cursor_set_visible(base == NULL);
|
||||
}
|
||||
|
||||
void djui_interactable_on_key_down(int scancode) {
|
||||
switch (scancode) {
|
||||
case SCANCODE_UP: sKeyboardHoldDirection = PAD_HOLD_DIR_UP; break;
|
||||
case SCANCODE_DOWN: sKeyboardHoldDirection = PAD_HOLD_DIR_DOWN; break;
|
||||
case SCANCODE_LEFT: sKeyboardHoldDirection = PAD_HOLD_DIR_LEFT; break;
|
||||
case SCANCODE_RIGHT: sKeyboardHoldDirection = PAD_HOLD_DIR_RIGHT; break;
|
||||
case SCANCODE_ENTER: sKeyboardButtons |= PAD_BUTTON_A; break;
|
||||
bool djui_interactable_is_input_focus(struct DjuiBase* base) {
|
||||
return sInteractableFocus == base;
|
||||
}
|
||||
|
||||
bool djui_interactable_on_key_down(int scancode) {
|
||||
|
||||
bool keyFocused = (sInteractableFocus != NULL)
|
||||
&& (sInteractableFocus->interactable != NULL)
|
||||
&& (sInteractableFocus->interactable->on_key_down != NULL);
|
||||
|
||||
if (keyFocused) {
|
||||
bool consume = sInteractableFocus->interactable->on_key_down(sInteractableFocus, scancode);
|
||||
sKeyboardHoldDirection = PAD_HOLD_DIR_NONE;
|
||||
sKeyboardButtons = 0;
|
||||
return consume;
|
||||
}
|
||||
|
||||
switch (scancode) {
|
||||
case SCANCODE_UP: sKeyboardHoldDirection = PAD_HOLD_DIR_UP; return true;
|
||||
case SCANCODE_DOWN: sKeyboardHoldDirection = PAD_HOLD_DIR_DOWN; return true;
|
||||
case SCANCODE_LEFT: sKeyboardHoldDirection = PAD_HOLD_DIR_LEFT; return true;
|
||||
case SCANCODE_RIGHT: sKeyboardHoldDirection = PAD_HOLD_DIR_RIGHT; return true;
|
||||
case SCANCODE_ENTER: sKeyboardButtons |= PAD_BUTTON_A; return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void djui_interactable_on_key_up(int scancode) {
|
||||
|
||||
bool keyFocused = (sInteractableFocus != NULL)
|
||||
&& (sInteractableFocus->interactable != NULL)
|
||||
&& (sInteractableFocus->interactable->on_key_up != NULL);
|
||||
|
||||
if (keyFocused) {
|
||||
sInteractableFocus->interactable->on_key_up(sInteractableFocus, scancode);
|
||||
sKeyboardHoldDirection = PAD_HOLD_DIR_NONE;
|
||||
sKeyboardButtons = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
OSContPad* pad = &gInteractablePad;
|
||||
switch (scancode) {
|
||||
case SCANCODE_UP: if (sKeyboardHoldDirection == PAD_HOLD_DIR_UP) { sKeyboardHoldDirection = PAD_HOLD_DIR_NONE; pad->stick_y = 0; } break;
|
||||
|
@ -187,6 +217,13 @@ void djui_interactable_on_key_up(int scancode) {
|
|||
}
|
||||
}
|
||||
|
||||
void djui_interactable_on_text_input(char* text) {
|
||||
if (sInteractableFocus == NULL) { return; }
|
||||
if (sInteractableFocus->interactable == NULL) { return; }
|
||||
if (sInteractableFocus->interactable->on_text_input == NULL) { return; }
|
||||
sInteractableFocus->interactable->on_text_input(sInteractableFocus, text);
|
||||
}
|
||||
|
||||
void djui_interactable_update_pad(void) {
|
||||
OSContPad* pad = &gInteractablePad;
|
||||
|
||||
|
@ -252,16 +289,22 @@ void djui_interactable_update(void) {
|
|||
}
|
||||
}
|
||||
|
||||
if (sInteractableBinding != NULL) {
|
||||
djui_interactable_on_bind(sInteractableBinding);
|
||||
} else if (sInteractableFocus != NULL) {
|
||||
// escape focus
|
||||
u16 buttons = PAD_BUTTON_A | PAD_BUTTON_B;
|
||||
if ((padButtons & buttons) && !(sLastInteractablePad.button & buttons)) {
|
||||
// update focused
|
||||
if (sInteractableFocus) {
|
||||
u16 mainButtons = PAD_BUTTON_A | PAD_BUTTON_B;
|
||||
if ((mouseButtons & MOUSE_BUTTON_1) && !(sLastMouseButtons && MOUSE_BUTTON_1) && !djui_cursor_inside_base(sInteractableFocus)) {
|
||||
// clicked outside of focused
|
||||
djui_interactable_set_input_focus(NULL);
|
||||
} else if ((padButtons & mainButtons) && !(sLastInteractablePad.button & mainButtons)) {
|
||||
// pressed main face button
|
||||
djui_interactable_set_input_focus(NULL);
|
||||
} else {
|
||||
djui_interactable_on_focus(sInteractableFocus);
|
||||
}
|
||||
}
|
||||
|
||||
if (sInteractableBinding != NULL) {
|
||||
djui_interactable_on_bind(sInteractableBinding);
|
||||
} else if ((padButtons & PAD_BUTTON_A) || (mouseButtons & MOUSE_BUTTON_1)) {
|
||||
// cursor down events
|
||||
if (sHovered != NULL) {
|
||||
|
@ -288,6 +331,7 @@ void djui_interactable_update(void) {
|
|||
}
|
||||
|
||||
sLastInteractablePad = gInteractablePad;
|
||||
sLastMouseButtons = mouseButtons;
|
||||
}
|
||||
|
||||
void djui_interactable_hook_hover(struct DjuiBase* base,
|
||||
|
@ -336,6 +380,21 @@ void djui_interactable_hook_bind(struct DjuiBase* base,
|
|||
interactable->on_bind = on_bind;
|
||||
}
|
||||
|
||||
void djui_interactable_hook_key(struct DjuiBase* base,
|
||||
bool (*on_key_down)(struct DjuiBase*, int),
|
||||
void (*on_key_up)(struct DjuiBase*, int)) {
|
||||
struct DjuiInteractable *interactable = base->interactable;
|
||||
interactable->on_key_down = on_key_down;
|
||||
interactable->on_key_up = on_key_up;
|
||||
|
||||
}
|
||||
|
||||
void djui_interactable_hook_text_input(struct DjuiBase *base,
|
||||
void (*on_text_input)(struct DjuiBase*, char*)) {
|
||||
struct DjuiInteractable *interactable = base->interactable;
|
||||
interactable->on_text_input = on_text_input;
|
||||
}
|
||||
|
||||
void djui_interactable_create(struct DjuiBase* base) {
|
||||
|
||||
if (base->interactable != NULL) {
|
||||
|
|
|
@ -21,6 +21,9 @@ struct DjuiInteractable {
|
|||
void (*on_click)(struct DjuiBase*);
|
||||
void (*on_value_change)(struct DjuiBase*);
|
||||
void (*on_bind)(struct DjuiBase*);
|
||||
bool (*on_key_down)(struct DjuiBase*, int scancode);
|
||||
void (*on_key_up)(struct DjuiBase*, int scancode);
|
||||
void (*on_text_input)(struct DjuiBase*, char* text);
|
||||
};
|
||||
|
||||
extern bool gInteractableOverridePad;
|
||||
|
@ -29,8 +32,11 @@ extern OSContPad gInteractablePad;
|
|||
bool djui_interactable_is_binding(void);
|
||||
void djui_interactable_set_binding(struct DjuiBase* base);
|
||||
void djui_interactable_set_input_focus(struct DjuiBase* base);
|
||||
void djui_interactable_on_key_down(int scancode);
|
||||
bool djui_interactable_is_input_focus(struct DjuiBase* base);
|
||||
bool djui_interactable_on_key_down(int scancode);
|
||||
void djui_interactable_on_key_up(int scancode);
|
||||
void djui_interactable_on_text_input(char *text);
|
||||
|
||||
void djui_interactable_update(void);
|
||||
|
||||
void djui_interactable_hook_hover(struct DjuiBase* base,
|
||||
|
@ -55,4 +61,12 @@ void djui_interactable_hook_value_change(struct DjuiBase* base,
|
|||
|
||||
void djui_interactable_hook_bind(struct DjuiBase* base,
|
||||
void (*on_bind)(struct DjuiBase*));
|
||||
|
||||
void djui_interactable_hook_key(struct DjuiBase* base,
|
||||
bool (*on_key_down)(struct DjuiBase*, int),
|
||||
void (*on_key_up)(struct DjuiBase*, int));
|
||||
|
||||
void djui_interactable_hook_text_input(struct DjuiBase* base,
|
||||
void (*on_text_input)(struct DjuiBase*, char*));
|
||||
|
||||
void djui_interactable_create(struct DjuiBase* base);
|
||||
|
|
|
@ -16,17 +16,17 @@ void djui_panel_controls_create(struct DjuiBase* caller) {
|
|||
djui_base_set_color(&bindBody->base, 0, 0, 0, 0);
|
||||
djui_flow_layout_set_margin(bindBody, 1);
|
||||
{
|
||||
struct DjuiBind* bind1 = djui_bind_create(&bindBody->base, "A", configKeyA);
|
||||
struct DjuiBind* bind2 = djui_bind_create(&bindBody->base, "B", configKeyB);
|
||||
struct DjuiBind* bind3 = djui_bind_create(&bindBody->base, "Start", configKeyStart);
|
||||
struct DjuiBind* bind4 = djui_bind_create(&bindBody->base, "L", configKeyL);
|
||||
struct DjuiBind* bind5 = djui_bind_create(&bindBody->base, "R", configKeyR);
|
||||
struct DjuiBind* bind6 = djui_bind_create(&bindBody->base, "Z", configKeyZ);
|
||||
struct DjuiBind* bind7 = djui_bind_create(&bindBody->base, "C Up", configKeyCUp);
|
||||
struct DjuiBind* bind8 = djui_bind_create(&bindBody->base, "C Down", configKeyCDown);
|
||||
struct DjuiBind* bind9 = djui_bind_create(&bindBody->base, "C Left", configKeyCLeft);
|
||||
struct DjuiBind* bind10 = djui_bind_create(&bindBody->base, "C Right", configKeyCRight);
|
||||
struct DjuiBind* bind11 = djui_bind_create(&bindBody->base, "Chat", configKeyChat);
|
||||
struct DjuiBind* bind1 = djui_bind_create(&bindBody->base, "A", configKeyA);
|
||||
djui_bind_create(&bindBody->base, "B", configKeyB);
|
||||
djui_bind_create(&bindBody->base, "Start", configKeyStart);
|
||||
djui_bind_create(&bindBody->base, "L", configKeyL);
|
||||
djui_bind_create(&bindBody->base, "R", configKeyR);
|
||||
djui_bind_create(&bindBody->base, "Z", configKeyZ);
|
||||
djui_bind_create(&bindBody->base, "C Up", configKeyCUp);
|
||||
djui_bind_create(&bindBody->base, "C Down", configKeyCDown);
|
||||
djui_bind_create(&bindBody->base, "C Left", configKeyCLeft);
|
||||
djui_bind_create(&bindBody->base, "C Right", configKeyCRight);
|
||||
djui_bind_create(&bindBody->base, "Chat", configKeyChat);
|
||||
defaultBase = &bind1->buttons[0]->base;
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ void djui_panel_main_create(struct DjuiBase* caller) {
|
|||
}
|
||||
|
||||
struct DjuiInputbox* inputbox = djui_inputbox_create(&gDjuiRoot->base, 256);
|
||||
djui_base_set_location(&inputbox->base, 400, 400);
|
||||
djui_base_set_location(&inputbox->base, 400, 100);
|
||||
|
||||
djui_panel_add(caller, &panel->base, defaultBase);
|
||||
gInteractableOverridePad = true;
|
||||
|
|
|
@ -634,6 +634,20 @@ static char* gfx_dxgi_get_clipboard_text(void) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void gfx_dxgi_set_clipboard_text(char* text) {
|
||||
if (OpenClipboard(NULL)) {
|
||||
HGLOBAL clipbuffer;
|
||||
char *buffer;
|
||||
EmptyClipboard();
|
||||
clipbuffer = GlobalAlloc(GMEM_DDESHARE, strlen(text) + 1);
|
||||
buffer = (char *) GlobalLock(clipbuffer);
|
||||
strcpy(buffer, LPCSTR(source));
|
||||
GlobalUnlock(clipbuffer);
|
||||
SetClipboardData(CF_TEXT, clipbuffer);
|
||||
CloseClipboard();
|
||||
}
|
||||
}
|
||||
|
||||
void ThrowIfFailed(HRESULT res) {
|
||||
if (FAILED(res)) {
|
||||
fprintf(stderr, "Error: 0x%08X\n", res);
|
||||
|
@ -665,6 +679,7 @@ struct GfxWindowManagerAPI gfx_dxgi = {
|
|||
gfx_dxgi_start_text_input,
|
||||
gfx_dxgi_stop_text_input,
|
||||
gfx_dxgi_get_clipboard_text,
|
||||
gfx_dxgi_set_clipboard_text,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -369,6 +369,7 @@ static void gfx_sdl_shutdown(void) {
|
|||
static void gfx_sdl_start_text_input(void) { SDL_StartTextInput(); }
|
||||
static void gfx_sdl_stop_text_input(void) { SDL_StopTextInput(); }
|
||||
static char* gfx_sdl_get_clipboard_text(void) { return SDL_GetClipboardText(); }
|
||||
static void gfx_sdl_set_clipboard_text(char* text) { SDL_SetClipboardText(text); }
|
||||
|
||||
struct GfxWindowManagerAPI gfx_sdl = {
|
||||
gfx_sdl_init,
|
||||
|
@ -384,6 +385,7 @@ struct GfxWindowManagerAPI gfx_sdl = {
|
|||
gfx_sdl_start_text_input,
|
||||
gfx_sdl_stop_text_input,
|
||||
gfx_sdl_get_clipboard_text,
|
||||
gfx_sdl_set_clipboard_text,
|
||||
};
|
||||
|
||||
#endif // BACKEND_WM
|
||||
|
|
|
@ -23,6 +23,7 @@ struct GfxWindowManagerAPI {
|
|||
void (*start_text_input)(void);
|
||||
void (*stop_text_input)(void);
|
||||
char* (*get_clipboard_text)(void);
|
||||
void (*set_clipboard_text)(char*);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue