diff --git a/include/courtroom.h b/include/courtroom.h index 4f59788df..2dc680e23 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -109,10 +109,14 @@ class Courtroom : public QMainWindow public: QString get_character(); QString get_character_ini(); + QString get_character_base_ini(); + QString get_character_outfit_ini(); QString get_character_content_url(); void update_iniswap_list(); + void update_outfit_list(); void update_default_iniswap_item(); - void select_base_character_iniswap(); + void select_character_base_iniswap(); + void select_character_outfit_iniswap(); void refresh_character_content_url(); // Set the showname of the client @@ -406,6 +410,7 @@ class Courtroom : public QMainWindow QComboBox *ui_emote_dropdown = nullptr; QComboBox *ui_iniswap_dropdown = nullptr; QComboBox *ui_pos_dropdown = nullptr; + QComboBox *ui_outfit_dropdown = nullptr; AOImageDisplay *ui_defense_bar = nullptr; AOImageDisplay *ui_prosecution_bar = nullptr; @@ -592,6 +597,7 @@ private slots: void on_emote_dropdown_changed(int p_index); void on_iniswap_dropdown_changed(int p_index); + void on_outfit_dropdown_changed(int p_index); void on_pos_dropdown_changed(int p_index); void on_evidence_name_edited(); diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 21142b8fd..3be0d9d8c 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -109,6 +109,7 @@ void Courtroom::setup_courtroom() ui_char_select_background->setVisible(l_chr_select_visible); update_iniswap_list(); + update_outfit_list(); m_shout_state = 0; m_shout_current = 0; @@ -164,6 +165,8 @@ void Courtroom::enter_courtroom(int p_cid) const int l_current_cursor_pos = l_current_field->cursorPosition(); const QString l_chr_name = get_character_ini(); + const QString l_base_chr_name = get_character_base_ini(); + if (is_spectating()) { ao_app->get_discord()->clear_character_name(); @@ -183,9 +186,11 @@ void Courtroom::enter_courtroom(int p_cid) } } const bool l_changed_chr = l_chr_name != l_prev_chr_name; + if (l_changed_chr) set_character_position(ao_app->get_char_side(l_chr_name)); - select_base_character_iniswap(); + select_character_base_iniswap(); + update_outfit_list(); refresh_character_content_url(); const int l_prev_emote_count = m_emote_list.count(); @@ -212,6 +217,7 @@ void Courtroom::enter_courtroom(int p_cid) ui_emotes->setHidden(is_spectating()); ui_emote_dropdown->setDisabled(is_spectating()); ui_iniswap_dropdown->setDisabled(is_spectating()); + ui_outfit_dropdown->setDisabled(is_spectating()); ui_ic_chat_message->setDisabled(is_spectating()); // restore line field focus diff --git a/src/courtroom_character.cpp b/src/courtroom_character.cpp index 112873c7f..22534f116 100644 --- a/src/courtroom_character.cpp +++ b/src/courtroom_character.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -35,6 +36,42 @@ QString Courtroom::get_character_ini() return ao_config->character_ini(get_character()); } +QString Courtroom::get_character_base_ini() +{ + const QString l_chr_ini = get_character_ini(); + if (l_chr_ini.isEmpty()) + return ""; + if (ui_iniswap_dropdown->findText(l_chr_ini) != -1) + return l_chr_ini; + + + const QStringList l_item_list = l_chr_ini.split(QRegularExpression("[\\/]")); + QString l_chr_ini_full = ao_app->get_base_path() + "characters/"; + QString l_chr_ini_short = ""; + for (auto it = l_item_list.cbegin(); it != l_item_list.cend(); it++) + { + QString name = *it; + l_chr_ini_full += name + "/"; + l_chr_ini_short += name + "/"; + if (file_exists(l_chr_ini_full + CHARACTER_CHAR_INI)) + return l_chr_ini_short.chopped(1); + } + return ""; +} + +QString Courtroom::get_character_outfit_ini() +{ + const QString l_chr_ini = get_character_ini(); + if (l_chr_ini.isEmpty()) + return ""; + const QString l_chr_base_ini = get_character_base_ini(); + if (l_chr_ini == l_chr_base_ini) + return ""; + + const QString l_chr_outfit_ini = l_chr_ini.mid(l_chr_base_ini.length()+1); // Account for "/" + return l_chr_outfit_ini; +} + QString Courtroom::get_character_content_url() { QFile l_contentFile(ao_app->get_character_path(get_character_ini(), "CONTENT.txt")); @@ -63,21 +100,37 @@ void drSetItemIcon(QComboBox *p_widget, const int p_index, const QString &p_chr_ } } // namespace +void _traverse_characters_folder(QStringList *l_name_list, QString l_path_start, QString l_path_end, + bool l_is_root_dir) +{ + if (!l_is_root_dir & file_exists(l_path_start + l_path_end + "/" + CHARACTER_CHAR_INI)) + { + const QString l_name = l_path_end.mid(1); + if (!l_name.isEmpty()) + l_name_list->append(l_name); + return; + } + QDirIterator it(l_path_start + l_path_end, QDir::Dirs | QDir::NoDotAndDotDot); + while (it.hasNext()) { + it.next(); + QFileInfo l_file_info = it.fileInfo(); + QString l_folder_name = l_file_info.fileName(); + if (l_folder_name == "emotions") + continue; + if (l_folder_name == "sounds") + continue; + _traverse_characters_folder(l_name_list, l_path_start, l_path_end + "/" + l_folder_name, false); + } +} + void Courtroom::update_iniswap_list() { QSignalBlocker b_ini_list(ui_iniswap_dropdown); ui_iniswap_dropdown->clear(); - QStringList l_name_list{"Default"}; - const QString l_path = ao_app->get_base_path() + "/characters"; - const QFileInfoList l_info_list = QDir(l_path).entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot); - for (const QFileInfo &i_info : l_info_list) - { - const QString l_name = i_info.fileName(); - if (!file_exists(ao_app->get_character_path(l_name, CHARACTER_CHAR_INI))) - continue; - l_name_list.append(l_name); - } + QStringList l_name_list{""}; + const QString l_path_start = ao_app->get_base_path() + "characters/"; + _traverse_characters_folder(&l_name_list, l_path_start, "", true); for (int i = 0; i < l_name_list.length(); ++i) { @@ -88,8 +141,7 @@ void Courtroom::update_iniswap_list() drSetItemIcon(ui_iniswap_dropdown, i, i_name, ao_app); } update_default_iniswap_item(); - - select_base_character_iniswap(); + select_character_base_iniswap(); } void Courtroom::update_default_iniswap_item() @@ -97,9 +149,34 @@ void Courtroom::update_default_iniswap_item() drSetItemIcon(ui_iniswap_dropdown, 0, get_character(), ao_app); } -void Courtroom::select_base_character_iniswap() +void Courtroom::update_outfit_list() +{ + QSignalBlocker b_ini_list(ui_outfit_dropdown); + ui_outfit_dropdown->clear(); + + QStringList l_name_list{""}; + const QString char_ini = get_character_base_ini(); + if (!char_ini.isEmpty()) + { + const QString l_path_start = ao_app->get_base_path() + "characters/" + char_ini + "/"; + _traverse_characters_folder(&l_name_list, l_path_start, "", true); + } + + for (int i = 0; i < l_name_list.length(); ++i) + { + const QString &i_name = l_name_list.at(i); + ui_outfit_dropdown->addItem(i_name); + if (i == 0) + continue; + drSetItemIcon(ui_iniswap_dropdown, i, get_character() + "/" + i_name, ao_app); + } + drSetItemIcon(ui_iniswap_dropdown, 0, get_character(), ao_app); + select_character_outfit_iniswap(); +} + +void Courtroom::select_character_base_iniswap() { - const QString l_current_chr = get_character_ini(); + QString l_current_chr = get_character_base_ini(); if (get_character() == l_current_chr) { ui_iniswap_dropdown->setCurrentIndex(0); @@ -108,6 +185,17 @@ void Courtroom::select_base_character_iniswap() ui_iniswap_dropdown->setCurrentText(l_current_chr); } +void Courtroom::select_character_outfit_iniswap() +{ + QString l_current_outfit = get_character_outfit_ini(); + if (l_current_outfit.isEmpty()) + { + ui_outfit_dropdown->setCurrentIndex(0); + return; + } + ui_outfit_dropdown->setCurrentText(l_current_outfit); +} + void Courtroom::refresh_character_content_url() { const QString l_new_content_url = get_character_content_url(); @@ -122,3 +210,16 @@ void Courtroom::on_iniswap_dropdown_changed(int p_index) ao_config->set_character_ini(get_character(), p_index == 0 ? get_character() : ui_iniswap_dropdown->itemText(p_index)); } + +void Courtroom::on_outfit_dropdown_changed(int p_index) +{ + QString l_character = get_character(); + QString l_chr_base_ini = get_character_base_ini(); + if (p_index == 0) + ao_config->set_character_ini(l_character, l_chr_base_ini); + else + { + QString l_character_outfit = l_chr_base_ini + "/" + ui_outfit_dropdown->itemText(p_index); + ao_config->set_character_ini(l_character, l_character_outfit); + } +} diff --git a/src/courtroom_widgets.cpp b/src/courtroom_widgets.cpp index 946e6222a..5af10a971 100644 --- a/src/courtroom_widgets.cpp +++ b/src/courtroom_widgets.cpp @@ -107,6 +107,15 @@ void Courtroom::create_widgets() ui_vp_chat_arrow->set_play_once(false); ui_iniswap_dropdown = new QComboBox(this); + QListView* view = new QListView(ui_iniswap_dropdown); + ui_iniswap_dropdown->setView(view); + view->setTextElideMode(Qt::TextElideMode::ElideNone); + view->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded); + ui_outfit_dropdown = new QComboBox(this); + QListView* view2 = new QListView(ui_outfit_dropdown); + ui_outfit_dropdown->setView(view2); + view2->setTextElideMode(Qt::TextElideMode::ElideNone); + view2->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded); ui_ic_chatlog = new DRTextEdit(this); ui_ic_chatlog->setReadOnly(true); @@ -264,6 +273,7 @@ void Courtroom::connect_widgets() connect(ui_emote_dropdown, SIGNAL(activated(int)), this, SLOT(on_emote_dropdown_changed(int))); connect(ui_iniswap_dropdown, SIGNAL(activated(int)), this, SLOT(on_iniswap_dropdown_changed(int))); + connect(ui_outfit_dropdown, SIGNAL(activated(int)), this, SLOT(on_outfit_dropdown_changed(int))); connect(ui_pos_dropdown, SIGNAL(activated(int)), this, SLOT(on_pos_dropdown_changed(int))); connect(ao_config, SIGNAL(showname_changed(QString)), this, SLOT(on_showname_changed(QString))); @@ -383,6 +393,7 @@ void Courtroom::reset_widget_names() {"emote_right", ui_emote_right}, {"emote_dropdown", ui_emote_dropdown}, {"iniswap_dropdown", ui_iniswap_dropdown}, + {"outfit_dropdown", ui_outfit_dropdown}, {"pos_dropdown", ui_pos_dropdown}, {"defense_bar", ui_defense_bar}, {"prosecution_bar", ui_prosecution_bar}, @@ -718,6 +729,8 @@ void Courtroom::set_widgets() set_size_and_pos(ui_iniswap_dropdown, "iniswap_dropdown", COURTROOM_DESIGN_INI, ao_app); set_stylesheet(ui_iniswap_dropdown, "[INISWAP DROPDOWN]", COURTROOM_STYLESHEETS_CSS, ao_app); + set_size_and_pos(ui_outfit_dropdown, "outfit_dropdown", COURTROOM_DESIGN_INI, ao_app); + set_size_and_pos(ui_pos_dropdown, "pos_dropdown", COURTROOM_DESIGN_INI, ao_app); set_stylesheet(ui_pos_dropdown, "[POS DROPDOWN]", COURTROOM_STYLESHEETS_CSS, ao_app);