chat.h 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. /*
  2. Minetest
  3. Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as published by
  6. the Free Software Foundation; either version 2.1 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License along
  13. with this program; if not, write to the Free Software Foundation, Inc.,
  14. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. */
  16. #pragma once
  17. #include <string>
  18. #include <vector>
  19. #include <list>
  20. #include "irrlichttypes.h"
  21. #include "util/enriched_string.h"
  22. #include "settings.h"
  23. // Chat console related classes
  24. struct ChatLine
  25. {
  26. // age in seconds
  27. f32 age = 0.0f;
  28. // name of sending player, or empty if sent by server
  29. EnrichedString name;
  30. // message text
  31. EnrichedString text;
  32. ChatLine(const std::wstring &a_name, const std::wstring &a_text):
  33. name(a_name),
  34. text(a_text)
  35. {
  36. }
  37. ChatLine(const EnrichedString &a_name, const EnrichedString &a_text):
  38. name(a_name),
  39. text(a_text)
  40. {
  41. }
  42. };
  43. struct ChatFormattedFragment
  44. {
  45. // text string
  46. EnrichedString text;
  47. // starting column
  48. u32 column;
  49. // web link is empty for most frags
  50. std::string weblink;
  51. // formatting
  52. //u8 bold:1;
  53. };
  54. struct ChatFormattedLine
  55. {
  56. // Array of text fragments
  57. std::vector<ChatFormattedFragment> fragments;
  58. // true if first line of one formatted ChatLine
  59. bool first;
  60. };
  61. class ChatBuffer
  62. {
  63. public:
  64. ChatBuffer(u32 scrollback);
  65. ~ChatBuffer() = default;
  66. // Append chat line
  67. // Removes oldest chat line if scrollback size is reached
  68. void addLine(const std::wstring &name, const std::wstring &text);
  69. // Remove all chat lines
  70. void clear();
  71. // Get number of lines currently in buffer.
  72. u32 getLineCount() const;
  73. // Get reference to i-th chat line.
  74. const ChatLine& getLine(u32 index) const;
  75. // Increase each chat line's age by dtime.
  76. void step(f32 dtime);
  77. // Delete oldest N chat lines.
  78. void deleteOldest(u32 count);
  79. // Delete lines older than maxAge.
  80. void deleteByAge(f32 maxAge);
  81. // Get number of rows, 0 if reformat has not been called yet.
  82. u32 getRows() const;
  83. // Update console size and reformat all formatted lines.
  84. void reformat(u32 cols, u32 rows);
  85. // Get formatted line for a given row (0 is top of screen).
  86. // Only valid after reformat has been called at least once
  87. const ChatFormattedLine& getFormattedLine(u32 row) const;
  88. // Scrolling in formatted buffer (relative)
  89. // positive rows == scroll up, negative rows == scroll down
  90. void scroll(s32 rows);
  91. // Scrolling in formatted buffer (absolute)
  92. void scrollAbsolute(s32 scroll);
  93. // Scroll to bottom of buffer (newest)
  94. void scrollBottom();
  95. // Functions for keeping track of whether the lines were modified by any
  96. // preceding operations
  97. // If they were not changed, getLineCount() and getLine() output the same as
  98. // before
  99. bool getLinesModified() const { return m_lines_modified; }
  100. void resetLinesModified() { m_lines_modified = false; }
  101. // Format a chat line for the given number of columns.
  102. // Appends the formatted lines to the destination array and
  103. // returns the number of formatted lines.
  104. u32 formatChatLine(const ChatLine& line, u32 cols,
  105. std::vector<ChatFormattedLine>& destination) const;
  106. void resize(u32 scrollback);
  107. protected:
  108. s32 getTopScrollPos() const;
  109. s32 getBottomScrollPos() const;
  110. private:
  111. // Scrollback size
  112. u32 m_scrollback;
  113. // Array of unformatted chat lines
  114. std::vector<ChatLine> m_unformatted;
  115. // Number of character columns in console
  116. u32 m_cols = 0;
  117. // Number of character rows in console
  118. u32 m_rows = 0;
  119. // Scroll position (console's top line index into m_formatted)
  120. s32 m_scroll = 0;
  121. // Array of formatted lines
  122. std::vector<ChatFormattedLine> m_formatted;
  123. // Empty formatted line, for error returns
  124. ChatFormattedLine m_empty_formatted_line;
  125. // Enable clickable chat weblinks
  126. bool m_cache_clickable_chat_weblinks;
  127. // Color of clickable chat weblinks
  128. irr::video::SColor m_cache_chat_weblink_color;
  129. // Whether the lines were modified since last markLinesUnchanged()
  130. // Is always set to true when m_unformatted is modified, because that's what
  131. // determines the output of getLineCount() and getLine()
  132. bool m_lines_modified = true;
  133. };
  134. class ChatPrompt
  135. {
  136. public:
  137. ChatPrompt(const std::wstring &prompt, u32 history_limit);
  138. ~ChatPrompt() = default;
  139. // Input character or string
  140. void input(wchar_t ch);
  141. void input(const std::wstring &str);
  142. // Add a string to the history
  143. void addToHistory(const std::wstring &line);
  144. // Get current line
  145. std::wstring getLine() const { return m_line; }
  146. // Get section of line that is currently selected
  147. std::wstring getSelection() const { return m_line.substr(m_cursor, m_cursor_len); }
  148. // Clear the current line
  149. void clear();
  150. // Replace the current line with the given text
  151. std::wstring replace(const std::wstring &line);
  152. // Select previous command from history
  153. void historyPrev();
  154. // Select next command from history
  155. void historyNext();
  156. // Nick completion
  157. void nickCompletion(const std::list<std::string>& names, bool backwards);
  158. // Update console size and reformat the visible portion of the prompt
  159. void reformat(u32 cols);
  160. // Get visible portion of the prompt.
  161. std::wstring getVisiblePortion() const;
  162. // Get cursor position (relative to visible portion). -1 if invalid
  163. s32 getVisibleCursorPosition() const;
  164. // Get length of cursor selection
  165. s32 getCursorLength() const { return m_cursor_len; }
  166. // Cursor operations
  167. enum CursorOp {
  168. CURSOROP_MOVE,
  169. CURSOROP_SELECT,
  170. CURSOROP_DELETE
  171. };
  172. // Cursor operation direction
  173. enum CursorOpDir {
  174. CURSOROP_DIR_LEFT,
  175. CURSOROP_DIR_RIGHT
  176. };
  177. // Cursor operation scope
  178. enum CursorOpScope {
  179. CURSOROP_SCOPE_CHARACTER,
  180. CURSOROP_SCOPE_WORD,
  181. CURSOROP_SCOPE_LINE,
  182. CURSOROP_SCOPE_SELECTION
  183. };
  184. // Cursor operation
  185. // op specifies whether it's a move or delete operation
  186. // dir specifies whether the operation goes left or right
  187. // scope specifies how far the operation will reach (char/word/line)
  188. // Examples:
  189. // cursorOperation(CURSOROP_MOVE, CURSOROP_DIR_RIGHT, CURSOROP_SCOPE_LINE)
  190. // moves the cursor to the end of the line.
  191. // cursorOperation(CURSOROP_DELETE, CURSOROP_DIR_LEFT, CURSOROP_SCOPE_WORD)
  192. // deletes the word to the left of the cursor.
  193. void cursorOperation(CursorOp op, CursorOpDir dir, CursorOpScope scope);
  194. protected:
  195. // set m_view to ensure that 0 <= m_view <= m_cursor < m_view + m_cols
  196. // if line can be fully shown, set m_view to zero
  197. // else, also ensure m_view <= m_line.size() + 1 - m_cols
  198. void clampView();
  199. private:
  200. // Prompt prefix
  201. std::wstring m_prompt = L"";
  202. // Currently edited line
  203. std::wstring m_line = L"";
  204. // History buffer
  205. std::vector<std::wstring> m_history;
  206. // History index (0 <= m_history_index <= m_history.size())
  207. u32 m_history_index = 0;
  208. // Maximum number of history entries
  209. u32 m_history_limit;
  210. // Number of columns excluding columns reserved for the prompt
  211. s32 m_cols = 0;
  212. // Start of visible portion (index into m_line)
  213. s32 m_view = 0;
  214. // Cursor (index into m_line)
  215. s32 m_cursor = 0;
  216. // Cursor length (length of selected portion of line)
  217. s32 m_cursor_len = 0;
  218. // Last nick completion start (index into m_line)
  219. s32 m_nick_completion_start = 0;
  220. // Last nick completion start (index into m_line)
  221. s32 m_nick_completion_end = 0;
  222. };
  223. class ChatBackend
  224. {
  225. public:
  226. ChatBackend();
  227. ~ChatBackend() = default;
  228. // Add chat message
  229. void addMessage(const std::wstring &name, std::wstring text);
  230. // Parse and add unparsed chat message
  231. void addUnparsedMessage(std::wstring line);
  232. // Get the console buffer
  233. ChatBuffer& getConsoleBuffer();
  234. // Get the recent messages buffer
  235. ChatBuffer& getRecentBuffer();
  236. // Concatenate all recent messages
  237. EnrichedString getRecentChat() const;
  238. // Get the console prompt
  239. ChatPrompt& getPrompt();
  240. // Reformat all buffers
  241. void reformat(u32 cols, u32 rows);
  242. // Clear all recent messages
  243. void clearRecentChat();
  244. // Age recent messages
  245. void step(float dtime);
  246. // Scrolling
  247. void scroll(s32 rows);
  248. void scrollPageDown();
  249. void scrollPageUp();
  250. // Resize recent buffer based on settings
  251. void applySettings();
  252. private:
  253. ChatBuffer m_console_buffer;
  254. ChatBuffer m_recent_buffer;
  255. ChatPrompt m_prompt;
  256. };