CAO/SAO: Nicer velocity-controlled, interpolated rotation property:
[oweals/minetest.git] / src / chat.cpp
index 809d4e4225c6d803ab3ed7120024bd4e489cf362..a5d82a6494289938bc011d71a014909075327a0c 100644 (file)
@@ -19,30 +19,21 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #include "chat.h"
 #include "debug.h"
-#include "strfnd.h"
+#include "config.h"
+#include "util/strfnd.h"
 #include <cctype>
 #include <sstream>
 #include "util/string.h"
 #include "util/numeric.h"
 
 ChatBuffer::ChatBuffer(u32 scrollback):
-       m_scrollback(scrollback),
-       m_unformatted(),
-       m_cols(0),
-       m_rows(0),
-       m_scroll(0),
-       m_formatted(),
-       m_empty_formatted_line()
+       m_scrollback(scrollback)
 {
        if (m_scrollback == 0)
                m_scrollback = 1;
        m_empty_formatted_line.first = true;
 }
 
-ChatBuffer::~ChatBuffer()
-{
-}
-
 void ChatBuffer::addLine(std::wstring name, std::wstring text)
 {
        ChatLine line(name, text);
@@ -76,11 +67,6 @@ u32 ChatBuffer::getLineCount() const
        return m_unformatted.size();
 }
 
