diff --git a/include/aoapplication.h b/include/aoapplication.h index f4685ec..b44c8a8 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -213,6 +213,15 @@ public: // or downwards (vanilla behaviour). bool get_log_goes_downwards(); + // Returns whether the log should separate name from text via newline or : + bool get_log_newline(); + + // Get spacing between IC log entries. + int get_log_margin(); + + // Returns whether the log should have a timestamp. + bool get_log_timestamp(); + // Returns the username the user may have set in config.ini. QString get_default_username(); diff --git a/include/aooptionsdialog.h b/include/aooptionsdialog.h index 2b8c879..fe99626 100644 --- a/include/aooptionsdialog.h +++ b/include/aooptionsdialog.h @@ -46,6 +46,12 @@ private: QCheckBox *ui_downwards_cb; QLabel *ui_length_lbl; QSpinBox *ui_length_spinbox; + QLabel *ui_log_newline_lbl; + QCheckBox *ui_log_newline_cb; + QLabel *ui_log_margin_lbl; + QSpinBox *ui_log_margin_spinbox; + QLabel *ui_log_timestamp_lbl; + QCheckBox *ui_log_timestamp_cb; QFrame *ui_log_names_divider; QLineEdit *ui_username_textbox; QLabel *ui_username_lbl; diff --git a/include/chatlogpiece.h b/include/chatlogpiece.h index 14d4b34..da78d0d 100644 --- a/include/chatlogpiece.h +++ b/include/chatlogpiece.h @@ -10,14 +10,14 @@ class chatlogpiece { public: chatlogpiece(); chatlogpiece(QString p_name, QString p_showname, QString p_message, - bool p_song,int color); + QString p_action,int color); chatlogpiece(QString p_name, QString p_showname, QString p_message, - bool p_song, int color, QDateTime p_datetime); + QString p_action, int color, QDateTime p_datetime); QString get_name(); QString get_showname(); QString get_message(); - bool is_song(); + QString get_action(); QDateTime get_datetime(); QString get_datetime_as_string(); int get_chat_color(); @@ -27,9 +27,9 @@ private: QString name; QString showname; QString message; + QString action; QDateTime datetime; int color; - bool p_is_song; }; #endif // CHATLOGPIECE_H diff --git a/include/courtroom.h b/include/courtroom.h index df75cce..979650a 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -218,6 +218,8 @@ public: QString filter_ic_text(QString p_text, bool colorize = false, int pos = -1, int default_color = 0); + void log_ic_text(QString p_name, QString p_showname, QString p_message, QString p_action="", int p_color=0); + // adds text to the IC chatlog. p_name first as bold then p_text then a newlin // this function keeps the chatlog scrolled to the top unless there's text // selected @@ -262,7 +264,6 @@ private: int m_viewport_width = 256; int m_viewport_height = 192; - bool first_message_sent = false; int maximumMessages = 0; QParallelAnimationGroup *screenshake_animation_group = @@ -319,7 +320,19 @@ private: int log_maximum_blocks = 0; // True, if the log should go downwards. - bool log_goes_downwards = false; + bool log_goes_downwards = true; + + // True, if log should display colors. + bool log_colors = true; + + // True, if the log should display the message like name
text instead of name: text + bool log_newline = false; + + // Margin in pixels between log entries for the IC log. + int log_margin = 0; + + // True, if the log should have a timestamp. + bool log_timestamp = false; // delay before chat messages starts ticking QTimer *text_delay_timer; @@ -649,6 +662,8 @@ private: void reset_ic(); void reset_ui(); + + void regenerate_ic_chatlog(); public slots: void objection_done(); void preanim_done(); diff --git a/src/aooptionsdialog.cpp b/src/aooptionsdialog.cpp index 6cedee8..4e6aca6 100644 --- a/src/aooptionsdialog.cpp +++ b/src/aooptionsdialog.cpp @@ -120,6 +120,49 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_length_spinbox); + row += 1; + ui_log_newline_lbl = new QLabel(ui_form_layout_widget); + ui_log_newline_lbl->setText(tr("Log newline:")); + ui_log_newline_lbl->setToolTip( + tr("If ticked, new messages will appear separated, " + "with the message coming on the next line after the name. " + "When unticked, it displays it as 'name: message'.")); + + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_log_newline_lbl); + + ui_log_newline_cb = new QCheckBox(ui_form_layout_widget); + ui_log_newline_cb->setChecked(p_ao_app->get_log_newline()); + + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_log_newline_cb); + + row += 1; + ui_log_margin_lbl = new QLabel(ui_form_layout_widget); + ui_log_margin_lbl->setText(tr("Log margin:")); + ui_log_margin_lbl->setToolTip(tr( + "The distance in pixels between each entry in the IC log. " + "Default: 0.")); + + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_log_margin_lbl); + + ui_log_margin_spinbox = new QSpinBox(ui_form_layout_widget); + ui_log_margin_spinbox->setMaximum(1000); + ui_log_margin_spinbox->setValue(p_ao_app->get_log_margin()); + + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_log_margin_spinbox); + + row += 1; + ui_log_timestamp_lbl = new QLabel(ui_form_layout_widget); + ui_log_timestamp_lbl->setText(tr("Log timestamp:")); + ui_log_timestamp_lbl->setToolTip( + tr("If ticked, log will contain a timestamp in UTC before the name.")); + + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_log_timestamp_lbl); + + ui_log_timestamp_cb = new QCheckBox(ui_form_layout_widget); + ui_log_timestamp_cb->setChecked(p_ao_app->get_log_timestamp()); + + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_log_timestamp_cb); + row += 1; ui_log_names_divider = new QFrame(ui_form_layout_widget); ui_log_names_divider->setFrameShape(QFrame::HLine); @@ -726,6 +769,9 @@ void AOOptionsDialog::save_pressed() configini->setValue("theme", ui_theme_combobox->currentText()); configini->setValue("log_goes_downwards", ui_downwards_cb->isChecked()); configini->setValue("log_maximum", ui_length_spinbox->value()); + configini->setValue("log_newline", ui_log_newline_cb->isChecked()); + configini->setValue("log_margin", ui_log_margin_spinbox->value()); + configini->setValue("log_timestamp", ui_log_timestamp_cb->isChecked()); configini->setValue("default_username", ui_username_textbox->text()); configini->setValue("show_custom_shownames", ui_showname_cb->isChecked()); configini->setValue("master", ui_ms_textbox->text()); diff --git a/src/chatlogpiece.cpp b/src/chatlogpiece.cpp index 2a041f1..05a924c 100644 --- a/src/chatlogpiece.cpp +++ b/src/chatlogpiece.cpp @@ -6,29 +6,29 @@ chatlogpiece::chatlogpiece() showname = tr("UNKNOWN"); message = tr("UNKNOWN"); color = 0; - p_is_song = false; + action = ""; datetime = QDateTime::currentDateTime().toUTC(); } chatlogpiece::chatlogpiece(QString p_name, QString p_showname, - QString p_message, bool p_song, int p_color) + QString p_message, QString p_action, int p_color) { name = p_name; showname = p_showname; message = p_message; - p_is_song = p_song; + action = p_action; color = p_color; datetime = QDateTime::currentDateTime().toUTC(); } chatlogpiece::chatlogpiece(QString p_name, QString p_showname, - QString p_message, bool p_song, int p_color, + QString p_message, QString p_action, int p_color, QDateTime p_datetime) { name = p_name; showname = p_showname; message = p_message; - p_is_song = p_song; + action = p_action; color = p_color; datetime = p_datetime.toUTC(); } @@ -41,7 +41,7 @@ QString chatlogpiece::get_message() { return message; } QDateTime chatlogpiece::get_datetime() { return datetime; } -bool chatlogpiece::is_song() { return p_is_song; } +QString chatlogpiece::get_action() { return action; } QString chatlogpiece::get_datetime_as_string() { return datetime.toString(); } @@ -54,13 +54,15 @@ QString chatlogpiece::get_full() full.append(get_datetime_as_string()); full.append("] "); full.append(get_showname()); - full.append(" ("); - full.append(get_name()); - full.append(")"); - if (p_is_song) - full.append(tr(" has played a song: ")); - else - full.append(": "); + if (get_showname() != get_name()) + { + full.append(" ("); + full.append(get_name()); + full.append(")"); + } + if (!get_action().isEmpty()) + full.append(" " + get_action()); + full.append(": "); full.append(get_message()); return full; diff --git a/src/courtroom.cpp b/src/courtroom.cpp index b76a4a6..fe10e13 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -109,6 +109,10 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() log_maximum_blocks = ao_app->get_max_log_size(); log_goes_downwards = ao_app->get_log_goes_downwards(); + log_colors = ao_app->is_colorlog_enabled(); + log_newline = ao_app->get_log_newline(); + log_margin = ao_app->get_log_margin(); + log_timestamp = ao_app->get_log_timestamp(); ui_ms_chatlog = new AOTextArea(this); ui_ms_chatlog->setReadOnly(true); @@ -581,8 +585,20 @@ void Courtroom::set_widgets() ui_vp_objection->move(ui_viewport->x(), ui_viewport->y()); ui_vp_objection->combo_resize(ui_viewport->width(), ui_viewport->height()); + log_maximum_blocks = ao_app->get_max_log_size(); + + bool regenerate = log_goes_downwards != ao_app->get_log_goes_downwards() || log_colors != ao_app->is_colorlog_enabled() || log_newline != ao_app->get_log_newline() || log_margin != ao_app->get_log_margin() || log_timestamp != ao_app->get_log_timestamp(); + log_goes_downwards = ao_app->get_log_goes_downwards(); + log_colors = ao_app->is_colorlog_enabled(); + log_newline = ao_app->get_log_newline(); + log_margin = ao_app->get_log_margin(); + log_timestamp = ao_app->get_log_timestamp(); + if (regenerate) + regenerate_ic_chatlog(); + set_size_and_pos(ui_ic_chatlog, "ic_chatlog"); ui_ic_chatlog->setFrameShape(QFrame::NoFrame); + ui_ic_chatlog->setPlaceholderText(log_goes_downwards ? "▼ Log goes down ▼" : "▲ Log goes up ▲"); set_size_and_pos(ui_ms_chatlog, "ms_chatlog"); ui_ms_chatlog->setFrameShape(QFrame::NoFrame); @@ -1874,17 +1890,8 @@ void Courtroom::handle_chatmessage(QStringList *p_contents) if (!m_chatmessage[MESSAGE].isEmpty() || ic_chatlog_history.isEmpty() || ic_chatlog_history.last().get_message() != "") { - chatlogpiece log_entry(f_charname, f_displayname, m_chatmessage[MESSAGE], false, + log_ic_text(f_charname, f_displayname, m_chatmessage[MESSAGE], "", m_chatmessage[TEXT_COLOR].toInt()); - ic_chatlog_history.append(log_entry); - if (ao_app->get_auto_logging_enabled()) - ao_app->append_to_file(log_entry.get_full(), ao_app->log_filename, true); - - while (ic_chatlog_history.size() > log_maximum_blocks && - log_maximum_blocks > 0) { - ic_chatlog_history.removeFirst(); - } - append_ic_text(m_chatmessage[MESSAGE], f_displayname, "", m_chatmessage[TEXT_COLOR].toInt()); } @@ -2275,13 +2282,16 @@ void Courtroom::handle_chatmessage_3() if (f_evi_id > 0 && f_evi_id <= local_evidence_list.size()) { // shifted by 1 because 0 is no evidence per legacy standards QString f_image = local_evidence_list.at(f_evi_id - 1).image; - QString f_name = local_evidence_list.at(f_evi_id - 1).name; + QString f_evi_name = local_evidence_list.at(f_evi_id - 1).name; // def jud and hlp should display the evidence icon on the RIGHT side bool is_left_side = !(f_side == "def" || f_side == "hlp" || f_side == "jud" || f_side == "jur"); ui_vp_evidence_display->show_evidence(f_image, is_left_side, ui_sfx_slider->value()); - append_ic_text(f_name, f_showname, "has presented evidence"); + + log_ic_text(m_chatmessage[CHAR_NAME], m_chatmessage[SHOWNAME], f_evi_name, tr("has presented evidence"), + m_chatmessage[TEXT_COLOR].toInt()); + append_ic_text(f_evi_name, f_showname, tr("has presented evidence")); } int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); @@ -2585,107 +2595,107 @@ QString Courtroom::filter_ic_text(QString p_text, bool html, int target_pos, return p_text_escaped; } +void Courtroom::log_ic_text(QString p_name, QString p_showname, + QString p_message, QString p_action, int p_color) +{ + chatlogpiece log_entry(p_name, p_showname, p_message, p_action, + p_color); + ic_chatlog_history.append(log_entry); + if (ao_app->get_auto_logging_enabled()) + ao_app->append_to_file(log_entry.get_full(), ao_app->log_filename, true); + + while (ic_chatlog_history.size() > log_maximum_blocks && + log_maximum_blocks > 0) { + ic_chatlog_history.removeFirst(); + } +} + void Courtroom::append_ic_text(QString p_text, QString p_name, QString p_action, int color) { QTextCharFormat bold; QTextCharFormat normal; QTextCharFormat italics; + QTextBlockFormat format; bold.setFontWeight(QFont::Bold); normal.setFontWeight(QFont::Normal); italics.setFontItalic(true); + format.setTopMargin(log_margin); const QTextCursor old_cursor = ui_ic_chatlog->textCursor(); const int old_scrollbar_value = ui_ic_chatlog->verticalScrollBar()->value(); + const bool need_newline = !ui_ic_chatlog->document()->isEmpty(); + const int scrollbar_target_value = log_goes_downwards ? ui_ic_chatlog->verticalScrollBar()->maximum() : ui_ic_chatlog->verticalScrollBar()->minimum(); - if (p_action == "") - p_text = filter_ic_text(p_text, ao_app->is_colorlog_enabled(), -1, color); + ui_ic_chatlog->moveCursor(log_goes_downwards ? QTextCursor::End : QTextCursor::Start); - if (log_goes_downwards) { - const bool is_scrolled_down = - old_scrollbar_value == ui_ic_chatlog->verticalScrollBar()->maximum(); + // Only prepend with newline if log goes downwards + if (log_goes_downwards && need_newline) { + ui_ic_chatlog->textCursor().insertBlock(format); + } - ui_ic_chatlog->moveCursor(QTextCursor::End); + // Timestamp if we're doing that meme + if (log_timestamp) + ui_ic_chatlog->textCursor().insertText("[" + QDateTime::currentDateTime().toString("h:mm:ss AP") + "] ", normal); - if (!first_message_sent) { - ui_ic_chatlog->textCursor().insertText(p_name, bold); - first_message_sent = true; - } - else { - ui_ic_chatlog->textCursor().insertText('\n' + p_name, bold); - } - - if (p_action != "") { - ui_ic_chatlog->textCursor().insertText(" " + p_action + ": ", normal); - ui_ic_chatlog->textCursor().insertText(p_text + ".", italics); - } - else { + // Format the name of the actor + ui_ic_chatlog->textCursor().insertText(p_name, bold); + // If action not blank: + if (p_action != "") { + // Format the action in normal + ui_ic_chatlog->textCursor().insertText(" " + p_action, normal); + if (log_newline) + // For some reason, we're forced to use
instead of the more sensible \n. + // Why? Because \n is treated as a new Block instead of a soft newline within a paragraph! + ui_ic_chatlog->textCursor().insertHtml("
"); + else ui_ic_chatlog->textCursor().insertText(": ", normal); - ui_ic_chatlog->textCursor().insertHtml(p_text); - } - - // If we got too many blocks in the current log, delete some from the top. - while (ui_ic_chatlog->document()->blockCount() > log_maximum_blocks && - log_maximum_blocks > 0) { - ui_ic_chatlog->moveCursor(QTextCursor::Start); - ui_ic_chatlog->textCursor().select(QTextCursor::BlockUnderCursor); - ui_ic_chatlog->textCursor().removeSelectedText(); - ui_ic_chatlog->textCursor().deleteChar(); - } - - if (old_cursor.hasSelection() || !is_scrolled_down) { - // The user has selected text or scrolled away from the bottom: maintain - // position. - ui_ic_chatlog->setTextCursor(old_cursor); - ui_ic_chatlog->verticalScrollBar()->setValue(old_scrollbar_value); - } - else { - // The user hasn't selected any text and the scrollbar is at the bottom: - // scroll to the bottom. - ui_ic_chatlog->moveCursor(QTextCursor::End); - ui_ic_chatlog->verticalScrollBar()->setValue( - ui_ic_chatlog->verticalScrollBar()->maximum()); - } + // Format the result in italics + ui_ic_chatlog->textCursor().insertText(p_text + ".", italics); } else { - const bool is_scrolled_up = - old_scrollbar_value == ui_ic_chatlog->verticalScrollBar()->minimum(); - - ui_ic_chatlog->moveCursor(QTextCursor::Start); - - ui_ic_chatlog->textCursor().insertText(p_name, bold); - - if (p_action != "") { - ui_ic_chatlog->textCursor().insertText(" " + p_action + ": ", normal); - ui_ic_chatlog->textCursor().insertText(p_text + "." + '\n', italics); - } - else { + if (log_newline) + // For some reason, we're forced to use
instead of the more sensible \n. + // Why? Because \n is treated as a new Block instead of a soft newline within a paragraph! + ui_ic_chatlog->textCursor().insertHtml("
"); + else ui_ic_chatlog->textCursor().insertText(": ", normal); - ui_ic_chatlog->textCursor().insertHtml(p_text + "
"); - } + // Format the result according to html + if (log_colors) + ui_ic_chatlog->textCursor().insertHtml(filter_ic_text(p_text, true, -1, color)); + else + ui_ic_chatlog->textCursor().insertText(filter_ic_text(p_text, false), normal); + } - // If we got too many blocks in the current log, delete some from the - // bottom. - while (ui_ic_chatlog->document()->blockCount() > log_maximum_blocks && - log_maximum_blocks > 0) { - ui_ic_chatlog->moveCursor(QTextCursor::End); - ui_ic_chatlog->textCursor().select(QTextCursor::BlockUnderCursor); - ui_ic_chatlog->textCursor().removeSelectedText(); + // Only append with newline if log goes upwards + if (!log_goes_downwards && need_newline) { + ui_ic_chatlog->textCursor().insertBlock(format); + } + + // If we got too many blocks in the current log, delete some. + while (ui_ic_chatlog->document()->blockCount() > log_maximum_blocks && + log_maximum_blocks > 0) { + ui_ic_chatlog->moveCursor(log_goes_downwards ? QTextCursor::Start : QTextCursor::End); + ui_ic_chatlog->textCursor().select(QTextCursor::BlockUnderCursor); + ui_ic_chatlog->textCursor().removeSelectedText(); + if (log_goes_downwards) + ui_ic_chatlog->textCursor().deleteChar(); + else ui_ic_chatlog->textCursor().deletePreviousChar(); - } + } - if (old_cursor.hasSelection() || !is_scrolled_up) { - // The user has selected text or scrolled away from the top: maintain - // position. - ui_ic_chatlog->setTextCursor(old_cursor); - ui_ic_chatlog->verticalScrollBar()->setValue(old_scrollbar_value); - } - else { - // The user hasn't selected any text and the scrollbar is at the top: - // scroll to the top. - ui_ic_chatlog->moveCursor(QTextCursor::Start); - ui_ic_chatlog->verticalScrollBar()->setValue( - ui_ic_chatlog->verticalScrollBar()->minimum()); - } + // Finally, scroll the scrollbar to the correct position. + if (old_cursor.hasSelection() || old_scrollbar_value != scrollbar_target_value) { + // The user has selected text or scrolled away from the bottom: maintain + // position. + ui_ic_chatlog->setTextCursor(old_cursor); + ui_ic_chatlog->verticalScrollBar()->setValue(old_scrollbar_value); + } + else { + // The user hasn't selected any text and the scrollbar is at the bottom: + // scroll to the bottom. + ui_ic_chatlog->moveCursor(log_goes_downwards ? QTextCursor::End : QTextCursor::Start); + ui_ic_chatlog->verticalScrollBar()->setValue( + ui_ic_chatlog->verticalScrollBar()->maximum()); } } @@ -3188,17 +3198,8 @@ void Courtroom::handle_song(QStringList *p_contents) } if (!mute_map.value(n_char)) { - chatlogpiece *temp = new chatlogpiece(str_char, str_show, f_song, true, - m_chatmessage[TEXT_COLOR].toInt()); - ic_chatlog_history.append(*temp); - if (ao_app->get_auto_logging_enabled()) - ao_app->append_to_file(temp->get_full(), ao_app->log_filename, true); - - while (ic_chatlog_history.size() > log_maximum_blocks && - log_maximum_blocks > 0) { - ic_chatlog_history.removeFirst(); - } - + log_ic_text(str_char, str_show, f_song, tr("has played a song"), + m_chatmessage[TEXT_COLOR].toInt()); append_ic_text(f_song_clear, str_show, tr("has played a song")); music_player->play(f_song, channel, looping, effect_flags); @@ -4659,31 +4660,19 @@ void Courtroom::on_guard_clicked() { ui_ic_chat_message->setFocus(); } void Courtroom::on_showname_enable_clicked() { - ui_ic_chatlog->clear(); - first_message_sent = false; - - foreach (chatlogpiece item, ic_chatlog_history) { - if (ui_showname_enable->isChecked()) { - if (item.is_song()) - append_ic_text(item.get_message(), item.get_showname(), - tr("has played a song")); - else - append_ic_text(item.get_message(), item.get_showname(), "", - item.get_chat_color()); - } - else { - if (item.is_song()) - append_ic_text(item.get_message(), item.get_name(), - tr("has played a song")); - else - append_ic_text(item.get_message(), item.get_name(), "", - item.get_chat_color()); - } - } - + regenerate_ic_chatlog(); ui_ic_chat_message->setFocus(); } +void Courtroom::regenerate_ic_chatlog() +{ + ui_ic_chatlog->clear(); + foreach (chatlogpiece item, ic_chatlog_history) { + append_ic_text(item.get_message(), ui_showname_enable->isChecked() ? item.get_showname() : item.get_name(), + item.get_action(), item.get_chat_color()); + } +} + void Courtroom::on_evidence_button_clicked() { if (ui_evidence->isHidden()) { diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 33a18d5..8247fd8 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -53,6 +53,26 @@ bool AOApplication::get_log_goes_downwards() return result.startsWith("true"); } +bool AOApplication::get_log_newline() +{ + QString result = + configini->value("log_newline", "false").value(); + return result.startsWith("true"); +} + +int AOApplication::get_log_margin() +{ + int result = configini->value("log_margin", 0).toInt(); + return result; +} + +bool AOApplication::get_log_timestamp() +{ + QString result = + configini->value("log_timestamp", "false").value(); + return result.startsWith("true"); +} + bool AOApplication::get_showname_enabled_by_default() { QString result =