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