diff --git a/include/aoapplication.h b/include/aoapplication.h index e76ad68..9a070d4 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -130,9 +130,7 @@ public: // implementation in path_functions.cpp QString get_base_path(); QString get_data_path(); - QString get_theme_path(QString p_file); - QString get_default_theme_path(QString p_file); - QString get_custom_theme_path(QString p_theme, QString p_file); + QString get_theme_path(QString p_file, QString p_theme=""); QString get_character_path(QString p_char, QString p_file); QString get_misc_path(QString p_misc, QString p_file); QString get_sounds_path(QString p_file); @@ -140,6 +138,14 @@ public: QString get_background_path(QString p_file); QString get_default_background_path(QString p_file); QString get_evidence_path(QString p_file); + QStringList get_asset_paths(QString p_element, QString p_theme="", QString p_subtheme="", QString p_default_theme="", QString p_misc="", QString p_character="", QString p_placeholder=""); + QString get_asset_path(QStringList pathlist); + QString get_image_path(QStringList pathlist, bool static_image=false); + QString get_sfx_path(QStringList pathlist); + QString get_config_value(QString p_identifier, QString p_config, QString p_theme="", QString p_subtheme="", QString p_default_theme="", QString p_misc=""); + QString get_asset(QString p_element, QString p_theme="", QString p_subtheme="", QString p_default_theme="", QString p_misc="", QString p_character="", QString p_placeholder=""); + QString get_image(QString p_element, QString p_theme="", QString p_subtheme="", QString p_default_theme="", QString p_misc="", QString p_character="", QString p_placeholder=""); + QString get_sfx(QString p_sfx, QString p_misc="", QString p_character=""); QString get_case_sensitive_path(QString p_file); ////// Functions for reading and writing files ////// @@ -306,10 +312,7 @@ public: // Returns the value to you QString get_design_element(QString p_identifier, QString p_file, - QString p_char = ""); - - // Returns the name of the font with p_identifier from p_file - QString get_font_name(QString p_identifier, QString p_file); + QString p_misc = ""); // Returns the value of font_size with p_identifier from p_file int get_font_size(QString p_identifier, QString p_file); @@ -323,19 +326,15 @@ public: // Returns the color from the misc folder. QColor get_chat_color(QString p_identifier, QString p_chat); - // Returns the sfx with p_identifier from sounds.ini in the current theme path - QString get_sfx(QString p_identifier, QString p_misc="default"); + // Returns the sfx with p_identifier from courtroom_sounds.ini in the current theme path + QString get_court_sfx(QString p_identifier, QString p_misc=""); // Figure out if we can opus this or if we should fall back to wav QString get_sfx_suffix(QString sound_to_check); // Can we use APNG for this? If not, WEBP? If not, GIF? If not, fall back to // PNG. - QString get_image_suffix(QString path_to_check); - - // If this image is static and non-animated, return the supported static image - // formats. Currently only PNG. - QString get_static_image_suffix(QString path_to_check); + QString get_image_suffix(QString path_to_check, bool static_image=false); // Returns the value of p_search_line within target_tag and terminator_tag QString read_char_ini(QString p_char, QString p_search_line, @@ -372,9 +371,6 @@ public: // Returns the value of chat font size from the specific p_char's ini file int get_chat_size(QString p_char); - // Returns the value of shouts from the specified p_char's ini file - QString get_char_shouts(QString p_char); - // Returns the preanim duration of p_char's p_emote int get_preanim_duration(QString p_char, QString p_emote); @@ -385,10 +381,6 @@ public: // Not in use int get_text_delay(QString p_char, QString p_emote); - // Get the effects folder referenced by the char.ini, read it and return the - // list of filenames in a string - QStringList get_theme_effects(); - // Get the theme's effects folder, read it and return the list of filenames in // a string QStringList get_effects(QString p_char); @@ -488,6 +480,18 @@ public: // Get if automatic logging is enabled bool get_auto_logging_enabled(); + // Get the subtheme from settings + QString get_subtheme(); + + // Get if the theme is animated + bool get_animated_theme(); + + // Currently defined subtheme + QString subtheme; + + QString default_theme = "default"; + QString current_theme = default_theme; + // The file name of the log file in base/logs. QString log_filename; @@ -505,8 +509,6 @@ private: const int MAJOR_VERSION = 9; const int MINOR_VERSION = 0; - QString current_theme = "default"; - QVector server_list; QVector favorite_list; diff --git a/include/aobutton.h b/include/aobutton.h index f575885..f1ae8b7 100644 --- a/include/aobutton.h +++ b/include/aobutton.h @@ -5,6 +5,7 @@ #include #include +#include class AOButton : public QPushButton { Q_OBJECT @@ -14,8 +15,9 @@ public: ~AOButton(); AOApplication *ao_app; + QMovie *movie; - void set_image(QString p_image); + void set_image(QString p_image, QString p_misc=""); }; #endif // AOBUTTON_H diff --git a/include/aoimage.h b/include/aoimage.h index 01ef854..70ff1fc 100644 --- a/include/aoimage.h +++ b/include/aoimage.h @@ -7,6 +7,7 @@ #include #include +#include class AOImage : public QLabel { public: @@ -15,9 +16,11 @@ public: QWidget *m_parent; AOApplication *ao_app; + QMovie *movie; - bool set_image(QString p_image); - bool set_chatbox(QString p_path); + QString path; + + bool set_image(QString p_image, QString p_misc = ""); void set_size_and_pos(QString identifier); }; diff --git a/include/aolayer.h b/include/aolayer.h index 6b4fb1f..c32da02 100644 --- a/include/aolayer.h +++ b/include/aolayer.h @@ -85,7 +85,7 @@ public: // iterate through a list of paths and return the first entry that exists. if // none exist, return NULL (safe because we check again for existence later) - QString find_image(QList p_list); + QString find_image(QStringList p_list); protected: AOApplication *ao_app; diff --git a/include/aooptionsdialog.h b/include/aooptionsdialog.h index b128ce2..31f3d66 100644 --- a/include/aooptionsdialog.h +++ b/include/aooptionsdialog.h @@ -45,7 +45,11 @@ private: QFormLayout *ui_gameplay_form; QLabel *ui_theme_label; QComboBox *ui_theme_combobox; + QLabel *ui_subtheme_label; + QComboBox *ui_subtheme_combobox; QPushButton *ui_theme_reload_button; + QLabel *ui_animated_theme_lbl; + QCheckBox *ui_animated_theme_cb; QFrame *ui_theme_log_divider; QLabel *ui_downwards_lbl; QCheckBox *ui_downwards_cb; @@ -173,6 +177,7 @@ public slots: void discard_pressed(); void button_clicked(QAbstractButton *button); void on_reload_theme_clicked(); + void theme_changed(int i); }; #endif // AOOPTIONSDIALOG_H diff --git a/include/courtroom.h b/include/courtroom.h index 43a0910..eb1aa7b 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -505,7 +505,7 @@ private: QVector default_color_rgb_list; // Get a color index from an arbitrary misc config - void gen_char_rgb_list(QString p_char); + void gen_char_rgb_list(QString p_misc); QVector char_color_rgb_list; // Misc we used for the last message, and the one we're using now. Used to avoid loading assets when it's not needed diff --git a/src/aobutton.cpp b/src/aobutton.cpp index b6d4af6..7f8c13f 100644 --- a/src/aobutton.cpp +++ b/src/aobutton.cpp @@ -7,34 +7,42 @@ AOButton::AOButton(QWidget *parent, AOApplication *p_ao_app) : QPushButton(parent) { ao_app = p_ao_app; + movie = new QMovie(this); + connect(movie, &QMovie::frameChanged, [=]{ + this->setIcon(movie->currentPixmap().scaled(this->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + this->setIconSize(QSize(this->width(), this->height())); + }); } AOButton::~AOButton() {} -void AOButton::set_image(QString p_image) +void AOButton::set_image(QString p_path, QString p_misc) { - QString image_path = - ao_app->get_static_image_suffix(ao_app->get_theme_path(p_image)); - QString default_image_path = - ao_app->get_static_image_suffix(ao_app->get_default_theme_path(p_image)); - - if (file_exists(image_path)) { - this->setText(""); - this->setStyleSheet("QPushButton { border-image: url(\"" + image_path + - "\") 0 0 0 0 stretch stretch; }" - "QToolTip { background-image: url(); color: #000000; " - "background-color: #ffffff; border: 0px; }"); - } - else if (file_exists(default_image_path)) { - this->setText(""); - this->setStyleSheet("QPushButton { border-image: url(\"" + - default_image_path + - "\"); }" - "QToolTip { background-image: url(); color: #000000; " - "background-color: #ffffff; border: 0px; }"); - } + movie->stop(); + QString p_image; + // Check if the user wants animated themes + if (ao_app->get_animated_theme()) + // We want an animated image + p_image = ao_app->get_image(p_path, ao_app->current_theme, ao_app->get_subtheme(), ao_app->default_theme, p_misc); else - this->setStyleSheet("QPushButton { border-image: url(); }" - "QToolTip { background-image: url(); color: #000000; " - "background-color: #ffffff; border: 0px; }"); + // Grab a static variant of the image + p_image = ao_app->get_image_path(ao_app->get_asset_paths(p_path, ao_app->current_theme, ao_app->get_subtheme(), ao_app->default_theme, p_misc), true); + if (!file_exists(p_image)) { + this->setIcon(QIcon()); + this->setIconSize(this->size()); + this->setStyleSheet(""); + return; + } + this->setText(""); + this->setStyleSheet("QPushButton { background-color: transparent; border: 0px }"); + movie->setFileName(p_image); + // We double-check if the user wants animated themes, so even if an animated image slipped through, + // we still set it static + if (ao_app->get_animated_theme() && movie->frameCount() > 1) { + movie->start(); + } + else { + this->setIcon(QPixmap(p_image).scaled(this->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + this->setIconSize(this->size()); + } } diff --git a/src/aocharbutton.cpp b/src/aocharbutton.cpp index 844c959..3b384f3 100644 --- a/src/aocharbutton.cpp +++ b/src/aocharbutton.cpp @@ -59,7 +59,7 @@ void AOCharButton::set_passworded() { ui_passworded->show(); } void AOCharButton::set_image(QString p_character) { - QString image_path = ao_app->get_static_image_suffix( + QString image_path = ao_app->get_image_suffix( ao_app->get_character_path(p_character, "char_icon")); this->setText(""); diff --git a/src/aoemotebutton.cpp b/src/aoemotebutton.cpp index 07e6a42..3260a94 100644 --- a/src/aoemotebutton.cpp +++ b/src/aoemotebutton.cpp @@ -61,7 +61,7 @@ void AOEmoteButton::set_char_image(QString p_char, int p_emote, QString suffix) { QString emotion_number = QString::number(p_emote + 1); QString image_path = - ao_app->get_static_image_suffix(ao_app->get_character_path( + ao_app->get_image_suffix(ao_app->get_character_path( p_char, "emotions/button" + emotion_number + suffix)); this->set_image(image_path, ao_app->get_emote_comment(p_char, p_emote)); diff --git a/src/aoevidencebutton.cpp b/src/aoevidencebutton.cpp index f85a223..aea903a 100644 --- a/src/aoevidencebutton.cpp +++ b/src/aoevidencebutton.cpp @@ -58,7 +58,7 @@ void AOEvidenceButton::set_image(QString p_image) void AOEvidenceButton::set_theme_image(QString p_image) { QString theme_image_path = ao_app->get_theme_path(p_image); - QString default_image_path = ao_app->get_default_theme_path(p_image); + QString default_image_path = ao_app->get_theme_path(p_image, ao_app->default_theme); QString final_image_path; diff --git a/src/aoevidencedisplay.cpp b/src/aoevidencedisplay.cpp index f6dffd8..ef5c8fd 100644 --- a/src/aoevidencedisplay.cpp +++ b/src/aoevidencedisplay.cpp @@ -23,7 +23,6 @@ void AOEvidenceDisplay::show_evidence(QString p_evidence_image, sfx_player->set_volume(p_volume); - QString final_gif_path; QString gif_name; QString icon_identifier; @@ -50,7 +49,7 @@ void AOEvidenceDisplay::show_evidence(QString p_evidence_image, evidence_movie->max_duration = 1000; evidence_movie->set_play_once(true); evidence_movie->load_image(gif_name, ""); - sfx_player->play(ao_app->get_sfx("evidence_present", "default")); + sfx_player->play(ao_app->get_court_sfx("evidence_present")); } void AOEvidenceDisplay::reset() diff --git a/src/aoimage.cpp b/src/aoimage.cpp index 3977c97..e1bd8b8 100644 --- a/src/aoimage.cpp +++ b/src/aoimage.cpp @@ -8,49 +8,45 @@ AOImage::AOImage(QWidget *parent, AOApplication *p_ao_app) : QLabel(parent) { m_parent = parent; ao_app = p_ao_app; + movie = new QMovie(); + connect(movie, &QMovie::frameChanged, [=]{ + QPixmap f_pixmap = movie->currentPixmap(); + f_pixmap = + f_pixmap.scaled(this->size(), Qt::IgnoreAspectRatio); + this->setPixmap(f_pixmap); + this->setMask(f_pixmap.mask()); + }); } AOImage::~AOImage() {} -bool AOImage::set_image(QString p_image) +bool AOImage::set_image(QString p_path, QString p_misc) { - QString theme_image_path = - ao_app->get_static_image_suffix(ao_app->get_theme_path(p_image)); - QString default_image_path = - ao_app->get_static_image_suffix(ao_app->get_default_theme_path(p_image)); + // Check if the user wants animated themes + if (ao_app->get_animated_theme()) + // We want an animated image + p_path = ao_app->get_image(p_path, ao_app->current_theme, ao_app->get_subtheme(), ao_app->default_theme, p_misc); + else + // Grab a static variant of the image + p_path = ao_app->get_image_path(ao_app->get_asset_paths(p_path, ao_app->current_theme, ao_app->get_subtheme(), ao_app->default_theme, p_misc), true); - QString final_image_path; - - if (file_exists(theme_image_path)) - final_image_path = theme_image_path; - else if (file_exists(default_image_path)) - final_image_path = default_image_path; - else { - qDebug() << "Warning: Image" << p_image << "not found! Can't set!"; - return false; - } - - QPixmap f_pixmap(final_image_path); - f_pixmap = - f_pixmap.scaled(this->width(), this->height(), Qt::IgnoreAspectRatio); - this->setPixmap(f_pixmap); - this->setMask(f_pixmap.mask()); - return true; -} - -bool AOImage::set_chatbox(QString p_path) -{ - p_path = ao_app->get_static_image_suffix(p_path); if (!file_exists(p_path)) { - qDebug() << "Warning: Chatbox" << p_path << "not found! Can't set!"; + qDebug() << "Warning: Image" << p_path << "not found! Can't set!"; return false; } + path = p_path; + movie->stop(); + movie->setFileName(path); + if (ao_app->get_animated_theme() && movie->frameCount() > 1) { + movie->start(); + } + else { + QPixmap f_pixmap(path); - QPixmap f_pixmap(p_path); - - f_pixmap = - f_pixmap.scaled(this->width(), this->height(), Qt::IgnoreAspectRatio); - this->setPixmap(f_pixmap); - this->setMask(f_pixmap.mask()); + f_pixmap = + f_pixmap.scaled(this->size(), Qt::IgnoreAspectRatio); + this->setPixmap(f_pixmap); + this->setMask(f_pixmap.mask()); + } return true; } diff --git a/src/aolayer.cpp b/src/aolayer.cpp index 05bec48..9b1ab83 100644 --- a/src/aolayer.cpp +++ b/src/aolayer.cpp @@ -49,7 +49,7 @@ StickerLayer::StickerLayer(QWidget *p_parent, AOApplication *p_ao_app) { } -QString AOLayer::find_image(QList p_list) +QString AOLayer::find_image(QStringList p_list) { QString image_path; for (QString path : p_list) { @@ -75,14 +75,15 @@ QPixmap AOLayer::get_pixmap(QImage image) else f_pixmap = QPixmap::fromImage(image); // auto aspect_ratio = Qt::KeepAspectRatio; - if (f_pixmap.height() > f_h) // We are downscaling, use anti-aliasing. - transform_mode = Qt::SmoothTransformation; - if (stretch) - f_pixmap = f_pixmap.scaled(f_w, f_h); - else - f_pixmap = f_pixmap.scaledToHeight(f_h, transform_mode); - this->resize(f_pixmap.size()); - + if (!f_pixmap.isNull()) { + if (f_pixmap.height() > f_h) // We are downscaling, use anti-aliasing. + transform_mode = Qt::SmoothTransformation; + if (stretch) + f_pixmap = f_pixmap.scaled(f_w, f_h); + else + f_pixmap = f_pixmap.scaledToHeight(f_h, transform_mode); + this->resize(f_pixmap.size()); + } return f_pixmap; } @@ -194,7 +195,7 @@ void CharLayer::load_image(QString p_filename, QString p_charname, << current_emote << " from character: " << p_charname << " continuous: " << continuous; #endif - QList pathlist = { + QStringList pathlist = { ao_app->get_image_suffix(ao_app->get_character_path( p_charname, prefix + current_emote)), // Default path ao_app->get_image_suffix(ao_app->get_character_path( @@ -206,42 +207,16 @@ void CharLayer::load_image(QString p_filename, QString p_charname, current_emote)), // Just use the non-prefixed image, animated or not ao_app->get_image_suffix( ao_app->get_theme_path("placeholder")), // Theme placeholder path - ao_app->get_image_suffix(ao_app->get_default_theme_path( - "placeholder"))}; // Default theme placeholder path - this->start_playback(find_image(pathlist)); + ao_app->get_image_suffix(ao_app->get_theme_path( + "placeholder", ao_app->default_theme))}; // Default theme placeholder path + start_playback(find_image(pathlist)); } void SplashLayer::load_image(QString p_filename, QString p_charname, QString p_miscname) { transform_mode = ao_app->get_misc_scaling(p_miscname); - QList pathlist = { - ao_app->get_image_suffix(ao_app->get_character_path( - p_charname, p_filename)), // Character folder - ao_app->get_image_suffix(ao_app->get_theme_path( - "misc/" + p_miscname + "/" + p_filename)), // Theme misc path - ao_app->get_image_suffix( - ao_app->get_misc_path(p_miscname, p_filename)), // Misc path - ao_app->get_image_suffix( - ao_app->get_theme_path(p_filename)), // Theme path - ao_app->get_image_suffix( - ao_app->get_default_theme_path(p_filename)), // Default theme path - ao_app->get_image_suffix( - ao_app->get_theme_path("placeholder")), // Placeholder path - ao_app->get_image_suffix(ao_app->get_default_theme_path( - "placeholder")), // Default placeholder path - }; - QString final_image = find_image(pathlist); - if (final_image == ao_app->get_theme_path("custom.png") || - final_image == ao_app->get_default_theme_path("custom.png") || - final_image == ao_app->get_theme_path("witnesstestimony.png") || - final_image == ao_app->get_default_theme_path("witnesstestimony.png") || - final_image == ao_app->get_theme_path("crossexamination.png") || - final_image == ao_app->get_default_theme_path("crossexamination.png")) - // stupid exceptions because themes are stupid - final_image = find_image( - {ao_app->get_image_suffix(ao_app->get_theme_path("placeholder")), - ao_app->get_image_suffix(ao_app->get_default_theme_path("placeholder"))}); + QString final_image = ao_app->get_image(p_filename, ao_app->current_theme, ao_app->get_subtheme(), ao_app->default_theme, p_miscname, p_charname, "placeholder"); start_playback(final_image); } @@ -259,36 +234,19 @@ void EffectLayer::load_image(QString p_filename, bool p_looping) void InterfaceLayer::load_image(QString p_filename, QString p_miscname) { stretch = true; - QList pathlist = { - ao_app->get_image_suffix(ao_app->get_theme_path( - "misc/" + p_miscname + "/" + - p_filename)), // first check our theme's misc directory - ao_app->get_image_suffix(ao_app->get_misc_path( - p_miscname, p_filename)), // then check our global misc folder - ao_app->get_image_suffix(ao_app->get_theme_path( - p_filename)), // then check the user's theme for a default image - ao_app->get_image_suffix(ao_app->get_default_theme_path( - p_filename))}; // and finally check the default theme - start_playback(find_image(pathlist)); + QString final_image = ao_app->get_image(p_filename, ao_app->current_theme, ao_app->get_subtheme(), ao_app->default_theme, p_miscname); + start_playback(final_image); } void StickerLayer::load_image(QString p_charname) { - QString miscname = ao_app->get_char_shouts(p_charname); - transform_mode = ao_app->get_misc_scaling(miscname); - QList pathlist = { - ao_app->get_image_suffix(ao_app->get_base_path() + "misc/" + - miscname + "/sticker/" + p_charname), // Misc path - ao_app->get_image_suffix(ao_app->get_custom_theme_path(miscname, "sticker/" + p_charname)), // Custom theme path - ao_app->get_image_suffix(ao_app->get_theme_path("sticker/" + p_charname)), // Theme path - ao_app->get_image_suffix( - ao_app->get_default_theme_path("sticker/" + p_charname)), // Default theme path - ao_app->get_image_suffix( - ao_app->get_character_path(p_charname, "sticker")), // Character folder - ao_app->get_image_suffix( - ao_app->get_character_path(p_charname, "showname")), // Scuffed DRO way - }; - start_playback(find_image(pathlist)); + QString p_miscname = ao_app->get_chat(p_charname); + transform_mode = ao_app->get_misc_scaling(p_miscname); + QString final_image = ao_app->get_image("sticker/" + p_charname, ao_app->current_theme, ao_app->get_subtheme(), ao_app->default_theme, p_miscname); + if (!file_exists((final_image))) + final_image = ao_app->get_image_suffix( + ao_app->get_character_path(p_charname, "showname")), // Scuffed DRO way + start_playback(final_image); } void CharLayer::start_playback(QString p_image) @@ -311,9 +269,6 @@ void AOLayer::start_playback(QString p_image) movie_frames.clear(); movie_delays.clear(); - if (!file_exists(p_image)) - return; - if (!ao_app->is_continuous_enabled()) { continuous = false; force_continuous = true; @@ -423,6 +378,8 @@ void AOLayer::set_max_duration(int p_max_duration) void CharLayer::load_effects() { movie_effects.clear(); + if (max_frames <= 1) + return; movie_effects.resize(max_frames); for (int e_frame = 0; e_frame < max_frames; ++e_frame) { QString effect = ao_app->get_screenshake_frame(m_char, m_emote, e_frame); @@ -445,6 +402,8 @@ void CharLayer::load_effects() void CharLayer::load_network_effects() { movie_effects.clear(); + if (max_frames <= 1) + return; movie_effects.resize(max_frames); // Order is important!!! QStringList effects_list = {"shake", "flash", "sfx^"}; @@ -525,6 +484,7 @@ void AOLayer::stop() // do we want a frozen gif to display this->freeze(); this->hide(); + shfx_timer->stop(); } void AOLayer::freeze() @@ -532,7 +492,6 @@ void AOLayer::freeze() // aT nO pOiNt Do We WaNt A fRoZeN gIf To DiSpLaY ticker->stop(); preanim_timer->stop(); - shfx_timer->stop(); } void CharLayer::movie_ticker() @@ -544,7 +503,7 @@ void CharLayer::movie_ticker() void AOLayer::movie_ticker() { ++frame; - if ((frame >= max_frames) && (max_frames > 1)) { + if (frame >= max_frames) { if (play_once) { if (cull_image) this->stop(); diff --git a/src/aooptionsdialog.cpp b/src/aooptionsdialog.cpp index 36a6f06..dfd8555 100644 --- a/src/aooptionsdialog.cpp +++ b/src/aooptionsdialog.cpp @@ -81,17 +81,55 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) ui_theme_combobox->addItem(actualname); } + QObject::connect(ui_theme_combobox, SIGNAL(currentIndexChanged(int)), this, + SLOT(theme_changed(int))); ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_theme_combobox); + row += 1; + + ui_subtheme_label = new QLabel(ui_form_layout_widget); + ui_subtheme_label->setText(tr("Subtheme:")); + ui_subtheme_label->setToolTip( + tr("Sets a 'subtheme', which will stack on top of the current theme and replace anything it can." + "Keep it at 'server' to let the server decide. Keep it at 'default' to keep it unchanging.")); + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_subtheme_label); + ui_subtheme_combobox = new QComboBox(ui_form_layout_widget); + + // Fill the combobox with the names of the themes. + ui_subtheme_combobox->addItem("server"); + ui_subtheme_combobox->addItem("default"); + QDirIterator it2(ao_app->get_base_path() + "themes/" + ao_app->current_theme, QDir::Dirs, + QDirIterator::NoIteratorFlags); + while (it2.hasNext()) { + QString actualname = QDir(it2.next()).dirName(); + if (actualname != "." && actualname != ".." && actualname.toLower() != "server" && actualname.toLower() != "default" && actualname.toLower() != "effects" && actualname.toLower() != "misc") + ui_subtheme_combobox->addItem(actualname); + } + + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_subtheme_combobox); + + row += 1; + ui_theme_reload_button = new QPushButton(ui_form_layout_widget); ui_theme_reload_button->setText(tr("Reload Theme")); ui_theme_reload_button->setToolTip( tr("Refresh the theme and update all of the ui elements to match.")); - row += 1; ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_theme_reload_button); QObject::connect(ui_theme_reload_button, SIGNAL(clicked()), this, SLOT(on_reload_theme_clicked())); + row += 1; + ui_animated_theme_lbl = new QLabel(ui_form_layout_widget); + ui_animated_theme_lbl->setText(tr("Animated Theme:")); + ui_animated_theme_lbl->setToolTip( + tr("If ticked, themes will be allowed to have animated elements.")); + + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_animated_theme_lbl); + + ui_animated_theme_cb = new QCheckBox(ui_form_layout_widget); + + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_animated_theme_cb); + row += 1; ui_theme_log_divider = new QFrame(ui_form_layout_widget); ui_theme_log_divider->setMidLineWidth(0); @@ -837,11 +875,21 @@ void AOOptionsDialog::update_values() { break; } } + QString subtheme = + ao_app->configini->value("subtheme").value(); + for (int i = 0; i < ui_subtheme_combobox->count(); ++i) { + if (ui_subtheme_combobox->itemText(i) == subtheme) + { + ui_subtheme_combobox->setCurrentIndex(i); + break; + } + } // Let's fill the callwords text edit with the already present callwords. ui_callwords_textbox->document()->clear(); foreach (QString callword, ao_app->get_call_words()) { ui_callwords_textbox->appendPlainText(callword); } + ui_animated_theme_cb->setChecked(ao_app->get_animated_theme()); ui_ms_textbox->setText(ao_app->configini->value("master", "").value()); ui_casing_cm_cases_textbox->setText(ao_app->get_casing_can_host_cases()); ui_username_textbox->setText(ao_app->get_default_username()); @@ -894,6 +942,8 @@ void AOOptionsDialog::save_pressed() ao_app->get_audio_output_device(); configini->setValue("theme", ui_theme_combobox->currentText()); + configini->setValue("subtheme", ui_subtheme_combobox->currentText()); + configini->setValue("animated_theme", ui_animated_theme_cb->isChecked()); 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()); @@ -991,12 +1041,29 @@ void AOOptionsDialog::button_clicked(QAbstractButton *button) { void AOOptionsDialog::on_reload_theme_clicked() { ao_app->configini->setValue("theme", ui_theme_combobox->currentText()); + ao_app->configini->setValue("subtheme", ui_subtheme_combobox->currentText()); + ao_app->configini->setValue("animated_theme", ui_animated_theme_cb->isChecked()); if (ao_app->courtroom_constructed) ao_app->w_courtroom->on_reload_theme_clicked(); if (ao_app->lobby_constructed) ao_app->w_lobby->set_widgets(); } +void AOOptionsDialog::theme_changed(int i) { + ui_subtheme_combobox->clear(); + // Fill the combobox with the names of the themes. + ui_subtheme_combobox->addItem("server"); + ui_subtheme_combobox->addItem("default"); + QDirIterator it(ao_app->get_base_path() + "themes/" + ui_theme_combobox->itemText(i), QDir::Dirs, + QDirIterator::NoIteratorFlags); + while (it.hasNext()) { + QString actualname = QDir(it.next()).dirName(); + if (actualname != "." && actualname != ".." && actualname.toLower() != "server" && actualname.toLower() != "default" && actualname.toLower() != "effects" && actualname.toLower() != "misc") + ui_subtheme_combobox->addItem(actualname); + } + +} + #if (defined(_WIN32) || defined(_WIN64)) bool AOOptionsDialog::needs_default_audiodev() { return true; } #elif (defined(LINUX) || defined(__linux__)) diff --git a/src/aosfxplayer.cpp b/src/aosfxplayer.cpp index 13de04f..000b6a7 100644 --- a/src/aosfxplayer.cpp +++ b/src/aosfxplayer.cpp @@ -24,7 +24,7 @@ void AOSfxPlayer::loop_clear() set_volume_internal(m_volume); } -void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout) +void AOSfxPlayer::play(QString p_sfx, QString p_character, QString p_misc) { for (int i = 0; i < m_channelmax; ++i) { if (BASS_ChannelIsActive(m_stream_list[i]) == BASS_ACTIVE_PLAYING) @@ -34,42 +34,14 @@ void AOSfxPlayer::play(QString p_sfx, QString p_char, QString shout) break; } } - - QString misc_path = ""; - QString char_path = ""; - QString theme_path = ""; - QString sound_path = ao_app->get_sfx_suffix(ao_app->get_sounds_path(p_sfx)); - - if (shout != "") { - misc_path = ao_app->get_sfx_suffix(ao_app->get_base_path() + "misc/" + - shout + "/" + p_sfx); - theme_path = ao_app->get_sfx_suffix(ao_app->get_theme_path(p_sfx)); - if (!file_exists(theme_path)) - theme_path = - ao_app->get_sfx_suffix(ao_app->get_default_theme_path(p_sfx)); - } - if (p_char != "") - char_path = - ao_app->get_sfx_suffix(ao_app->get_character_path(p_char, p_sfx)); - - QString f_path; - - if (file_exists(char_path)) - f_path = char_path; - else if (file_exists(misc_path)) - f_path = misc_path; - else if (shout != "" && file_exists(theme_path)) // only check here for shouts - f_path = theme_path; - else - f_path = sound_path; - - if (f_path.endsWith(".opus")) + QString path = ao_app->get_sfx(p_sfx, p_misc, p_character); + if (path.endsWith(".opus")) m_stream_list[m_channel] = BASS_OPUS_StreamCreateFile( - FALSE, f_path.utf16(), 0, 0, + FALSE, path.utf16(), 0, 0, BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE); else m_stream_list[m_channel] = BASS_StreamCreateFile( - FALSE, f_path.utf16(), 0, 0, + FALSE, path.utf16(), 0, 0, BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE); set_volume_internal(m_volume); diff --git a/src/charselect.cpp b/src/charselect.cpp index bdd951c..4f3ba99 100644 --- a/src/charselect.cpp +++ b/src/charselect.cpp @@ -252,7 +252,7 @@ void Courtroom::character_loading_finished() // create the character tree item QTreeWidgetItem *treeItem = new QTreeWidgetItem(); treeItem->setText(0, char_list.at(n).name); - treeItem->setIcon(0, QIcon(ao_app->get_static_image_suffix( + treeItem->setIcon(0, QIcon(ao_app->get_image_suffix( ao_app->get_character_path(char_list.at(n).name, "char_icon")))); treeItem->setText(1, QString::number(n)); // category logic diff --git a/src/courtroom.cpp b/src/courtroom.cpp index d03bf23..19a00c5 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -476,6 +476,9 @@ void Courtroom::set_pair_list() void Courtroom::set_widgets() { QString filename = "courtroom_design.ini"; + // Update the default theme from the courtroom_design.ini, if it's not defined it will be 'default'. + QSettings settings(ao_app->get_theme_path(filename, ao_app->current_theme), QSettings::IniFormat); + ao_app->default_theme = settings.value("default_theme", "default").toString(); pos_size_type f_courtroom = ao_app->get_element_dimensions("courtroom", filename); @@ -644,13 +647,13 @@ void Courtroom::set_widgets() set_size_and_pos(ui_music_list, "music_list"); ui_music_list->header()->setMinimumSectionSize(ui_music_list->width()); - QString music_list_indentation = ao_app->get_font_name("music_list_indent", "courtroom_design.ini"); + QString music_list_indentation = ao_app->get_design_element("music_list_indent", "courtroom_design.ini"); if (music_list_indentation == "") ui_music_list->resetIndentation(); else ui_music_list->setIndentation(music_list_indentation.toInt()); - QString music_list_animated = ao_app->get_font_name("music_list_animated", "courtroom_design.ini"); + QString music_list_animated = ao_app->get_design_element("music_list_animated", "courtroom_design.ini"); if (music_list_animated == "1") ui_music_list->setAnimated(true); else @@ -1053,12 +1056,12 @@ void Courtroom::set_font(QWidget *widget, QString class_name, QString design_file = "courtroom_fonts.ini"; if (f_pointsize <= 0) f_pointsize = - ao_app->get_design_element(p_identifier, design_file, p_char).toInt(); + ao_app->get_design_element(p_identifier, design_file, ao_app->get_chat(p_char)).toInt(); if (font_name == "") font_name = - ao_app->get_design_element(p_identifier + "_font", design_file, p_char); + ao_app->get_design_element(p_identifier + "_font", design_file, ao_app->get_chat(p_char)); QString f_color_result = - ao_app->get_design_element(p_identifier + "_color", design_file, p_char); + ao_app->get_design_element(p_identifier + "_color", design_file, ao_app->get_chat(p_char)); QColor f_color(0, 0, 0); if (f_color_result != "") { QStringList color_list = f_color_result.split(","); @@ -1070,10 +1073,10 @@ void Courtroom::set_font(QWidget *widget, QString class_name, } } bool bold = - ao_app->get_design_element(p_identifier + "_bold", design_file, p_char) == + ao_app->get_design_element(p_identifier + "_bold", design_file, ao_app->get_chat(p_char)) == "1"; // is the font bold or not? bool antialias = ao_app->get_design_element(p_identifier + "_sharp", - design_file, p_char) != + design_file, ao_app->get_chat(p_char)) != "1"; // is the font anti-aliased or not? this->set_qfont(widget, class_name, @@ -2095,7 +2098,7 @@ void Courtroom::log_chatmessage(QString f_message, int f_char_id, QString f_show } QString f_char = m_chatmessage[CHAR_NAME]; - QString f_custom_theme = ao_app->get_char_shouts(f_char); + QString f_custom_theme = ao_app->get_chat(f_char); if (objection_mod <= 4 && objection_mod >= 1) { QString shout_message; switch (objection_mod) { @@ -2215,19 +2218,19 @@ bool Courtroom::handle_objection() case 1: filename = "holdit_bubble"; objection_player->play("holdit", m_chatmessage[CHAR_NAME], - ao_app->get_char_shouts(m_chatmessage[CHAR_NAME])); + ao_app->get_chat(m_chatmessage[CHAR_NAME])); break; case 2: filename = "objection_bubble"; objection_player->play("objection", m_chatmessage[CHAR_NAME], - ao_app->get_char_shouts(m_chatmessage[CHAR_NAME])); + ao_app->get_chat(m_chatmessage[CHAR_NAME])); if (ao_app->objection_stop_music()) music_player->stop(); break; case 3: filename = "takethat_bubble"; objection_player->play("takethat", m_chatmessage[CHAR_NAME], - ao_app->get_char_shouts(m_chatmessage[CHAR_NAME])); + ao_app->get_chat(m_chatmessage[CHAR_NAME])); break; // case 4 is AO2 only case 4: @@ -2236,20 +2239,20 @@ bool Courtroom::handle_objection() objection_player->play( "custom_objections/" + custom_objection.split('.')[0], m_chatmessage[CHAR_NAME], - ao_app->get_char_shouts(m_chatmessage[CHAR_NAME])); + ao_app->get_chat(m_chatmessage[CHAR_NAME])); } else { filename = "custom"; objection_player->play( "custom", m_chatmessage[CHAR_NAME], - ao_app->get_char_shouts(m_chatmessage[CHAR_NAME])); + ao_app->get_chat(m_chatmessage[CHAR_NAME])); } break; m_chatmessage[EMOTE_MOD] = 1; } ui_vp_objection->load_image( filename, m_chatmessage[CHAR_NAME], - ao_app->get_char_shouts(m_chatmessage[CHAR_NAME])); + ao_app->get_chat(m_chatmessage[CHAR_NAME])); sfx_player->clear(); // Objection played! Cut all sfx. return true; } @@ -2490,7 +2493,7 @@ void Courtroom::do_flash() return; QString f_char = m_chatmessage[CHAR_NAME]; - QString f_custom_theme = ao_app->get_char_shouts(f_char); + QString f_custom_theme = ao_app->get_chat(f_char); ui_vp_effect->stretch = true; ui_vp_effect->set_static_duration(60); ui_vp_effect->set_max_duration(60); @@ -2502,7 +2505,8 @@ void Courtroom::do_flash() void Courtroom::do_effect(QString fx_name, QString fx_sound, QString p_char, QString p_folder) { - + if (fx_name == "") + return; QString effect = ao_app->get_effect(fx_name, p_char, p_folder); if (effect == "") return; @@ -2554,38 +2558,20 @@ void Courtroom::initialize_chatbox() QString customchar; if (ao_app->is_customchat_enabled()) customchar = m_chatmessage[CHAR_NAME]; + QString p_misc = ao_app->get_chat(customchar); if (ui_vp_showname->text().trimmed().isEmpty()) // Whitespace showname { - ui_vp_chatbox->set_image("chatblank"); + ui_vp_chatbox->set_image("chatblank", p_misc); } else // Aw yeah dude do some showname magic { - if (!ui_vp_chatbox->set_image("chat")) - ui_vp_chatbox->set_image("chatbox"); - - QFontMetrics fm(ui_vp_showname->font()); -// Gotta support the slow paced ubuntu 18 STUCK IN 5.9.5!! -#if QT_VERSION > QT_VERSION_CHECK(5, 11, 0) - int fm_width = fm.horizontalAdvance(ui_vp_showname->text()); -#else - int fm_width = fm.boundingRect((ui_vp_showname->text())).width(); -#endif - QString chatbox_path = ao_app->get_theme_path("chat"); - QString chatbox = ao_app->get_chat(customchar); - - if (chatbox != "" && ao_app->is_customchat_enabled()) { - chatbox_path = ao_app->get_theme_path("misc/" + chatbox + "/chat"); - if (!ui_vp_chatbox->set_chatbox(chatbox_path)) { - chatbox_path = ao_app->get_base_path() + "misc/" + chatbox + "/chat"; - if (!ui_vp_chatbox->set_chatbox(chatbox_path)) - ui_vp_chatbox->set_chatbox(chatbox_path + "box"); - } - } + if (!ui_vp_chatbox->set_image("chat", p_misc)) + ui_vp_chatbox->set_image("chatbox", p_misc); // This should probably be called only if any change from the last chat // arrow was actually detected. pos_size_type design_ini_result = ao_app->get_element_dimensions( - "chat_arrow", "courtroom_design.ini", customchar); + "chat_arrow", "courtroom_design.ini", p_misc); if (design_ini_result.width < 0 || design_ini_result.height < 0) { qDebug() << "W: could not find \"chat_arrow\" in courtroom_design.ini"; ui_vp_chat_arrow->hide(); @@ -2596,16 +2582,19 @@ void Courtroom::initialize_chatbox() design_ini_result.height); } + // Remember to set the showname font before the font metrics check. + set_font(ui_vp_showname, "", "showname", customchar); + pos_size_type default_width = ao_app->get_element_dimensions( - "showname", "courtroom_design.ini", customchar); + "showname", "courtroom_design.ini", p_misc); int extra_width = ao_app ->get_design_element("showname_extra_width", "courtroom_design.ini", - customchar) + p_misc) .toInt(); QString align = ao_app ->get_design_element("showname_align", - "courtroom_design.ini", customchar) + "courtroom_design.ini", p_misc) .toLower(); if (align == "right") ui_vp_showname->setAlignment(Qt::AlignRight); @@ -2616,17 +2605,23 @@ void Courtroom::initialize_chatbox() else ui_vp_showname->setAlignment(Qt::AlignLeft); + QFontMetrics fm(ui_vp_showname->font()); +// Gotta support the slow paced ubuntu 18 STUCK IN 5.9.5!! +#if QT_VERSION > QT_VERSION_CHECK(5, 11, 0) + int fm_width = fm.horizontalAdvance(ui_vp_showname->text()); +#else + int fm_width = fm.boundingRect((ui_vp_showname->text())).width(); +#endif if (extra_width > 0) { + QString current_path = ui_vp_chatbox->path.left(ui_vp_chatbox->path.lastIndexOf('.')); if (fm_width > default_width.width && - ui_vp_chatbox->set_chatbox( - chatbox_path + + ui_vp_chatbox->set_image(current_path + "med")) // This text be big. Let's do some shenanigans. { ui_vp_showname->resize(default_width.width + extra_width, ui_vp_showname->height()); if (fm_width > ui_vp_showname->width() && - ui_vp_chatbox->set_chatbox(chatbox_path + - "big")) // Biggest possible size for us. + ui_vp_chatbox->set_image(current_path + "big")) // Biggest possible size for us. { ui_vp_showname->resize( static_cast(default_width.width + (extra_width * 2)), @@ -2635,8 +2630,6 @@ void Courtroom::initialize_chatbox() } else ui_vp_showname->resize(default_width.width, ui_vp_showname->height()); - - set_font(ui_vp_showname, "", "showname", customchar); } else { ui_vp_showname->resize(default_width.width, ui_vp_showname->height()); @@ -2666,7 +2659,7 @@ void Courtroom::handle_callwords() // If our message contains that specific call word if (f_message.contains(word, Qt::CaseInsensitive)) { // Play the call word sfx on the modcall_player sound container - modcall_player->play(ao_app->get_sfx("word_call")); + modcall_player->play(ao_app->get_court_sfx("word_call")); // Make the window flash ao_app->alert(this); // Break the loop so we don't spam sound effects @@ -2709,7 +2702,7 @@ void Courtroom::handle_ic_speaking() filename = "prosecution_speedlines"; else filename = "defense_speedlines"; - ui_vp_speedlines->load_image(filename, m_chatmessage[CHAR_NAME], ao_app->get_char_shouts(m_chatmessage[CHAR_NAME])); + ui_vp_speedlines->load_image(filename, m_chatmessage[CHAR_NAME], ao_app->get_chat(m_chatmessage[CHAR_NAME])); } // Check if this is a talking color (white text, etc.) @@ -3214,7 +3207,6 @@ void Courtroom::preanim_done() set_scene(m_chatmessage[DESK_MOD], m_chatmessage[SIDE]); break; } - qDebug() << "preanim over, anim_state set to 1"; handle_ic_speaking(); } @@ -3281,9 +3273,9 @@ void Courtroom::start_chat_ticking() chat_tick_timer->start(0); // Display the first char right away last_misc = current_misc; - current_misc = ao_app->get_char_shouts(m_chatmessage[CHAR_NAME]); - if (last_misc != current_misc) - gen_char_rgb_list(m_chatmessage[CHAR_NAME]); + current_misc = ao_app->get_chat(m_chatmessage[CHAR_NAME]); + if (last_misc != current_misc || char_color_rgb_list.size() < max_colors) + gen_char_rgb_list(current_misc); QString f_blips = ao_app->get_blips(m_chatmessage[CHAR_NAME]); blip_player->set_blips(f_blips); @@ -3805,31 +3797,44 @@ void Courtroom::handle_wtce(QString p_wtce, int variant) ui_vp_wtce->set_max_duration(wtce_max_time); // witness testimony if (p_wtce == "testimony1") { - sfx_name = "witness_testimony"; + // End testimony indicator + if (variant == 1) { + ui_vp_testimony->stop(); + return; + } + sfx_name = ao_app->get_court_sfx("witnesstestimony", bg_misc); filename = "witnesstestimony"; ui_vp_testimony->load_image("testimony", "", bg_misc); } // cross examination else if (p_wtce == "testimony2") { - sfx_name = "cross_examination"; + sfx_name = ao_app->get_court_sfx("crossexamination", bg_misc); filename = "crossexamination"; ui_vp_testimony->stop(); } - else if (p_wtce == "judgeruling") { + else { ui_vp_wtce->set_static_duration(verdict_static_time); ui_vp_wtce->set_max_duration(verdict_max_time); - if (variant == 0) { - sfx_name = "not_guilty"; - filename = "notguilty"; - ui_vp_testimony->stop(); + // Verdict? + if (p_wtce == "judgeruling") { + if (variant == 0) { + sfx_name = ao_app->get_court_sfx("notguilty", bg_misc); + filename = "notguilty"; + ui_vp_testimony->stop(); + } + else if (variant == 1) { + sfx_name = ao_app->get_court_sfx("guilty", bg_misc); + filename = "guilty"; + ui_vp_testimony->stop(); + } } - else if (variant == 1) { - sfx_name = "guilty"; - filename = "guilty"; - ui_vp_testimony->stop(); + // Completely custom WTCE + else { + sfx_name = p_wtce; + filename = p_wtce; } } - sfx_player->play(ao_app->get_sfx(sfx_name, bg_misc)); + sfx_player->play(sfx_name); ui_vp_wtce->load_image(filename, "", bg_misc); ui_vp_wtce->set_play_once(true); } @@ -3877,7 +3882,7 @@ void Courtroom::mod_called(QString p_ip) { ui_server_chatlog->append(p_ip); if (!ui_guard->isChecked()) { - modcall_player->play(ao_app->get_sfx("mod_call")); + modcall_player->play(ao_app->get_court_sfx("mod_call")); ao_app->alert(this); } } @@ -3892,7 +3897,7 @@ void Courtroom::case_called(QString msg, bool def, bool pro, bool jud, bool jur, (ao_app->get_casing_judge_enabled() && jud) || (ao_app->get_casing_juror_enabled() && jur) || (ao_app->get_casing_steno_enabled() && steno)) { - modcall_player->play(ao_app->get_sfx("case_call")); + modcall_player->play(ao_app->get_court_sfx("case_call")); ao_app->alert(this); } } @@ -4550,14 +4555,14 @@ void Courtroom::set_effects_dropdown() QString custom_path = ao_app->get_base_path() + "misc/" + p_effect + "/icons/"; QString theme_path = ao_app->get_theme_path("effects/icons/"); - QString default_path = ao_app->get_default_theme_path("effects/icons/"); + QString default_path = ao_app->get_theme_path("effects/icons/", "default"); for (int i = 0; i < ui_effects_dropdown->count(); ++i) { QString entry = ui_effects_dropdown->itemText(i); - QString iconpath = ao_app->get_static_image_suffix(custom_path + entry); + QString iconpath = ao_app->get_image_suffix(custom_path + entry); if (!file_exists(iconpath)) { - iconpath = ao_app->get_static_image_suffix(theme_path + entry); + iconpath = ao_app->get_image_suffix(theme_path + entry); if (!file_exists(iconpath)) { - iconpath = ao_app->get_static_image_suffix(default_path + entry); + iconpath = ao_app->get_image_suffix(default_path + entry); if (!file_exists(iconpath)) continue; } @@ -4588,7 +4593,7 @@ void Courtroom::on_effects_edit_requested() { QString p_path = ao_app->get_theme_path("effects/"); if (!dir_exists(p_path)) { - p_path = ao_app->get_default_theme_path("effects/"); + p_path = ao_app->get_theme_path("effects/", "default"); if (!dir_exists(p_path)) { return; } @@ -5091,21 +5096,21 @@ void Courtroom::set_text_color_dropdown() // config file once instead of several times for (int c = 0; c < max_colors; ++c) { QColor color = - ao_app->get_chat_color("c" + QString::number(c), current_char); + ao_app->get_chat_color("c" + QString::number(c), ao_app->get_chat(current_char)); color_rgb_list.append(color); color_markdown_start_list.append(ao_app->get_chat_markup( - "c" + QString::number(c) + "_start", current_char)); + "c" + QString::number(c) + "_start", ao_app->get_chat(current_char))); color_markdown_end_list.append(ao_app->get_chat_markup( - "c" + QString::number(c) + "_end", current_char)); + "c" + QString::number(c) + "_end", ao_app->get_chat(current_char))); color_markdown_remove_list.append( ao_app->get_chat_markup("c" + QString::number(c) + "_remove", - current_char) == "1"); + ao_app->get_chat(current_char)) == "1"); color_markdown_talking_list.append( ao_app->get_chat_markup("c" + QString::number(c) + "_talking", - current_char) != "0"); + ao_app->get_chat(current_char)) != "0"); QString color_name = ao_app->get_chat_markup( - "c" + QString::number(c) + "_name", current_char); + "c" + QString::number(c) + "_name", ao_app->get_chat(current_char)); if (color_name.isEmpty()) // Not defined { if (c > 0) @@ -5124,10 +5129,10 @@ void Courtroom::set_text_color_dropdown() } } -void Courtroom::gen_char_rgb_list(QString p_char) { +void Courtroom::gen_char_rgb_list(QString p_misc) { char_color_rgb_list.clear(); for (int c = 0; c < max_colors; ++c) { - QColor color = ao_app->get_chat_color("c" + QString::number(c), p_char); + QColor color = ao_app->get_chat_color("c" + QString::number(c), p_misc); char_color_rgb_list.append(color); } } diff --git a/src/lobby.cpp b/src/lobby.cpp index 39ddfa3..314874e 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -244,7 +244,7 @@ void Lobby::set_font(QWidget *widget, QString p_identifier) int f_weight = ao_app->get_font_size(p_identifier, design_file); QString class_name = widget->metaObject()->className(); QString font_name = - ao_app->get_font_name(p_identifier + "_font", design_file); + ao_app->get_design_element(p_identifier + "_font", design_file); QFont font(font_name, f_weight); bool use = ao_app->get_font_size("use_custom_fonts", design_file) == 1; if (use) { diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index 53f6deb..1c88120 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -663,6 +663,23 @@ void AOApplication::server_packet_received(AOPacket *p_packet) if (ping_time != -1) latency = ping_time; } + // Subtheme packet + else if (header == "ST") { + if (!courtroom_constructed) + goto end; + // Subtheme reserved as argument 0 + subtheme = f_contents.at(0); + + // Check if we have subthemes set to "server" + QString p_st = configini->value("subtheme").value(); + if (p_st.toLower() != "server") + // We don't. Simply acknowledge the subtheme sent by the server, but don't do anything else. + return; + + // Reload theme request + if (f_contents.size() > 1 && f_contents.at(1) == "1") + w_courtroom->on_reload_theme_clicked(); + } end: diff --git a/src/path_functions.cpp b/src/path_functions.cpp index 728f5a4..5107349 100644 --- a/src/path_functions.cpp +++ b/src/path_functions.cpp @@ -41,24 +41,14 @@ QString AOApplication::get_base_path() QString AOApplication::get_data_path() { return get_base_path() + "data/"; } -QString AOApplication::get_default_theme_path(QString p_file) -{ - QString path = get_base_path() + "themes/default/" + p_file; - return get_case_sensitive_path(path); -} - -QString AOApplication::get_custom_theme_path(QString p_theme, QString p_file) +QString AOApplication::get_theme_path(QString p_file, QString p_theme) { + if (p_theme == "") + p_theme = current_theme; QString path = get_base_path() + "themes/" + p_theme + "/" + p_file; return get_case_sensitive_path(path); } -QString AOApplication::get_theme_path(QString p_file) -{ - QString path = get_base_path() + "themes/" + current_theme + "/" + p_file; - return get_case_sensitive_path(path); -} - QString AOApplication::get_character_path(QString p_char, QString p_file) { QString path = get_base_path() + "characters/" + p_char + "/" + p_file; @@ -112,18 +102,119 @@ QString AOApplication::get_evidence_path(QString p_file) return get_case_sensitive_path(path); } +QStringList AOApplication::get_asset_paths(QString p_element, QString p_theme, QString p_subtheme, QString p_default_theme, QString p_misc, QString p_character, QString p_placeholder) +{ + QStringList pathlist; + pathlist += p_element; // The path by itself + if (p_character != "") + pathlist += get_character_path(p_character, p_element); // Character folder + if (p_misc != "" && p_theme != "" && p_subtheme != "") + pathlist += get_theme_path("misc/" + p_misc + "/" + p_element, p_theme + "/" + p_subtheme); // Subtheme misc path + if (p_misc != "" && p_theme != "") + pathlist += get_theme_path("misc/" + p_misc + "/" + p_element, p_theme); // Theme misc path + if (p_theme != "" && p_subtheme != "") + pathlist += get_theme_path(p_element, p_theme + "/" + p_subtheme); // Subtheme path + if (p_misc != "") + pathlist += get_misc_path(p_misc, p_element); // Base misc path + if (p_theme != "") + pathlist += get_theme_path(p_element, p_theme); // Theme path + if (p_default_theme != "") + pathlist += get_theme_path(p_element, p_default_theme); // Default theme path + if (p_placeholder != "" && p_theme != "") + pathlist += get_theme_path(p_placeholder, p_theme); // Placeholder path + if (p_placeholder != "" && p_default_theme != "") + pathlist += get_theme_path(p_placeholder, p_default_theme); // Default placeholder path + return pathlist; +} + +QString AOApplication::get_asset_path(QStringList pathlist) +{ + QString path; + for (QString p : pathlist) { + p = get_case_sensitive_path(p); + if (file_exists(p)) { + path = p; + break; + } + } + return path; +} + +QString AOApplication::get_image_path(QStringList pathlist, bool static_image) +{ + QString path; + for (QString p : pathlist) { + p = get_case_sensitive_path(get_image_suffix(p, static_image)); + if (file_exists(p)) { + path = p; + break; + } + } + return path; +} + +QString AOApplication::get_sfx_path(QStringList pathlist) +{ + QString path; + for (QString p : pathlist) { + p = get_case_sensitive_path(get_sfx_suffix(p)); + if (file_exists(p)) { + path = p; + break; + } + } + return path; +} +QString AOApplication::get_config_value(QString p_identifier, QString p_config, QString p_theme, QString p_subtheme, QString p_default_theme, QString p_misc) +{ + QString path; +// qDebug() << "got request for" << p_identifier << "in" << p_config; + for (QString p : get_asset_paths(p_config, p_theme, p_subtheme, p_default_theme, p_misc)) { + p = get_case_sensitive_path(p); + if (file_exists(p)) { + QSettings settings(p, QSettings::IniFormat); + QVariant value = settings.value(p_identifier); + if (value.type() == QVariant::StringList) { +// qDebug() << "got" << p << "is a string list, returning" << value.toStringList().join(","); + return value.toStringList().join(","); + } + else if (!value.isNull()){ +// qDebug() << "got" << p << "is a string, returning" << value.toString(); + return value.toString(); + } + } + } + return ""; +} + +QString AOApplication::get_asset(QString p_element, QString p_theme, QString p_subtheme, QString p_default_theme, QString p_misc, QString p_character, QString p_placeholder) +{ + return get_asset_path(get_asset_paths(p_element, p_theme, p_subtheme, p_default_theme, p_misc, p_character, p_placeholder)); +} + +QString AOApplication::get_image(QString p_element, QString p_theme, QString p_subtheme, QString p_default_theme, QString p_misc, QString p_character, QString p_placeholder) +{ + return get_image_path(get_asset_paths(p_element, p_theme, p_subtheme, p_default_theme, p_misc, p_character, p_placeholder)); +} + +QString AOApplication::get_sfx(QString p_sfx, QString p_misc, QString p_character) +{ + QStringList pathlist = get_asset_paths(p_sfx, current_theme, get_subtheme(), default_theme, p_misc, p_character); + pathlist += get_sounds_path(p_sfx); // Sounds folder path + return get_sfx_path(pathlist); +} + QString AOApplication::get_case_sensitive_path(QString p_file) { - QFileInfo file(p_file); - QString file_basename = file.fileName(); - // no path traversal above base folder - if (!(file.absolutePath().startsWith(get_base_path()))) - return get_base_path() + file_basename; + if (!(p_file.startsWith(get_base_path()))) + return get_base_path() + p_file; #ifdef CASE_SENSITIVE_FILESYSTEM // first, check to see if it's actually there (also serves as base case for // recursion) + QFileInfo file(p_file); + QString file_basename = file.fileName(); if (exists(p_file)) return p_file; diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index cc28628..919657c 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -281,9 +281,10 @@ QString AOApplication::read_design_ini(QString p_identifier, if (value.type() == QVariant::StringList) { return value.toStringList().join(","); } - else { + else if (!value.isNull()) { return value.toString(); } + return ""; } Qt::TransformationMode AOApplication::get_scaling(QString p_scaling) @@ -295,23 +296,16 @@ Qt::TransformationMode AOApplication::get_scaling(QString p_scaling) QPoint AOApplication::get_button_spacing(QString p_identifier, QString p_file) { - QString design_ini_path = get_theme_path(p_file); - QString default_path = get_default_theme_path(p_file); - QString f_result = read_design_ini(p_identifier, design_ini_path); - + QString value = get_config_value(p_identifier, p_file, current_theme, get_subtheme(), default_theme); QPoint return_value; return_value.setX(0); return_value.setY(0); - if (f_result == "") { - f_result = read_design_ini(p_identifier, default_path); + if (value == "") + return return_value; - if (f_result == "") - return return_value; - } - - QStringList sub_line_elements = f_result.split(","); + QStringList sub_line_elements = value.split(","); if (sub_line_elements.size() < 2) return return_value; @@ -346,63 +340,32 @@ pos_size_type AOApplication::get_element_dimensions(QString p_identifier, return return_value; } QString AOApplication::get_design_element(QString p_identifier, QString p_file, - QString p_char) + QString p_misc) { - QStringList paths{get_theme_path("misc/" + get_chat(p_char) + "/" + - p_file), // user theme overrides base/misc - get_base_path() + "misc/" + get_chat(p_char) + "/" + p_file, - get_theme_path(p_file), get_default_theme_path(p_file)}; - for (const QString &path : paths) { - QString value = read_design_ini(p_identifier, path); - if (!value.isEmpty()) - return value; - } + QString value = get_config_value(p_identifier, p_file, current_theme, get_subtheme(), default_theme, p_misc); + if (!value.isEmpty()) + return value; return ""; } -QString AOApplication::get_font_name(QString p_identifier, QString p_file) -{ - QString design_ini_path = get_theme_path(p_file); - QString f_result = read_design_ini(p_identifier, design_ini_path); - QString default_path = get_default_theme_path(p_file); - if (f_result == "") { - f_result = read_design_ini(p_identifier, default_path); - if (f_result == "") - return ""; - } - return f_result; -} + +// tfw this function is only used for lobby and nowhere else int AOApplication::get_font_size(QString p_identifier, QString p_file) { - QString design_ini_path = get_theme_path(p_file); - QString default_path = get_default_theme_path(p_file); - QString f_result = read_design_ini(p_identifier, design_ini_path); - - if (f_result == "") { - f_result = read_design_ini(p_identifier, default_path); - - if (f_result == "") - return 10; - } - - return f_result.toInt(); + QString value = get_config_value(p_identifier, p_file, current_theme, get_subtheme(), default_theme); + if (!value.isEmpty()) + return value.toInt(); + return 10; } QColor AOApplication::get_color(QString p_identifier, QString p_file) { - QString design_ini_path = get_theme_path(p_file); - QString default_path = get_default_theme_path(p_file); - QString f_result = read_design_ini(p_identifier, design_ini_path); - + QString value = get_config_value(p_identifier, p_file, current_theme, get_subtheme(), default_theme); QColor return_color(0, 0, 0); - if (f_result == "") { - f_result = read_design_ini(p_identifier, default_path); + if (value.isEmpty()) + return return_color; - if (f_result == "") - return return_color; - } - - QStringList color_list = f_result.split(","); + QStringList color_list = value.split(","); if (color_list.size() < 3) return return_color; @@ -416,18 +379,11 @@ QColor AOApplication::get_color(QString p_identifier, QString p_file) QString AOApplication::get_stylesheet(QString p_file) { - QString design_ini_path = get_theme_path(p_file); - QString default_path = get_default_theme_path(p_file); - + QString path = get_asset(p_file, current_theme, get_subtheme(), default_theme); QFile design_ini; - - design_ini.setFileName(design_ini_path); - - if (!design_ini.open(QIODevice::ReadOnly)) { - design_ini.setFileName(default_path); - if (!design_ini.open(QIODevice::ReadOnly)) - return ""; - } + design_ini.setFileName(path); + if (!design_ini.open(QIODevice::ReadOnly)) + return ""; QTextStream in(&design_ini); @@ -443,12 +399,9 @@ QString AOApplication::get_stylesheet(QString p_file) QString AOApplication::get_tagged_stylesheet(QString target_tag, QString p_file) { - QString design_ini_path = get_theme_path(p_file); - + QString path = get_asset(p_file, current_theme, get_subtheme(), default_theme); QFile design_ini; - - design_ini.setFileName(design_ini_path); - + design_ini.setFileName(path); if (!design_ini.open(QIODevice::ReadOnly)) return ""; @@ -479,14 +432,19 @@ QString AOApplication::get_tagged_stylesheet(QString target_tag, QString p_file) QString AOApplication::get_chat_markup(QString p_identifier, QString p_chat) { - QStringList paths{get_theme_path("misc/" + get_chat(p_chat) + "/config.ini"), - get_base_path() + "misc/" + get_chat(p_chat) + + // New Chadly method + QString value = get_config_value(p_identifier, "chat_config.ini", current_theme, get_subtheme(), default_theme, p_chat); + if (!value.isEmpty()) + return value.toLatin1(); + + // Backwards ass compatibility + QStringList backwards_paths{get_theme_path("misc/" + p_chat + "/config.ini"), + get_base_path() + "misc/" + p_chat + "/config.ini", get_base_path() + "misc/default/config.ini", get_theme_path("misc/default/config.ini")}; - - for (const QString &path : paths) { - QString value = read_design_ini(p_identifier, path); + for (const QString &p : backwards_paths) { + QString value = read_design_ini(p_identifier, p); if (!value.isEmpty()) { return value.toLatin1(); } @@ -514,22 +472,12 @@ QColor AOApplication::get_chat_color(QString p_identifier, QString p_chat) return return_color; } -QString AOApplication::get_sfx(QString p_identifier, QString p_misc) +QString AOApplication::get_court_sfx(QString p_identifier, QString p_misc) { - QStringList paths{get_theme_path("misc/" + p_misc + "/courtroom_sounds.ini"), - get_misc_path(p_misc, "courtroom_sounds.ini"), - get_theme_path("courtroom_sounds.ini"), - get_default_theme_path("courtroom_sounds.ini")}; - - QString return_sfx = ""; - - for (const QString &path : paths) { - QString value = read_design_ini(p_identifier, path); - if (!value.isEmpty()) { - return value.toLatin1(); - } - } - return return_sfx; + QString value = get_config_value(p_identifier, "courtroom_sounds.ini", current_theme, get_subtheme(), default_theme, p_misc); + if (!value.isEmpty()) + return value.toLatin1(); + return ""; } QString AOApplication::get_sfx_suffix(QString sound_to_check) @@ -547,21 +495,20 @@ QString AOApplication::get_sfx_suffix(QString sound_to_check) return sound_to_check + ".wav"; } -QString AOApplication::get_image_suffix(QString path_to_check) +QString AOApplication::get_image_suffix(QString path_to_check, bool static_image) { if (file_exists(path_to_check)) return path_to_check; - if (file_exists(path_to_check + ".webp")) - return path_to_check + ".webp"; - if (file_exists(path_to_check + ".apng")) - return path_to_check + ".apng"; - if (file_exists(path_to_check + ".gif")) - return path_to_check + ".gif"; - return path_to_check + ".png"; -} - -QString AOApplication::get_static_image_suffix(QString path_to_check) -{ + // A better method would to actually use AOImageReader and see if these images have more than 1 frame. + // However, that might not be performant. + if (!static_image) { + if (file_exists(path_to_check + ".webp")) + return path_to_check + ".webp"; + if (file_exists(path_to_check + ".apng")) + return path_to_check + ".apng"; + if (file_exists(path_to_check + ".gif")) + return path_to_check + ".gif"; + } return path_to_check + ".png"; } @@ -574,7 +521,7 @@ QString AOApplication::read_char_ini(QString p_char, QString p_search_line, QSettings settings(get_character_path(p_char, "char.ini"), QSettings::IniFormat); settings.beginGroup(target_tag); - QString value = settings.value(p_search_line).toString(); + QString value = settings.value(p_search_line).value(); settings.endGroup(); return value; } @@ -598,7 +545,7 @@ QStringList AOApplication::read_ini_tags(QString p_path, QString target_tag) settings.beginGroup(target_tag); QStringList keys = settings.allKeys(); foreach (QString key, keys) { - QString value = settings.value(key).toString(); + QString value = settings.value(key).value(); r_values << key + "=" + value; } if (!settings.group().isEmpty()) @@ -691,9 +638,6 @@ QString AOApplication::get_chat(QString p_char) if (p_char == "default") return "default"; QString f_result = read_char_ini(p_char, "chat", "Options"); - - // handling the correct order of chat is a bit complicated, we let the caller - // do it return f_result; } @@ -713,14 +657,6 @@ int AOApplication::get_chat_size(QString p_char) return f_result.toInt(); } -QString AOApplication::get_char_shouts(QString p_char) -{ - QString f_result = read_char_ini(p_char, "shouts", "Options"); - if (f_result == "") - return current_theme; // The default option is the current theme. - return f_result; -} - int AOApplication::get_preanim_duration(QString p_char, QString p_emote) { QString f_result = read_char_ini(p_char, p_emote, "Time"); @@ -854,7 +790,6 @@ QString AOApplication::get_sfx_looping(QString p_char, int p_emote) QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "SoundL"); - qDebug() << f_result; if (f_result == "") return "0"; else @@ -903,37 +838,18 @@ int AOApplication::get_text_delay(QString p_char, QString p_emote) return f_result.toInt(); } -QStringList AOApplication::get_theme_effects() -{ - QString p_path = get_theme_path("effects/effects.ini"); - QString default_path = get_default_theme_path("effects/effects.ini"); - - QStringList effects; - if (!file_exists(p_path)) { - p_path = default_path; - if (!file_exists(p_path)) - return effects; - } - - QStringList lines = read_file(p_path).split("\n"); - foreach (QString effect, lines) { - effect = effect.split("=")[0].trimmed().split("_")[0]; - if (!effect.isEmpty() && !effects.contains(effect)) - effects.append(effect); - } - return effects; -} - QStringList AOApplication::get_effects(QString p_char) { - QString p_effect = read_char_ini(p_char, "effects", "Options"); - QString p_path = get_base_path() + "misc/" + p_effect + "/effects.ini"; - - QStringList effects = get_theme_effects(); - if (!file_exists(p_path)) - return effects; + QString p_misc = read_char_ini(p_char, "effects", "Options"); + QString p_path = get_asset("effects/effects.ini", current_theme, get_subtheme(), default_theme, ""); + QString p_misc_path = get_asset("effects/effects.ini", current_theme, get_subtheme(), default_theme, p_misc); + QStringList effects; QStringList lines = read_file(p_path).split("\n"); + // Misc path different from default path, stack the new miscs on top of the defaults + if (p_misc_path != p_path) { + lines << read_file(p_misc_path).split("\n"); + } foreach (QString effect, lines) { effect = effect.split("=")[0].trimmed().split("_")[0]; if (!effect.isEmpty() && !effects.contains(effect)) @@ -946,27 +862,13 @@ QStringList AOApplication::get_effects(QString p_char) QString AOApplication::get_effect(QString effect, QString p_char, QString p_folder) { - QString p_effect = p_folder; if (p_folder == "") - p_effect = read_char_ini(p_char, "effects", "Options"); + p_folder = read_char_ini(p_char, "effects", "Options"); - QString p_path = - get_image_suffix(get_base_path() + "misc/" + p_effect + "/" + effect); - QString design_ini_path = - get_image_suffix(get_theme_path("effects/" + effect)); - QString default_path = - get_image_suffix(get_default_theme_path("effects/" + effect)); - - if (!file_exists(p_path)) { - p_path = design_ini_path; - if (!file_exists(p_path)) { - p_path = default_path; - if (!file_exists(p_path)) { - return ""; - } - } - } + QString p_path = get_image("effects/" + effect, current_theme, get_subtheme(), default_theme, p_folder); + if (!file_exists(p_path)) + return ""; return p_path; } @@ -978,36 +880,20 @@ QString AOApplication::get_effect_property(QString fx_name, QString p_char, f_property = fx_name; else f_property = fx_name + "_" + p_property; - QString p_effect = read_char_ini(p_char, "effects", "Options"); - QString p_path = get_base_path() + "misc/" + p_effect + "/effects.ini"; - QString design_ini_path = get_theme_path("effects/effects.ini"); - QString default_path = get_default_theme_path("effects/effects.ini"); - - QString f_result = read_design_ini(f_property, p_path); - if (f_result == "") { - f_result = read_design_ini(f_property, design_ini_path); - if (f_result == "") { - f_result = read_design_ini(f_property, default_path); - } - } + QString f_result = get_config_value(f_property, "effects/effects.ini", current_theme, get_subtheme(), default_theme, read_char_ini(p_char, "effects", "Options")); if (fx_name == "realization" && p_property == "sound") { f_result = get_custom_realization(p_char); } - - qDebug() << "got" << f_property << "of" << fx_name << "==" << f_result; - return f_result; } QString AOApplication::get_custom_realization(QString p_char) { QString f_result = read_char_ini(p_char, "realization", "Options"); - if (f_result == "") - return get_sfx("realization"); - else - return get_sfx_suffix(get_sounds_path(f_result)); + return get_court_sfx("realization"); + return get_sfx_suffix(get_sounds_path(f_result)); } bool AOApplication::get_blank_blip() @@ -1162,9 +1048,31 @@ QString AOApplication::get_casing_can_host_cases() .value(); return result; } + bool AOApplication::get_auto_logging_enabled() { QString result = configini->value("automatic_logging_enabled", "true").value(); return result.startsWith("true"); } + +QString AOApplication::get_subtheme() +{ + QString result = + configini->value("subtheme", "server").value(); + // Server means we want the server to decide for us + if (result == "server") + // 'subtheme' variable is affected by the server + result = subtheme; + // Default means we don't want any subthemes + else if (result == "default") + result = ""; + return result; +} + +bool AOApplication::get_animated_theme() +{ + QString result = + configini->value("animated_theme", "true").value(); + return result.startsWith("true"); +}