sm64coopdx/src/pc/djui/djui_console.c
2024-03-19 19:48:48 +10:00

199 lines
6.8 KiB
C

#include <stdio.h>
#include <string.h>
#include "djui.h"
#include "djui_console.h"
#include "pc/pc_main.h"
#define MAX_CONSOLE_MESSAGES 500
struct DjuiConsole* gDjuiConsole = NULL;
bool gDjuiConsoleFocus = false;
char gDjuiConsoleTmpBuffer[CONSOLE_MAX_TMP_BUFFER] = "";
u32 sDjuiConsoleMessages = 0;
bool sDjuiConsoleQueueMessages = true;
struct ConsoleQueuedMessage {
char* message;
enum ConsoleMessageLevel level;
struct ConsoleQueuedMessage* next;
};
struct ConsoleQueuedMessage* sConsoleQueuedMessages = NULL;
static void djui_console_message_queue(const char* message, enum ConsoleMessageLevel level) {
struct ConsoleQueuedMessage* queued = malloc(sizeof(struct ConsoleQueuedMessage));
queued->message = strdup(message);
queued->level = level;
queued->next = NULL;
if (sConsoleQueuedMessages == NULL) {
sConsoleQueuedMessages = queued;
return;
}
struct ConsoleQueuedMessage* entry = sConsoleQueuedMessages;
while (entry->next) { entry = entry->next; }
entry->next = queued;
}
void djui_console_message_dequeue(void) {
if (!gDjuiConsole) { return; }
sDjuiConsoleQueueMessages = false;
struct ConsoleQueuedMessage* entry = sConsoleQueuedMessages;
while (entry) {
struct ConsoleQueuedMessage* next = entry->next;
djui_console_message_create(entry->message, entry->level);
free(entry->message);
free(entry);
entry = next;
}
sConsoleQueuedMessages = NULL;
}
bool djui_console_render(struct DjuiBase* base) {
djui_base_set_size(base, gDjuiRoot->base.width.value, gDjuiRoot->base.height.value * 0.5f);
djui_rect_render(base);
return true;
}
static void djui_console_destroy(struct DjuiBase* base) {
struct DjuiConsole* console = (struct DjuiConsole*)base;
free(console);
}
void djui_console_toggle(void) {
if (gDjuiConsole == NULL) { return; }
gDjuiConsoleFocus = !gDjuiConsoleFocus;
djui_base_set_visible(&gDjuiConsole->base, gDjuiConsoleFocus);
if (gDjuiConsoleFocus) {
if (gDjuiChatBoxFocus) { djui_chat_box_toggle(); }
djui_interactable_set_input_focus(&gDjuiConsole->base);
} else {
djui_interactable_set_input_focus(NULL);
}
}
static bool djui_console_on_key_down(UNUSED struct DjuiBase* base, int scancode) {
if (gDjuiConsole == NULL) { return false; }
f32 yMax = gDjuiConsole->base.comp.height - gDjuiConsole->flow->base.height.value;
f32* yValue = &gDjuiConsole->flow->base.y.value;
bool canScrollUp = (*yValue > yMax);
bool canScrollDown = (*yValue < 0);
f32 pageAmount = gDjuiConsole->base.comp.height * 3.0f / 4.0f;
switch (scancode) {
case SCANCODE_UP:
if (canScrollUp) { *yValue = fmax(*yValue - 15, yMax); }
break;
case SCANCODE_DOWN:
if (canScrollDown) { *yValue = fmin(*yValue + 15, 0); }
break;
case SCANCODE_PAGE_UP:
if (canScrollUp) { *yValue = fmax(*yValue - pageAmount, yMax); }
break;
case SCANCODE_PAGE_DOWN:
if (canScrollDown) { *yValue = fmin(*yValue + pageAmount, 0); }
break;
case SCANCODE_ESCAPE: djui_console_toggle(); break;
default: break;
}
gDjuiConsole->scrolling = (*yValue != 0);
return true;
}
void djui_console_message_create(const char* message, enum ConsoleMessageLevel level) {
if (sDjuiConsoleQueueMessages || !gDjuiConsole) {
djui_console_message_queue(message, level);
return;
}
djui_base_compute_tree(&gDjuiConsole->base);
struct DjuiBase* cfBase = &gDjuiConsole->flow->base;
f32 maxTextWidth = gDjuiConsole->base.comp.width - gDjuiConsole->base.padding.left.value - gDjuiConsole->base.padding.right.value;
struct DjuiText* text = djui_text_create(cfBase, message);
struct DjuiBase* tBase = &text->base;
djui_base_set_alignment(tBase, DJUI_HALIGN_LEFT, DJUI_VALIGN_BOTTOM);
djui_base_set_size_type(tBase, DJUI_SVT_ABSOLUTE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(tBase, maxTextWidth, 32);
switch (level) {
case CONSOLE_MESSAGE_INFO:
djui_base_set_color(tBase, 220, 220, 220, 255);
break;
case CONSOLE_MESSAGE_WARNING:
djui_base_set_color(tBase, 255, 255, 160, 255);
break;
case CONSOLE_MESSAGE_ERROR:
djui_base_set_color(tBase, 255, 160, 160, 255);
break;
}
// figure out chat message height
text->base.comp.width = maxTextWidth;
f32 messageHeight = djui_text_count_lines(text, 10) * (text->font->lineHeight * text->font->defaultFontScale) + 8;
djui_base_set_size(tBase, maxTextWidth, messageHeight);
f32 heightAdjust = messageHeight + gDjuiConsole->flow->margin.value;
cfBase->height.value += heightAdjust;
if (gDjuiConsole->scrolling) {
cfBase->y.value -= heightAdjust;
}
sDjuiConsoleMessages++;
if (sDjuiConsoleMessages >= MAX_CONSOLE_MESSAGES) {
if (cfBase->child) {
heightAdjust = cfBase->child->base->height.value + gDjuiConsole->flow->margin.value;
cfBase->height.value -= heightAdjust;
if (gDjuiConsole->scrolling) {
cfBase->y.value += heightAdjust;
}
}
djui_base_destroy_one_child(cfBase);
sDjuiConsoleMessages--;
}
}
struct DjuiConsole* djui_console_create(void) {
if (gDjuiConsole != NULL) {
djui_base_destroy(&gDjuiConsole->base);
free(gDjuiConsole);
gDjuiConsole = NULL;
}
struct DjuiConsole* console = calloc(1, sizeof(struct DjuiConsole));
struct DjuiBase* base = &console->base;
djui_base_init(NULL, base, djui_console_render, djui_console_destroy);
djui_base_set_size_type(base, DJUI_SVT_ABSOLUTE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(base, gDjuiRoot->base.width.value, gDjuiRoot->base.height.value * 0.5f);
djui_base_set_alignment(base, DJUI_HALIGN_LEFT, DJUI_VALIGN_TOP);
djui_base_set_color(base, 0, 0, 0, 200);
djui_base_set_padding(base, 0, 8, 8, 8);
djui_base_set_visible(base, false);
djui_interactable_create(base, NULL);
djui_interactable_hook_key(base, djui_console_on_key_down, NULL);
struct DjuiFlowLayout* flow = djui_flow_layout_create(base);
struct DjuiBase* cfBase = &flow->base;
djui_base_set_alignment(cfBase, DJUI_HALIGN_LEFT, DJUI_VALIGN_BOTTOM);
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, 0);
djui_base_set_color(cfBase, 0, 0, 0, 0);
djui_base_set_padding(cfBase, 2, 2, 2, 2);
djui_flow_layout_set_margin(flow, 2);
djui_flow_layout_set_flow_direction(flow, DJUI_FLOW_DIR_UP);
cfBase->addChildrenToHead = true;
cfBase->abandonAfterChildRenderFail = true;
console->flow = flow;
gDjuiConsole = console;
return console;
}