diff --git a/build-windows-visual-studio/sm64ex.vcxproj b/build-windows-visual-studio/sm64ex.vcxproj index 31c4ff6b6..fed72c0cb 100644 --- a/build-windows-visual-studio/sm64ex.vcxproj +++ b/build-windows-visual-studio/sm64ex.vcxproj @@ -3942,6 +3942,8 @@ + + @@ -4388,6 +4390,8 @@ + + diff --git a/build-windows-visual-studio/sm64ex.vcxproj.filters b/build-windows-visual-studio/sm64ex.vcxproj.filters index c95d97925..bc6bc802b 100644 --- a/build-windows-visual-studio/sm64ex.vcxproj.filters +++ b/build-windows-visual-studio/sm64ex.vcxproj.filters @@ -15264,6 +15264,12 @@ Source Files\src\pc\djui\panel + + Source Files\src\pc\djui\component + + + Source Files\src\pc\djui\component\compound + @@ -16348,5 +16354,11 @@ Source Files\src\pc\djui\panel + + Source Files\src\pc\djui\component + + + Source Files\src\pc\djui\component\compound + \ No newline at end of file diff --git a/src/pc/djui/djui.c b/src/pc/djui/djui.c index af4b1064d..f19074161 100644 --- a/src/pc/djui/djui.c +++ b/src/pc/djui/djui.c @@ -22,7 +22,6 @@ void djui_init(void) { djui_panel_main_create(NULL); //djui_panel_debug_create(); } - djui_cursor_create(); } diff --git a/src/pc/djui/djui.h b/src/pc/djui/djui.h index c810cf4be..bedb8c07d 100644 --- a/src/pc/djui/djui.h +++ b/src/pc/djui/djui.h @@ -28,6 +28,8 @@ #include "djui_selectionbox.h" #include "djui_bind.h" #include "djui_popup.h" +#include "djui_chat_box.h" +#include "djui_chat_message.h" #include "djui_panel.h" #include "djui_panel_menu.h" diff --git a/src/pc/djui/djui_base.c b/src/pc/djui/djui_base.c index 8e491b5ac..535fafd0e 100644 --- a/src/pc/djui/djui_base.c +++ b/src/pc/djui/djui_base.c @@ -180,7 +180,8 @@ static void djui_base_add_child(struct DjuiBase* parent, struct DjuiBase* base) baseChild->next = NULL; // add it to the head - if (parent->child == NULL) { + if (parent->child == NULL || parent->addChildrenToHead) { + baseChild->next = parent->child; parent->child = baseChild; return; } @@ -269,29 +270,29 @@ static void djui_base_render_border(struct DjuiBase* base) { // events // //////////// -void djui_base_render(struct DjuiBase* base) { - if (!base->visible) { return; } +bool djui_base_render(struct DjuiBase* base) { + if (!base->visible) { return false; } if (base->on_render_pre != NULL) { bool skipRender = false; base->on_render_pre(base, &skipRender); - if (skipRender) { return; } + if (skipRender) { return false; } } struct DjuiBaseRect* comp = &base->comp; struct DjuiBaseRect* clip = &base->clip; djui_base_compute(base); - if (comp->width <= 0) { return; } - if (comp->height <= 0) { return; } - if (clip->width <= 0) { return; } - if (clip->height <= 0) { return; } + if (comp->width <= 0) { return false; } + if (comp->height <= 0) { return false; } + if (clip->width <= 0) { return false; } + if (clip->height <= 0) { return false; } if (base->borderWidth.value > 0 && base->borderColor.a > 0) { djui_base_render_border(base); } - if (clip->width < 0 || clip->height <= 0) { return; } + if (clip->width < 0 || clip->height <= 0) { return false; } if (base->render != NULL) { base->render(base); @@ -301,16 +302,20 @@ void djui_base_render(struct DjuiBase* base) { // render all children struct DjuiBaseChild* child = base->child; + bool hasChildRendered = false; while (child != NULL) { struct DjuiBaseChild* nextChild = child->next; - djui_base_render(child->base); - + bool childRendered = djui_base_render(child->base); + if (base->abandonAfterChildRenderFail && !childRendered && hasChildRendered) { break; } + hasChildRendered = hasChildRendered || childRendered; if (base->on_child_render != NULL) { base->on_child_render(base, child->base); } child = nextChild; } + + return true; } void djui_base_destroy(struct DjuiBase* base) { diff --git a/src/pc/djui/djui_base.h b/src/pc/djui/djui_base.h index bfc8aeda3..b6a59e2fd 100644 --- a/src/pc/djui/djui_base.h +++ b/src/pc/djui/djui_base.h @@ -43,6 +43,8 @@ struct DjuiBase { struct DjuiBaseRect comp; struct DjuiBaseRect clip; struct DjuiInteractable* interactable; + bool addChildrenToHead; + bool abandonAfterChildRenderFail; s32 tag; void (*get_cursor_hover_location)(struct DjuiBase*, f32* x, f32* y); void (*on_child_render)(struct DjuiBase*, struct DjuiBase*); @@ -67,6 +69,6 @@ void djui_base_set_alignment(struct DjuiBase* base, enum DjuiHAlign hAlign, enum void djui_base_compute(struct DjuiBase* base); -void djui_base_render(struct DjuiBase* base); +bool djui_base_render(struct DjuiBase* base); void djui_base_destroy(struct DjuiBase* base); void djui_base_init(struct DjuiBase* parent, struct DjuiBase* base, void (*render)(struct DjuiBase*), void (*destroy)(struct DjuiBase*)); diff --git a/src/pc/djui/djui_chat_box.c b/src/pc/djui/djui_chat_box.c new file mode 100644 index 000000000..0b0bec17c --- /dev/null +++ b/src/pc/djui/djui_chat_box.c @@ -0,0 +1,135 @@ +#include +#include +#include "pc/network/network.h" +#include "djui.h" + +struct DjuiChatBox* gDjuiChatBox = NULL; +bool gDjuiChatBoxFocus = false; + +void djui_chat_box_render(struct DjuiBase* base) { + struct DjuiChatBox* chatBox = (struct DjuiChatBox*)base; + struct DjuiBase* ccBase = &chatBox->chatContainer->base; + djui_base_set_size(ccBase, 1.0f, chatBox->base.comp.height - 32 - 8); +} + +static void djui_chat_box_destroy(struct DjuiBase* base) { + struct DjuiChatBox* chatBox = (struct DjuiChatBox*)base; + free(chatBox); +} + +static void djui_chat_box_set_focus_style(void) { + djui_base_set_visible(&gDjuiChatBox->chatInput->base, gDjuiChatBoxFocus); + if (gDjuiChatBoxFocus) { + djui_interactable_set_input_focus(&gDjuiChatBox->chatInput->base); + } + + djui_base_set_color(&gDjuiChatBox->chatFlow->base, 0, 0, 0, gDjuiChatBoxFocus ? 128 : 0); +} + +static void djui_chat_box_input_enter(struct DjuiInputbox* chatInput) { + djui_interactable_set_input_focus(NULL); + + if (strlen(chatInput->buffer) != 0) { + djui_chat_message_create_from(gNetworkPlayerLocal->globalIndex, chatInput->buffer); + network_send_chat(chatInput->buffer, gNetworkPlayerLocal->globalIndex); + } + + djui_inputbox_set_text(chatInput, ""); + djui_inputbox_select_all(chatInput); + if (gDjuiChatBoxFocus) { djui_chat_box_toggle(); } +} + +static void djui_chat_box_input_escape(struct DjuiInputbox* chatInput) { + djui_inputbox_set_text(chatInput, ""); + djui_inputbox_select_all(chatInput); + if (gDjuiChatBoxFocus) { djui_chat_box_toggle(); } +} + +static bool djui_chat_box_input_on_key_down(struct DjuiBase* base, int scancode) { + if (gDjuiChatBox == NULL) { return false; } + f32 yMax = gDjuiChatBox->chatContainer->base.elem.height - gDjuiChatBox->chatFlow->base.height.value; + + f32* yValue = &gDjuiChatBox->chatFlow->base.y.value; + bool canScrollUp = (*yValue > yMax); + bool canScrollDown = (*yValue < 0); + f32 pageAmount = gDjuiChatBox->chatFlow->base.elem.height / 3.0f; + + switch (scancode) { + case SCANCODE_UP: + gDjuiChatBox->scrolling = true; + if (canScrollUp) { *yValue = fmax(*yValue - 15, yMax); } + return true; + case SCANCODE_DOWN: + gDjuiChatBox->scrolling = true; + if (canScrollDown) { *yValue = fmin(*yValue + 15, 0); } + return true; + case SCANCODE_PAGE_UP: + gDjuiChatBox->scrolling = true; + if (canScrollUp) { *yValue = fmax(*yValue - pageAmount, yMax); } + return true; + case SCANCODE_PAGE_DOWN: + gDjuiChatBox->scrolling = true; + if (canScrollDown) { *yValue = fmin(*yValue + pageAmount, 0); } + return true; + case SCANCODE_ENTER: djui_chat_box_input_enter(gDjuiChatBox->chatInput); return true; + case SCANCODE_ESCAPE: djui_chat_box_input_escape(gDjuiChatBox->chatInput); return true; + default: return djui_inputbox_on_key_down(base, scancode); + } +} + +void djui_chat_box_toggle(void) { + if (gDjuiChatBox == NULL) { return; } + gDjuiChatBoxFocus = !gDjuiChatBoxFocus; + djui_chat_box_set_focus_style(); + gDjuiChatBox->scrolling = false; + gDjuiChatBox->chatFlow->base.y.value = gDjuiChatBox->chatContainer->base.elem.height - gDjuiChatBox->chatFlow->base.height.value; +} + +struct DjuiChatBox* djui_chat_box_create(void) { + if (gDjuiChatBox != NULL) { + djui_base_destroy(&gDjuiChatBox->base); + gDjuiChatBox = NULL; + } + + struct DjuiChatBox* chatBox = malloc(sizeof(struct DjuiChatBox)); + struct DjuiBase* base = &chatBox->base; + + djui_base_init(&gDjuiRoot->base, base, djui_chat_box_render, djui_chat_box_destroy); + djui_base_set_size_type(base, DJUI_SVT_ABSOLUTE, DJUI_SVT_RELATIVE); + djui_base_set_size(base, 600, 1.0f); + djui_base_set_alignment(base, DJUI_HALIGN_LEFT, DJUI_VALIGN_TOP); + djui_base_set_color(base, 0, 0, 0, 0); + djui_base_set_padding(base, 0, 8, 8, 8); + + struct DjuiRect* chatContainer = djui_rect_create(base); + struct DjuiBase* ccBase = &chatContainer->base; + djui_base_set_size_type(ccBase, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(ccBase, 1.0f, 0); + djui_base_set_color(ccBase, 0, 0, 0, 0); + chatBox->chatContainer = chatContainer; + + struct DjuiFlowLayout* chatFlow = djui_flow_layout_create(ccBase); + struct DjuiBase* cfBase = &chatFlow->base; + djui_base_set_location(cfBase, 0, 0); + djui_base_set_size_type(cfBase, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(cfBase, 1.0f, 2); + djui_base_set_color(cfBase, 0, 0, 0, 128); + djui_base_set_padding(cfBase, 2, 2, 2, 2); + djui_flow_layout_set_margin(chatFlow, 2); + djui_flow_layout_set_flow_direction(chatFlow, DJUI_FLOW_DIR_UP); + cfBase->addChildrenToHead = true; + cfBase->abandonAfterChildRenderFail = true; + chatBox->chatFlow = chatFlow; + + struct DjuiInputbox* chatInput = djui_inputbox_create(base, 200); + struct DjuiBase* ciBase = &chatInput->base; + djui_base_set_size_type(ciBase, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(ciBase, 1.0f, 32); + djui_base_set_alignment(ciBase, DJUI_HALIGN_LEFT, DJUI_VALIGN_BOTTOM); + djui_interactable_hook_key(&chatInput->base, djui_chat_box_input_on_key_down, djui_inputbox_on_key_up); + chatBox->chatInput = chatInput; + + gDjuiChatBox = chatBox; + djui_chat_box_set_focus_style(); + return chatBox; +} diff --git a/src/pc/djui/djui_chat_box.h b/src/pc/djui/djui_chat_box.h new file mode 100644 index 000000000..99467b895 --- /dev/null +++ b/src/pc/djui/djui_chat_box.h @@ -0,0 +1,17 @@ +#pragma once +#include "djui.h" + +#pragma pack(1) +struct DjuiChatBox { + struct DjuiBase base; + struct DjuiRect* chatContainer; + struct DjuiFlowLayout* chatFlow; + struct DjuiInputbox* chatInput; + bool scrolling; +}; + +extern struct DjuiChatBox* gDjuiChatBox; +extern bool gDjuiChatBoxFocus; + +void djui_chat_box_toggle(void); +struct DjuiChatBox* djui_chat_box_create(void); diff --git a/src/pc/djui/djui_chat_message.c b/src/pc/djui/djui_chat_message.c new file mode 100644 index 000000000..175732630 --- /dev/null +++ b/src/pc/djui/djui_chat_message.c @@ -0,0 +1,91 @@ +#include +#include "pc/network/network.h" +#include "audio_defines.h" +#include "audio/external.h" +#include "game/mario_misc.h" +#include "djui.h" + +#define DJUI_CHAT_LIFE_TIME 10.0f + +static void djui_chat_message_render(struct DjuiBase* base) { + struct DjuiChatMessage* chatMessage = (struct DjuiChatMessage*)base; + struct DjuiBase* ctBase = &chatMessage->message->base; + + f32 seconds = (clock() - chatMessage->createTime) / (f32)CLOCKS_PER_SEC; + f32 f = 1.0f; + if (seconds >= (DJUI_CHAT_LIFE_TIME - 1)) { + f = fmax(1.0f - (seconds - (DJUI_CHAT_LIFE_TIME - 1)), 0.0f); + f *= f; + f *= f; + } + + if (gDjuiChatBoxFocus) { + djui_base_set_color(base, 0, 0, 0, 64); + djui_base_set_color(ctBase, 255, 255, 255, 255); + djui_text_set_drop_shadow(chatMessage->message, 0, 0, 0, 200); + djui_base_set_size_type(base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(base, 1.0f, chatMessage->base.height.value); + } else { + djui_base_set_color(base, 0, 0, 0, 150 * f); + djui_base_set_color(ctBase, 255, 255, 255, 255 * f); + djui_text_set_drop_shadow(chatMessage->message, 0, 0, 0, 200 * f); + djui_base_set_size_type(base, DJUI_SVT_ABSOLUTE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(base, chatMessage->messageWidth, chatMessage->base.height.value); + } + + djui_rect_render(base); +} + +static void djui_chat_message_destroy(struct DjuiBase* base) { + struct DjuiChatMessage* chatMessage = (struct DjuiChatMessage*)base; + free(chatMessage); +} + +struct DjuiChatMessage* djui_chat_message_create_from(u8 globalIndex, char* message) { + u8* rgb = get_player_color(globalIndex, 0); + u8 rgb2[3] = { 0 }; + for (int i = 0; i < 3; i++) { rgb2[i] = fmin((f32)rgb[i] * 1.3f + 32.0f, 255); } + char chatMsg[256] = { 0 }; + snprintf(chatMsg, 256, "\\#%02x%02x%02x\\%s:\\#dcdcdc\\ %s", rgb2[0], rgb2[1], rgb2[2], "Player", message); + play_sound((globalIndex == gNetworkPlayerLocal->globalIndex) ? SOUND_MENU_MESSAGE_DISAPPEAR : SOUND_MENU_MESSAGE_APPEAR, gDefaultSoundArgs); + return djui_chat_message_create(chatMsg); +} + +struct DjuiChatMessage* djui_chat_message_create(char* message) { + struct DjuiChatMessage* chatMessage = malloc(sizeof(struct DjuiChatMessage)); + struct DjuiBase* base = &chatMessage->base; + djui_base_init(&gDjuiChatBox->chatFlow->base, base, djui_chat_message_render, djui_chat_message_destroy); + djui_base_set_size_type(base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(base, 1.0f, 0); + djui_base_set_color(base, 0, 0, 0, 64); + djui_base_set_padding(base, 2, 4, 2, 4); + djui_base_set_alignment(base, DJUI_HALIGN_LEFT, DJUI_VALIGN_BOTTOM); + + f32 maxTextWidth = gDjuiChatBox->base.width.value - gDjuiChatBox->base.padding.left.value - gDjuiChatBox->base.padding.right.value - base->padding.left.value - base->padding.right.value; + + struct DjuiText* chatText = djui_text_create(base, message); + struct DjuiBase* ctBase = &chatText->base; + djui_base_set_size_type(ctBase, DJUI_SVT_ABSOLUTE, DJUI_SVT_RELATIVE); + djui_base_set_size(ctBase, maxTextWidth, 1.0f); + djui_base_set_color(ctBase, 255, 255, 255, 255); + djui_base_set_location(ctBase, 0, 0); + djui_text_set_alignment(chatText, DJUI_HALIGN_LEFT, DJUI_VALIGN_TOP); + djui_text_set_drop_shadow(chatText, 0, 0, 0, 200); + chatMessage->message = chatText; + chatMessage->createTime = clock(); + + // figure out chat message height + chatText->base.comp.width = maxTextWidth; + f32 messageHeight = djui_text_count_lines(chatText, 10) * (chatText->font->lineHeight * chatText->font->defaultFontScale) + 8; + djui_base_set_size(base, 1.0f, messageHeight); + gDjuiChatBox->chatFlow->base.height.value += messageHeight + gDjuiChatBox->chatFlow->margin.value; + if (!gDjuiChatBox->scrolling) { + gDjuiChatBox->chatFlow->base.y.value = gDjuiChatBox->chatContainer->base.elem.height - gDjuiChatBox->chatFlow->base.height.value; + } + + // figure out chat message width + f32 messageWidth = djui_text_find_width(chatText, 10); + chatMessage->messageWidth = messageWidth + 8; + + return chatMessage; +} diff --git a/src/pc/djui/djui_chat_message.h b/src/pc/djui/djui_chat_message.h new file mode 100644 index 000000000..7b8b3cd83 --- /dev/null +++ b/src/pc/djui/djui_chat_message.h @@ -0,0 +1,14 @@ +#pragma once +#include "djui.h" +#include + +#pragma pack(1) +struct DjuiChatMessage { + struct DjuiBase base; + struct DjuiText* message; + f32 messageWidth; + clock_t createTime; +}; + +struct DjuiChatMessage* djui_chat_message_create_from(u8 globalIndex, char* message); +struct DjuiChatMessage* djui_chat_message_create(char* message); diff --git a/src/pc/djui/djui_inputbox.c b/src/pc/djui/djui_inputbox.c index 36d214859..afb4d6803 100644 --- a/src/pc/djui/djui_inputbox.c +++ b/src/pc/djui/djui_inputbox.c @@ -38,10 +38,14 @@ void djui_inputbox_select_all(struct DjuiInputbox* inputbox) { inputbox->selection[0] = strlen(inputbox->buffer); } -void djui_inputbox_hook_enter_press(struct DjuiInputbox* inputbox, void (*on_enter_press)(void)) { +void djui_inputbox_hook_enter_press(struct DjuiInputbox* inputbox, void (*on_enter_press)(struct DjuiInputbox*)) { inputbox->on_enter_press = on_enter_press; } +void djui_inputbox_hook_escape_press(struct DjuiInputbox* inputbox, void (*on_escape_press)(struct DjuiInputbox*)) { + inputbox->on_escape_press = on_escape_press; +} + static void djui_inputbox_set_default_style(struct DjuiBase* base) { struct DjuiInputbox* inputbox = (struct DjuiInputbox*)base; if (inputbox->base.enabled) { @@ -152,7 +156,7 @@ static void djui_inputbox_delete_selection(struct DjuiInputbox *inputbox) { djui_inputbox_on_change(inputbox); } -static bool djui_inputbox_on_key_down(struct DjuiBase *base, int scancode) { +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; @@ -261,13 +265,16 @@ static bool djui_inputbox_on_key_down(struct DjuiBase *base, int scancode) { if (scancode == SCANCODE_ESCAPE) { djui_interactable_set_input_focus(NULL); + if (inputbox->on_escape_press) { + inputbox->on_escape_press(inputbox); + } return true; } if (scancode == SCANCODE_ENTER) { djui_interactable_set_input_focus(NULL); if (inputbox->on_enter_press) { - inputbox->on_enter_press(); + inputbox->on_enter_press(inputbox); } return true; } @@ -275,7 +282,7 @@ static bool djui_inputbox_on_key_down(struct DjuiBase *base, int scancode) { return true; } -static void djui_inputbox_on_key_up(struct DjuiBase *base, int scancode) { +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; diff --git a/src/pc/djui/djui_inputbox.h b/src/pc/djui/djui_inputbox.h index 3556fbc7b..8627be556 100644 --- a/src/pc/djui/djui_inputbox.h +++ b/src/pc/djui/djui_inputbox.h @@ -9,12 +9,16 @@ struct DjuiInputbox { u16 selection[2]; f32 viewX; struct DjuiColor textColor; - void (*on_enter_press)(void); + void (*on_enter_press)(struct DjuiInputbox*); + void (*on_escape_press)(struct DjuiInputbox*); }; void djui_inputbox_set_text_color(struct DjuiInputbox* inputbox, u8 r, u8 g, u8 b, u8 a); void djui_inputbox_set_text(struct DjuiInputbox* inputbox, char* text); void djui_inputbox_select_all(struct DjuiInputbox* inputbox); -void djui_inputbox_hook_enter_press(struct DjuiInputbox* inputbox, void (*on_enter_press)(void)); +void djui_inputbox_hook_enter_press(struct DjuiInputbox* inputbox, void (*on_enter_press)(struct DjuiInputbox*)); +void djui_inputbox_hook_escape_press(struct DjuiInputbox* inputbox, void (*on_escape_press)(struct DjuiInputbox*)); +bool djui_inputbox_on_key_down(struct DjuiBase* base, int scancode); +void djui_inputbox_on_key_up(struct DjuiBase* base, int scancode); struct DjuiInputbox* djui_inputbox_create(struct DjuiBase* parent, u16 bufferSize); diff --git a/src/pc/djui/djui_interactable.c b/src/pc/djui/djui_interactable.c index e1e91723a..b8508b120 100644 --- a/src/pc/djui/djui_interactable.c +++ b/src/pc/djui/djui_interactable.c @@ -9,15 +9,6 @@ #include "audio_defines.h" #include "audio/external.h" -#define SCANCODE_UP 328 -#define SCANCODE_DOWN 336 -#define SCANCODE_LEFT 331 -#define SCANCODE_RIGHT 333 - -#define SCANCODE_ENTER 28 -#define SCANCODE_SPACE 57 -#define SCANCODE_ESCAPE 1 - enum PadHoldDirection { PAD_HOLD_DIR_NONE, PAD_HOLD_DIR_UP, PAD_HOLD_DIR_DOWN, PAD_HOLD_DIR_LEFT, PAD_HOLD_DIR_RIGHT }; static enum PadHoldDirection sKeyboardHoldDirection = PAD_HOLD_DIR_NONE; static u16 sKeyboardButtons = 0; @@ -179,9 +170,11 @@ bool djui_interactable_on_key_down(int scancode) { if (keyFocused) { bool consume = sInteractableFocus->interactable->on_key_down(sInteractableFocus, scancode); - sKeyboardHoldDirection = PAD_HOLD_DIR_NONE; - sKeyboardButtons = 0; - return consume; + if (consume) { + sKeyboardHoldDirection = PAD_HOLD_DIR_NONE; + sKeyboardButtons = 0; + return true; + } } if (scancode == SCANCODE_ESCAPE) { @@ -189,6 +182,18 @@ bool djui_interactable_on_key_down(int scancode) { djui_panel_back(); } + if (gDjuiChatBox != NULL && !gDjuiChatBoxFocus) { + bool pressChat = false; + for (int i = 0; i < MAX_BINDS; i++) { + if (scancode == (int)configKeyChat[i]) { pressChat = true; } + } + + if (pressChat) { + djui_chat_box_toggle(); + return true; + } + } + switch (scancode) { case SCANCODE_UP: sKeyboardHoldDirection = PAD_HOLD_DIR_UP; return true; case SCANCODE_DOWN: sKeyboardHoldDirection = PAD_HOLD_DIR_DOWN; return true; @@ -196,6 +201,7 @@ bool djui_interactable_on_key_down(int scancode) { case SCANCODE_RIGHT: sKeyboardHoldDirection = PAD_HOLD_DIR_RIGHT; return true; case SCANCODE_ENTER: sKeyboardButtons |= PAD_BUTTON_A; return true; } + return false; } diff --git a/src/pc/djui/djui_interactable.h b/src/pc/djui/djui_interactable.h index f83d555f2..2fba0528d 100644 --- a/src/pc/djui/djui_interactable.h +++ b/src/pc/djui/djui_interactable.h @@ -8,6 +8,18 @@ #define MOUSE_BUTTON_1 ((u16)(1 << 0)) +#define SCANCODE_UP 328 +#define SCANCODE_DOWN 336 +#define SCANCODE_LEFT 331 +#define SCANCODE_RIGHT 333 +#define SCANCODE_PAGE_DOWN 337 +#define SCANCODE_PAGE_UP 329 + + +#define SCANCODE_ENTER 28 +#define SCANCODE_SPACE 57 +#define SCANCODE_ESCAPE 1 + #pragma pack(1) struct DjuiInteractable { bool enabled; diff --git a/src/pc/djui/djui_panel_pause.c b/src/pc/djui/djui_panel_pause.c index 1aa843dbb..0df1813eb 100644 --- a/src/pc/djui/djui_panel_pause.c +++ b/src/pc/djui/djui_panel_pause.c @@ -19,6 +19,8 @@ static void djui_panel_pause_quit(struct DjuiBase* caller) { } void djui_panel_pause_create(struct DjuiBase* caller) { + if (gDjuiChatBoxFocus) { djui_chat_box_toggle(); } + f32 bodyHeight = 64 * 3 + 16 * 2; if (Cheats.EnableCheats) { bodyHeight += 64 + 16; } diff --git a/src/pc/djui/djui_text.c b/src/pc/djui/djui_text.c index 9c56cf7d8..a493b600f 100644 --- a/src/pc/djui/djui_text.c +++ b/src/pc/djui/djui_text.c @@ -169,6 +169,46 @@ static void djui_text_read_line(struct DjuiText* text, u16* index, f32* lineWidt }*/ } +int djui_text_count_lines(struct DjuiText* text, u16 maxLines) { + struct DjuiBaseRect* comp = &text->base.comp; + u16 startIndex = 0; + u16 endIndex = 0; + f32 maxLineWidth = comp->width / ((f32)text->fontScale); + u16 lineCount = 0; + while (text->message[startIndex] != '\0') { + bool onLastLine = lineCount + 1 >= maxLines; + f32 lineWidth; + bool ellipses; + djui_text_read_line(text, &endIndex, &lineWidth, maxLineWidth, onLastLine, &ellipses); + startIndex = endIndex; + lineCount++; + if (onLastLine) { break; } + } + return lineCount; +} + +f32 djui_text_find_width(struct DjuiText* text, u16 maxLines) { + struct DjuiBaseRect* comp = &text->base.comp; + u16 startIndex = 0; + u16 endIndex = 0; + f32 maxLineWidth = comp->width / ((f32)text->fontScale); + u16 lineCount = 0; + + f32 largestWidth = 0; + + while (text->message[startIndex] != '\0') { + bool onLastLine = lineCount + 1 >= maxLines; + f32 lineWidth; + bool ellipses; + djui_text_read_line(text, &endIndex, &lineWidth, maxLineWidth, onLastLine, &ellipses); + largestWidth = fmax(largestWidth, lineWidth); + startIndex = endIndex; + lineCount++; + if (onLastLine) { break; } + } + return largestWidth * text->fontScale; +} + static int djui_text_render_line_parse_escape(struct DjuiText* text, u16 startIndex, u16 endIndex) { bool parsingColor = text->message[startIndex + 1] == '#'; u16 i = parsingColor ? (startIndex + 1) : startIndex; @@ -298,20 +338,9 @@ static void djui_text_render(struct DjuiBase* base) { sSavedA = base->color.a; // count lines - u16 startIndex = 0; - u16 endIndex = 0; - f32 maxLineWidth = comp->width / ((f32)text->fontScale); - u16 lineCount = 0; u16 maxLines = comp->height / ((f32)text->font->lineHeight * text->fontScale); - while (text->message[startIndex] != '\0') { - bool onLastLine = lineCount + 1 >= maxLines; - f32 lineWidth; - bool ellipses; - djui_text_read_line(text, &endIndex, &lineWidth, maxLineWidth, onLastLine, &ellipses); - startIndex = endIndex; - lineCount++; - if (onLastLine) { break; } - } + f32 maxLineWidth = comp->width / ((f32)text->fontScale); + u16 lineCount = djui_text_count_lines(text, maxLines); // do vertical alignment f32 vOffset = 0; @@ -325,8 +354,8 @@ static void djui_text_render(struct DjuiBase* base) { djui_text_translate(0, vOffset); // render lines - startIndex = 0; - endIndex = 0; + u16 startIndex = 0; + u16 endIndex = 0; f32 lineWidth; u16 lineIndex = 0; bool ellipses = false; diff --git a/src/pc/djui/djui_text.h b/src/pc/djui/djui_text.h index 92c40e290..401eb3c14 100644 --- a/src/pc/djui/djui_text.h +++ b/src/pc/djui/djui_text.h @@ -18,4 +18,7 @@ void djui_text_set_font_scale(struct DjuiText* text, f32 fontScale); void djui_text_set_drop_shadow(struct DjuiText* text, f32 r, f32 g, f32 b, f32 a); void djui_text_set_alignment(struct DjuiText* text, enum DjuiHAlign hAlign, enum DjuiVAlign vAlign); +int djui_text_count_lines(struct DjuiText* text, u16 maxLines); +f32 djui_text_find_width(struct DjuiText* text, u16 maxLines); + struct DjuiText* djui_text_create(struct DjuiBase* parent, const char* message); diff --git a/src/pc/network/network.c b/src/pc/network/network.c index 24e7c6630..dbbf8d8af 100644 --- a/src/pc/network/network.c +++ b/src/pc/network/network.c @@ -10,6 +10,7 @@ #endif #include "pc/configfile.h" #include "pc/cheats.h" +#include "pc/djui/djui.h" #include "pc/debuglog.h" // Mario 64 specific externs @@ -81,6 +82,8 @@ bool network_init(enum NetworkType inNetworkType) { network_player_connected(NPT_LOCAL, 0); extern u8* gOverrideEeprom; gOverrideEeprom = NULL; + + djui_chat_box_create(); } else if (gNetworkType == NT_CLIENT) { network_player_connected(NPT_SERVER, 0); } @@ -267,6 +270,11 @@ void network_register_mod(char* modName) { } void network_shutdown(bool sendLeaving) { + if (gDjuiChatBox != NULL) { + djui_base_destroy(&gDjuiChatBox->base); + gDjuiChatBox = NULL; + } + network_forget_all_reliable(); if (gNetworkType == NT_NONE) { return; } if (gNetworkSystem == NULL) { LOG_ERROR("no network system attached"); return; } @@ -277,8 +285,3 @@ void network_shutdown(bool sendLeaving) { gNetworkType = NT_NONE; } - -// TODO: replace -void chat_add_message(char* message) { - LOG_INFO("chat: %s", message); -} diff --git a/src/pc/network/network.h b/src/pc/network/network.h index d6dd42ccd..7fdf06392 100644 --- a/src/pc/network/network.h +++ b/src/pc/network/network.h @@ -102,6 +102,4 @@ void network_update(void); void network_register_mod(char* modName); void network_shutdown(bool sendLeaving); -// TODO: replace -void chat_add_message(char* message); #endif diff --git a/src/pc/network/network_player.c b/src/pc/network/network_player.c index baff5ca83..4f53b903d 100644 --- a/src/pc/network/network_player.c +++ b/src/pc/network/network_player.c @@ -183,8 +183,10 @@ u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex) { } else { // display popup u8* rgb = get_player_color(np->globalIndex, 0); + u8 rgb2[3] = { 0 }; + for (int i = 0; i < 3; i++) { rgb2[i] = fmin((f32)rgb[i] * 1.3f + 32.0f, 255); } char popupMsg[128] = { 0 }; - snprintf(popupMsg, 128, "\\#%02x%02x%02x\\Player\\#dcdcdc\\ connected.", rgb[0], rgb[1], rgb[2]); + snprintf(popupMsg, 128, "\\#%02x%02x%02x\\%s\\#dcdcdc\\ connected.", rgb2[0], rgb2[1], rgb2[2], "Player"); djui_popup_create(popupMsg, 1); } LOG_INFO("player connected, local %d, global %d", i, np->globalIndex); @@ -229,8 +231,10 @@ u8 network_player_disconnected(u8 globalIndex) { // display popup u8* rgb = get_player_color(np->globalIndex, 0); + u8 rgb2[3] = { 0 }; + for (int i = 0; i < 3; i++) { rgb2[i] = fmin((f32)rgb[i] * 1.3f + 32.0f, 255); } char popupMsg[128] = { 0 }; - snprintf(popupMsg, 128, "\\#%02x%02x%02x\\Player\\#dcdcdc\\ disconnected.", rgb[0], rgb[1], rgb[2]); + snprintf(popupMsg, 128, "\\#%02x%02x%02x\\%s\\#dcdcdc\\ disconnected.", rgb2[0], rgb2[1], rgb2[2], "Player"); djui_popup_create(popupMsg, 1); packet_ordered_clear(globalIndex); diff --git a/src/pc/network/packets/packet.h b/src/pc/network/packets/packet.h index 8614b676f..6cafa3af9 100644 --- a/src/pc/network/packets/packet.h +++ b/src/pc/network/packets/packet.h @@ -169,7 +169,7 @@ void network_send_custom(u8 customId, bool reliable, bool levelAreaMustMatch, vo void network_receive_custom(struct Packet* p); // packet_chat.c -void network_send_chat(char* message, u8 rgb[3]); +void network_send_chat(char* message, u8 globalIndex); void network_receive_chat(struct Packet* p); // packet_kick.c diff --git a/src/pc/network/packets/packet_chat.c b/src/pc/network/packets/packet_chat.c index b8fd3ae01..a73b278cf 100644 --- a/src/pc/network/packets/packet_chat.c +++ b/src/pc/network/packets/packet_chat.c @@ -1,6 +1,7 @@ #include #include "../network.h" #include "../reservation_area.h" +#include "pc/djui/djui.h" #include "pc/debuglog.h" #ifdef DEVELOPMENT @@ -28,11 +29,11 @@ static void print_network_player_table(void) { } #endif -void network_send_chat(char* message, u8 rgb[3]) { +void network_send_chat(char* message, u8 globalIndex) { u16 messageLength = strlen(message); struct Packet p; packet_init(&p, PACKET_CHAT, true, false); - packet_write(&p, rgb, 3 * sizeof(u8)); + packet_write(&p, &globalIndex, sizeof(u8)); packet_write(&p, &messageLength, sizeof(u16)); packet_write(&p, message, messageLength * sizeof(u8)); network_send(&p); @@ -45,16 +46,16 @@ void network_send_chat(char* message, u8 rgb[3]) { void network_receive_chat(struct Packet* p) { u16 remoteMessageLength = 0; - char remoteMessage[255] = { 0 }; - u8 rgb[3] = { 255, 255, 255}; + char remoteMessage[256] = { 0 }; + u8 globalIndex; - packet_read(p, rgb, 3 * sizeof(u8)); + packet_read(p, &globalIndex, sizeof(u8)); packet_read(p, &remoteMessageLength, sizeof(u16)); - if (remoteMessageLength > 255) { remoteMessageLength = 254; } + if (remoteMessageLength > 256) { remoteMessageLength = 255; } packet_read(p, &remoteMessage, remoteMessageLength * sizeof(u8)); // add the message - chat_add_message(remoteMessage); + djui_chat_message_create_from(globalIndex, remoteMessage); LOG_INFO("rx chat: %s", remoteMessage); /* #ifdef DEVELOPMENT diff --git a/src/pc/network/packets/packet_join.c b/src/pc/network/packets/packet_join.c index 9de84ee88..b444d4380 100644 --- a/src/pc/network/packets/packet_join.c +++ b/src/pc/network/packets/packet_join.c @@ -178,6 +178,7 @@ void network_receive_join(struct Packet* p) { network_player_connected(NPT_SERVER, 0); network_player_connected(NPT_LOCAL, myGlobalIndex); + djui_chat_box_create(); save_file_load_all(TRUE); diff --git a/src/pc/network/packets/packet_player.c b/src/pc/network/packets/packet_player.c index 369e1e7de..9d97a09f0 100644 --- a/src/pc/network/packets/packet_player.c +++ b/src/pc/network/packets/packet_player.c @@ -323,7 +323,7 @@ void network_receive_player(struct Packet* p) { // inform of player death if (oldData.action != ACT_BUBBLED && data.action == ACT_BUBBLED) { - chat_add_message("player died"); + //chat_add_message("player died"); } // action changed, reset timer