From 64b5bb64dc2fb204329daf009bd34edc8d0a0102 Mon Sep 17 00:00:00 2001 From: TimePath Date: Sat, 7 Apr 2018 14:40:28 +1000 Subject: [PATCH] Chat: add dialog --- qcsrc/lib/string.qh | 7 +++ qcsrc/lib/vector.qh | 13 ++--- qcsrc/menu/modules/chat/_mod.inc | 2 + qcsrc/menu/modules/chat/_mod.qh | 2 + qcsrc/menu/modules/chat/commands.qc | 83 ++++++++++++++++++++++++++--- qcsrc/menu/modules/chat/dialog.qc | 77 ++++++++++++++++++++++++++ qcsrc/menu/modules/chat/dialog.qh | 16 ++++++ qcsrc/menu/modules/chat/state.qc | 20 +++++++ qcsrc/menu/modules/chat/state.qh | 10 ++++ qcsrc/menu/xonotic/mainwindow.qc | 4 ++ 10 files changed, 220 insertions(+), 14 deletions(-) create mode 100644 qcsrc/menu/modules/chat/dialog.qc create mode 100644 qcsrc/menu/modules/chat/dialog.qh create mode 100644 qcsrc/menu/modules/chat/state.qc create mode 100644 qcsrc/menu/modules/chat/state.qh diff --git a/qcsrc/lib/string.qh b/qcsrc/lib/string.qh index 812eb72c8..d79552187 100644 --- a/qcsrc/lib/string.qh +++ b/qcsrc/lib/string.qh @@ -27,6 +27,13 @@ } #endif +#define strcpy(this, s) MACRO_BEGIN \ + if (this) { \ + strunzone(this); \ + } \ + this = strzone(s); \ +MACRO_END + ERASEABLE string seconds_tostring(float sec) { diff --git a/qcsrc/lib/vector.qh b/qcsrc/lib/vector.qh index 8340381ba..6e622b416 100644 --- a/qcsrc/lib/vector.qh +++ b/qcsrc/lib/vector.qh @@ -104,13 +104,14 @@ float boxinsidebox(vector smins, vector smaxs, vector bmins, vector bmaxs) { ret // vector vec2(vector v); // returns a vector with just the x and y components of the given vector // vector vec2(float x, float y); // returns a vector with the given x and y components -noref vector _vec2; -#define vec2(...) EVAL(OVERLOAD(vec2, __VA_ARGS__)) -#define vec2_1(v) (_vec2 = (v), _vec2.z = 0, _vec2) -#define vec2_2(x, y) (_vec2_x = (x), _vec2_y = (y), _vec2) +noref vector _vec_zero; +noref vector _vec2_tmp; +noref vector _vec3_tmp; -noref vector _vec3; -#define vec3(_x, _y, _z) (_vec3.x = (_x), _vec3.y = (_y), _vec3.z = (_z), _vec3) +#define vec2(...) EVAL(OVERLOAD(vec2, __VA_ARGS__)) +#define vec2_1(v) (_vec2_tmp = (v), _vec2_tmp.z = 0, _vec2_tmp + _vec_zero) +#define vec2_2(_x, _y) (_vec2_tmp.x = (_x), _vec2_tmp.y = (_y), _vec2_tmp + _vec_zero) +#define vec3(_x, _y, _z) (_vec3_tmp.x = (_x), _vec3_tmp.y = (_y), _vec3_tmp.z = (_z), _vec3_tmp + _vec_zero) ERASEABLE vector Rotate(vector v, float a) diff --git a/qcsrc/menu/modules/chat/_mod.inc b/qcsrc/menu/modules/chat/_mod.inc index b8c8810be..fc162caa2 100644 --- a/qcsrc/menu/modules/chat/_mod.inc +++ b/qcsrc/menu/modules/chat/_mod.inc @@ -1,2 +1,4 @@ // generated file; do not modify #include +#include +#include diff --git a/qcsrc/menu/modules/chat/_mod.qh b/qcsrc/menu/modules/chat/_mod.qh index 8eaea0a7a..85fa89b1b 100644 --- a/qcsrc/menu/modules/chat/_mod.qh +++ b/qcsrc/menu/modules/chat/_mod.qh @@ -1,2 +1,4 @@ // generated file; do not modify #include +#include +#include diff --git a/qcsrc/menu/modules/chat/commands.qc b/qcsrc/menu/modules/chat/commands.qc index 668ff651d..5e4c052a1 100644 --- a/qcsrc/menu/modules/chat/commands.qc +++ b/qcsrc/menu/modules/chat/commands.qc @@ -2,14 +2,9 @@ #include -noref string autocvar__cl_hook_print = "menu_cmd notice"; - -int notice_buffer; -int notice_buffer_idx; +#include "state.qh" -STATIC_INIT(notice_buffer) { - notice_buffer = buf_create(); -} +noref string autocvar__cl_hook_print = "menu_cmd notice"; GENERIC_COMMAND(notice, "Append a notice to chat") { @@ -25,7 +20,7 @@ GENERIC_COMMAND(notice, "Append a notice to chat") entity snd = (flags & NOTICE_PRIVATE) ? SND_TALK2 : SND_TALK; localsound(Sound_fixpath(snd)); } - bufstr_set(notice_buffer, notice_buffer_idx++, s); + chat_lines_push(s); print(prefix, "^7", s, "\n"); return; } @@ -39,3 +34,75 @@ GENERIC_COMMAND(notice, "Append a notice to chat") } } } + +GENERIC_COMMAND(commandmode, "input a console command") +{ + switch(request) + { + case CMD_REQUEST_COMMAND: + { + string prefix = arguments > 1 ? strcat(substring(command, argv_start_index(1), argv_end_index(-1)), " ") : ""; + chat_command = ""; + strcpy(chat_text, prefix); + if (!isdemo()) { + m_goto("Chat"); + } + return; + } + + default: + case CMD_REQUEST_USAGE: + { + LOG_INFO("Usage:^3 ", GetProgramCommandPrefix(), " commandmode [prefix]"); + return; + } + } +} + +GENERIC_COMMAND(messagemode, "input a chat message to say to everyone") +{ + switch(request) + { + case CMD_REQUEST_COMMAND: + { + string prefix = arguments > 1 ? strcat(substring(command, argv_start_index(1), argv_end_index(-1)), " ") : ""; + chat_command = "say "; + strcpy(chat_text, prefix); + if (!isdemo()) { + m_goto("Chat"); + } + return; + } + + default: + case CMD_REQUEST_USAGE: + { + LOG_INFO("Usage:^3 ", GetProgramCommandPrefix(), " messagemode [prefix]"); + return; + } + } +} + +GENERIC_COMMAND(messagemode2, "input a chat message to say to only your team") +{ + switch(request) + { + case CMD_REQUEST_COMMAND: + { + string prefix = arguments > 1 ? strcat(substring(command, argv_start_index(1), argv_end_index(-1)), " ") : ""; + chat_command = "say_team "; + strcpy(chat_text, prefix); + if (!isdemo()) { + m_goto("Chat"); + } + return; + } + + default: + case CMD_REQUEST_USAGE: + { + LOG_INFO("Usage:^3 ", GetProgramCommandPrefix(), " messagemode2 [prefix]"); + return; + } + } +} diff --git a/qcsrc/menu/modules/chat/dialog.qc b/qcsrc/menu/modules/chat/dialog.qc new file mode 100644 index 000000000..681a698f8 --- /dev/null +++ b/qcsrc/menu/modules/chat/dialog.qc @@ -0,0 +1,77 @@ +#include "dialog.qh" + +#include + +CLASS(XonoticChatList, XonoticListBox) + ATTRIB(XonoticChatList, rowsPerItem, int, 1); + ATTRIB(XonoticChatList, realFontSize, vector); + ATTRIB(XonoticChatList, autoscroll, int); + ATTRIB(XonoticChatList, inputbox, XonoticInputBox); + + METHOD(XonoticChatList, showNotify, void(XonoticChatList this)); + METHOD(XonoticChatList, resizeNotify, void(XonoticChatList this, vector, vector, vector, vector)); + METHOD(XonoticChatList, draw, void(XonoticChatList this)); + METHOD(XonoticChatList, drawListBoxItem, void(XonoticChatList this, int, vector, bool, bool)); +ENDCLASS(XonoticChatList) + +void XonoticChatDialog_onEnter(XonoticInputBox this, XonoticChatDialog data) +{ + entity e = this; + localcmd("\n", chat_command, e.text, "\n"); + e.setText(e, chat_text); + e.cursorPos = strlen(chat_text); +} + +METHOD(XonoticChatDialog, fill, void(XonoticChatDialog this)) +{ + entity list = NEW(XonoticChatList);; + list.configureXonoticListBox(list); + this.TR(this); + { + this.TD(this, this.rows - 1, this.columns, list); + } + this.gotoRC(this, this.rows - 1, 0); + { + entity e = list.inputbox = NEW(XonoticInputBox); + e.configureXonoticInputBox(e, true, string_null, ""); + e.onEnter = XonoticChatDialog_onEnter; + e.onEnterEntity = this; + e.preferredFocusPriority = true; + this.TD(this, 1, this.columns, e); + } +} + +METHOD(XonoticChatList, showNotify, void(XonoticChatList this)) +{ + this.autoscroll = 1; + entity e = this.inputbox; + e.setText(e, chat_text); + e.cursorPos = strlen(chat_text); +} + +METHOD(XonoticChatList, resizeNotify, void(XonoticChatList this, vector relOrigin, vector relSize, vector absOrigin, vector absSize)) +{ + SUPER(XonoticChatList).resizeNotify(this, relOrigin, relSize, absOrigin, absSize); + + this.realFontSize_y = this.fontSize / (absSize.y * this.itemHeight); + this.realFontSize_x = this.fontSize / (absSize.x * (1 - this.controlWidth)); +} + +METHOD(XonoticChatList, draw, void(XonoticChatList this)) +{ + int prevCount = this.nItems; + this.nItems = chat_lines_count(); + if (this.autoscroll && prevCount != this.nItems) { + this.scrollToItem(this, this.nItems - 1); + if (this.autoscroll == 1) { + this.autoscroll = 0; + } + } + SUPER(XonoticChatList).draw(this); +} + +METHOD(XonoticChatList, drawListBoxItem, void(XonoticChatList this, int i, vector absSize, bool isSelected, bool isFocused)) +{ + string s = chat_lines_get(i); + draw_Text(vec2(0, 0), s, this.realFontSize, '1 1 1', 1, true); +} diff --git a/qcsrc/menu/modules/chat/dialog.qh b/qcsrc/menu/modules/chat/dialog.qh new file mode 100644 index 000000000..fd13c5051 --- /dev/null +++ b/qcsrc/menu/modules/chat/dialog.qh @@ -0,0 +1,16 @@ +#pragma once + +#include + +CLASS(XonoticChatDialog, XonoticRootDialog) + ATTRIB(XonoticChatDialog, name, string, "Chat"); + ATTRIB(XonoticChatDialog, requiresConnection, bool, true); + + ATTRIB(XonoticChatDialog, title, string, _("Chat")); + ATTRIB(XonoticChatDialog, color, vector, '1 1 1'); + ATTRIB(XonoticChatDialog, intendedWidth, float, 0.5); + ATTRIB(XonoticChatDialog, rows, float, 5); + ATTRIB(XonoticChatDialog, columns, float, 4); + + METHOD(XonoticChatDialog, fill, void(entity)); +ENDCLASS(XonoticChatDialog) diff --git a/qcsrc/menu/modules/chat/state.qc b/qcsrc/menu/modules/chat/state.qc new file mode 100644 index 000000000..299efbdb5 --- /dev/null +++ b/qcsrc/menu/modules/chat/state.qc @@ -0,0 +1,20 @@ +#include "state.qh" + +int chat_buffer; +int chat_buffer_idx; + +STATIC_INIT(chat_buffer) { + chat_buffer = buf_create(); +} + +int chat_lines_count() { + return chat_buffer_idx + 1; +} + +string chat_lines_get(int i) { + return bufstr_get(chat_buffer, i); +} + +void chat_lines_push(string s) { + bufstr_set(chat_buffer, chat_buffer_idx++, s); +} diff --git a/qcsrc/menu/modules/chat/state.qh b/qcsrc/menu/modules/chat/state.qh new file mode 100644 index 000000000..9ca190389 --- /dev/null +++ b/qcsrc/menu/modules/chat/state.qh @@ -0,0 +1,10 @@ +#pragma once + +string chat_command; +string chat_text; + +int chat_lines_count(); + +string chat_lines_get(int i); + +void chat_lines_push(string s); diff --git a/qcsrc/menu/xonotic/mainwindow.qc b/qcsrc/menu/xonotic/mainwindow.qc index 0afd27c8d..ef1f011fb 100644 --- a/qcsrc/menu/xonotic/mainwindow.qc +++ b/qcsrc/menu/xonotic/mainwindow.qc @@ -235,6 +235,10 @@ void MainWindow_configureMainWindow(entity me) i.configureDialog(i); me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z * SKINALPHA_DIALOG_SANDBOXTOOLS); + i = NEW(XonoticChatDialog); + i.configureDialog(i); + me.addItem(me, i, vec2(0, 1 - i.intendedHeight), vec2(i.intendedWidth, i.intendedHeight), SKINALPHAS_MAINMENU_z); + MUTATOR_CALLHOOK(ConfigureDialogs, me); -- 2.39.2