-u32 ChatBuffer::getScrollback() const
-{
-       return m_scrollback;
-}
-
 const ChatLine& ChatBuffer::getLine(u32 index) const
 {
        assert(index < getLineCount()); // pre-condition
@@ -89,14 +75,15 @@ const ChatLine& ChatBuffer::getLine(u32 index) const
 
 void ChatBuffer::step(f32 dtime)
 {
-       for (u32 i = 0; i < m_unformatted.size(); ++i)
-       {
-               m_unformatted[i].age += dtime;
+       for (ChatLine &line : m_unformatted) {
+               line.age += dtime;
        }
 }
 
 void ChatBuffer::deleteOldest(u32 count)
 {
+       bool at_bottom = (m_scroll == getBottomScrollPos());
+
        u32 del_unformatted = 0;
        u32 del_formatted = 0;
 
@@ -120,6 +107,11 @@ void ChatBuffer::deleteOldest(u32 count)
 
        m_unformatted.erase(m_unformatted.begin(), m_unformatted.begin() + del_unformatted);
        m_formatted.erase(m_formatted.begin(), m_formatted.begin() + del_formatted);
+
+       if (at_bottom)
+               m_scroll = getBottomScrollPos();
+       else
+               scrollAbsolute(m_scroll - del_formatted);
 }
 
 void ChatBuffer::deleteByAge(f32 maxAge)
@@ -201,8 +193,8 @@ const ChatFormattedLine& ChatBuffer::getFormattedLine(u32 row) const
        s32 index = m_scroll + (s32) row;
        if (index >= 0 && index < (s32) m_formatted.size())
                return m_formatted[index];
-       else
-               return m_empty_formatted_line;
+
+       return m_empty_formatted_line;
 }
 
 void ChatBuffer::scroll(s32 rows)
@@ -244,8 +236,7 @@ u32 ChatBuffer::formatChatLine(const ChatLine& line, u32 cols,
        u32 hanging_indentation = 0;
 
        // Format the sender name and produce fragments
-       if (!line.name.empty())
-       {
+       if (!line.name.empty()) {
                temp_frag.text = L"<";
                temp_frag.column = 0;
                //temp_frag.bold = 0;
@@ -260,22 +251,20 @@ u32 ChatBuffer::formatChatLine(const ChatLine& line, u32 cols,
                next_frags.push_back(temp_frag);
        }
 
+       std::wstring name_sanitized = line.name.c_str();
+
        // Choose an indentation level
-       if (line.name.empty())
-       {
+       if (line.name.empty()) {
                // Server messages
                hanging_indentation = 0;
-       }
-       else if (line.name.size() + 3 <= cols/2)
-       {
+       } else if (name_sanitized.size() + 3 <= cols/2) {
                // Names shorter than about half the console width
                hanging_indentation = line.name.size() + 3;
-       }
-       else
-       {
+       } else {
                // Very long names
                hanging_indentation = 2;
        }
+       //EnrichedString line_text(line.text);
 
        next_line.first = true;
        bool text_processing = false;
@@ -331,7 +320,7 @@ u32 ChatBuffer::formatChatLine(const ChatLine& line, u32 cols,
                        while (frag_length < remaining_in_input &&
                                        frag_length < remaining_in_output)
                        {
-                               if (isspace(line.text[in_pos + frag_length]))
+                               if (iswspace(line.text.getString()[in_pos + frag_length]))
                                        space_pos = frag_length;
                                ++frag_length;
                        }
@@ -363,10 +352,11 @@ s32 ChatBuffer::getTopScrollPos() const
        s32 rows = (s32) m_rows;
        if (rows == 0)
                return 0;
-       else if (formatted_count <= rows)
+
+       if (formatted_count <= rows)
                return formatted_count - rows;
-       else
-               return 0;
+
+       return 0;
 }
 
 s32 ChatBuffer::getBottomScrollPos() const
@@ -375,28 +365,21 @@ s32 ChatBuffer::getBottomScrollPos() const
        s32 rows = (s32) m_rows;
        if (rows == 0)
                return 0;
-       else
-               return formatted_count - rows;
-}
-
 
+       return formatted_count - rows;
+}
 
-ChatPrompt::ChatPrompt(std::wstring prompt, u32 history_limit):
-       m_prompt(prompt),
-       m_line(L""),
-       m_history(),
-       m_history_index(0),
-       m_history_limit(history_limit),
-       m_cols(0),
-       m_view(0),
-       m_cursor(0),
-       m_cursor_len(0),
-       m_nick_completion_start(0),
-       m_nick_completion_end(0)
+void ChatBuffer::resize(u32 scrollback)
 {
+       m_scrollback = scrollback;
+       if (m_unformatted.size() > m_scrollback)
+               deleteOldest(m_unformatted.size() - m_scrollback);
 }
 
-ChatPrompt::~ChatPrompt()
+
+ChatPrompt::ChatPrompt(const std::wstring &prompt, u32 history_limit):
+       m_prompt(prompt),
+       m_history_limit(history_limit)
 {
 }
 
@@ -488,9 +471,9 @@ void ChatPrompt::nickCompletion(const std::list<std::string>& names, bool backwa
        {
                // no previous nick completion is active
                prefix_start = prefix_end = m_cursor;
-               while (prefix_start > 0 && !isspace(m_line[prefix_start-1]))
+               while (prefix_start > 0 && !iswspace(m_line[prefix_start-1]))
                        --prefix_start;
-               while (prefix_end < m_line.size() && !isspace(m_line[prefix_end]))
+               while (prefix_end < m_line.size() && !iswspace(m_line[prefix_end]))
                        ++prefix_end;
                if (prefix_start == prefix_end)
                        return;
@@ -499,18 +482,15 @@ void ChatPrompt::nickCompletion(const std::list<std::string>& names, bool backwa
 
        // find all names that start with the selected prefix
        std::vector<std::wstring> completions;
-       for (std::list<std::string>::const_iterator
-                       i = names.begin();
-                       i != names.end(); ++i)
-       {
-               if (str_starts_with(narrow_to_wide(*i), prefix, true))
-               {
-                       std::wstring completion = narrow_to_wide(*i);
+       for (const std::string &name : names) {
+               if (str_starts_with(narrow_to_wide(name), prefix, true)) {
+                       std::wstring completion = narrow_to_wide(name);
                        if (prefix_start == 0)
                                completion += L": ";
                        completions.push_back(completion);
                }
        }
+
        if (completions.empty())
                return;
 
@@ -519,7 +499,7 @@ void ChatPrompt::nickCompletion(const std::list<std::string>& names, bool backwa
        u32 replacement_index = 0;
        if (!initial)
        {
-               while (word_end < m_line.size() && !isspace(m_line[word_end]))
+               while (word_end < m_line.size() && !iswspace(m_line[word_end]))
                        ++word_end;
                std::wstring word = m_line.substr(prefix_start, word_end - prefix_start);
 
@@ -538,7 +518,7 @@ void ChatPrompt::nickCompletion(const std::list<std::string>& names, bool backwa
                }
        }
        std::wstring replacement = completions[replacement_index];
-       if (word_end < m_line.size() && isspace(word_end))
+       if (word_end < m_line.size() && iswspace(m_line[word_end]))
                ++word_end;
 
        // replace existing word with replacement word,
@@ -593,17 +573,17 @@ void ChatPrompt::cursorOperation(CursorOp op, CursorOpDir dir, CursorOpScope sco
        case CURSOROP_SCOPE_WORD:
                if (dir == CURSOROP_DIR_RIGHT) {
                        // skip one word to the right
-                       while (new_cursor < length && isspace(m_line[new_cursor]))
+                       while (new_cursor < length && iswspace(m_line[new_cursor]))
                                new_cursor++;
-                       while (new_cursor < length && !isspace(m_line[new_cursor]))
+                       while (new_cursor < length && !iswspace(m_line[new_cursor]))
                                new_cursor++;
-                       while (new_cursor < length && isspace(m_line[new_cursor]))
+                       while (new_cursor < length && iswspace(m_line[new_cursor]))
                                new_cursor++;
                } else {
                        // skip one word to the left
-                       while (new_cursor >= 1 && isspace(m_line[new_cursor - 1]))
+                       while (new_cursor >= 1 && iswspace(m_line[new_cursor - 1]))
                                new_cursor--;
-                       while (new_cursor >= 1 && !isspace(m_line[new_cursor - 1]))
+                       while (new_cursor >= 1 && !iswspace(m_line[new_cursor - 1]))
                                new_cursor--;
                }
                break;
@@ -673,15 +653,12 @@ ChatBackend::ChatBackend():
 {
 }
 
-ChatBackend::~ChatBackend()
-{
-}
-
 void ChatBackend::addMessage(std::wstring name, std::wstring text)
 {
        // Note: A message may consist of multiple lines, for example the MOTD.
+       text = translate_string(text);
        WStrfnd fnd(text);
-       while (!fnd.atend())
+       while (!fnd.at_end())
        {
                std::wstring line = fnd.next(L"\n");
                m_console_buffer.addLine(name, line);
@@ -722,19 +699,22 @@ ChatBuffer& ChatBackend::getRecentBuffer()
        return m_recent_buffer;
 }
 
-std::wstring ChatBackend::getRecentChat()
+EnrichedString ChatBackend::getRecentChat()
 {
-       std::wostringstream stream;
+       EnrichedString result;
        for (u32 i = 0; i < m_recent_buffer.getLineCount(); ++i)
        {
                const ChatLine& line = m_recent_buffer.getLine(i);
                if (i != 0)
-                       stream << L"\n";
-               if (!line.name.empty())
-                       stream << L"<" << line.name << L"> ";
-               stream << line.text;
+                       result += L"\n";
+               if (!line.name.empty()) {
+                       result += L"<";
+                       result += line.name;
+                       result += L"> ";
+               }
+               result += line.text;
        }
-       return stream.str();
+       return result;
 }
 
 ChatPrompt& ChatBackend::getPrompt()
@@ -757,6 +737,14 @@ void ChatBackend::clearRecentChat()
        m_recent_buffer.clear();
 }
 
+
+void ChatBackend::applySettings()
+{
+       u32 recent_lines = g_settings->getU32("recent_chat_messages");
+       recent_lines = rangelim(recent_lines, 2, 20);
+       m_recent_buffer.resize(recent_lines);
+}
+
 void ChatBackend::step(float dtime)
 {
        m_recent_buffer.step(dtime);