diff --git a/Attorney_Online.pro b/Attorney_Online.pro index 2a5c1e1..abca0fb 100644 --- a/Attorney_Online.pro +++ b/Attorney_Online.pro @@ -19,6 +19,9 @@ QMAKE_LFLAGS += -Wl,-rpath,"'\$$ORIGIN/lib'" # Uncomment for verbose network logging # DEFINES += DEBUG_NETWORK +# Uncomment for verbose animation logging +# DEFINES += DEBUG_MOVIE + # Uncomment for building with debug symbols # CONFIG += debug diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index 18cf23b..e74a49b 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -10,13 +10,11 @@ aoevidencebutton.h aoevidencedisplay.h aoimage.h aolayer.h -aolineedit.h aomusicplayer.h aooptionsdialog.h aopacket.h aosfxplayer.h aotextarea.h -aotextedit.h bass.h bassopus.h chatlogpiece.h @@ -28,6 +26,7 @@ discord-rpc.h discord_register.h discord_rich_presence.h discord_rpc.h +eventfilters.h file_functions.h hardware_functions.h lobby.h diff --git a/include/aoapplication.h b/include/aoapplication.h index 1cdcbc5..d8d3c9a 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -1,8 +1,6 @@ #ifndef AOAPPLICATION_H #define AOAPPLICATION_H -#define UNUSED(x) (void)(x) - #include "aopacket.h" #include "datatypes.h" #include "demoserver.h" @@ -37,6 +35,25 @@ class NetworkManager; class Lobby; class Courtroom; +class VPath : QString { + using QString::QString; + +public: + explicit VPath(const QString &str) : QString(str) {} + inline QString const &toQString() const { return *this; } + inline bool operator==(const VPath &str) const { + return this->toQString() == str.toQString(); + } + inline VPath operator+(const VPath &str) const { + return VPath(this->toQString() + str.toQString()); + } +}; + +inline uint qHash(const VPath &key, uint seed = qGlobalQHashSeed()) +{ + return qHash(key.toQString(), seed); +} + class AOApplication : public QApplication { Q_OBJECT @@ -129,24 +146,26 @@ public: // implementation in path_functions.cpp QString get_base_path(); - QString get_data_path(); - 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); - QString get_music_path(QString p_song); - 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); + VPath get_theme_path(QString p_file, QString p_theme=""); + VPath get_character_path(QString p_char, QString p_file); + VPath get_misc_path(QString p_misc, QString p_file); + VPath get_sounds_path(QString p_file); + VPath get_music_path(QString p_song); + VPath get_background_path(QString p_file); + VPath get_default_background_path(QString p_file); + VPath get_evidence_path(QString p_file); + QVector 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(QVector pathlist); + QString get_image_path(QVector pathlist, bool static_image=false); + QString get_sfx_path(QVector 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_image(QString p_element, QString p_theme="", QString p_subtheme="", QString p_default_theme="", QString p_misc="", QString p_character="", QString p_placeholder="", bool static_image=false); QString get_sfx(QString p_sfx, QString p_misc="", QString p_character=""); QString get_case_sensitive_path(QString p_file); + QString get_real_path(const VPath &vpath); + QString get_real_suffixed_path(const VPath &vpath, const QStringList &suffixes); + void invalidate_lookup_cache(); ////// Functions for reading and writing files ////// // Implementations file_functions.cpp @@ -265,6 +284,9 @@ public: // Returns whether the log should have a timestamp. bool get_log_timestamp(); + // Returns the format string for the log timestamp + QString get_log_timestamp_format(); + // Returns whether to log IC actions. bool get_log_ic_actions(); @@ -284,6 +306,7 @@ public: QStringList get_call_words(); // returns all of the file's lines in a QStringList + QStringList get_list_file(VPath path); QStringList get_list_file(QString p_file); // Process a file and return its text as a QString @@ -307,6 +330,7 @@ public: QVector read_serverlist_txt(); // Returns the value of p_identifier in the design.ini file in p_design_path + QString read_design_ini(QString p_identifier, VPath p_design_path); QString read_design_ini(QString p_identifier, QString p_design_path); // Returns the coordinates of widget with p_identifier from p_file @@ -336,18 +360,18 @@ public: 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); + QString get_sfx_suffix(VPath 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, bool static_image=false); + QString get_image_suffix(VPath 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, QString target_tag); // Returns a QStringList of all key=value definitions on a given tag. - QStringList read_ini_tags(QString p_file, QString target_tag = ""); + QStringList read_ini_tags(VPath p_file, QString target_tag = ""); // Sets the char.ini p_search_line key under tag target_tag to value. void set_char_ini(QString p_char, QString value, QString p_search_line, @@ -491,6 +515,9 @@ public: // Get the default scaling method QString get_default_scaling(); + // Get a list of custom mount paths + QStringList get_mount_paths(); + // Get whether to opt out of player count metrics sent to the master server bool get_player_count_optout(); @@ -529,6 +556,9 @@ private: QVector server_list; QVector favorite_list; + QHash asset_lookup_cache; + QHash dir_listing_cache; + QSet dir_listing_exist_cache; public slots: void server_disconnected(); diff --git a/include/aolayer.h b/include/aolayer.h index f3ecebf..b890715 100644 --- a/include/aolayer.h +++ b/include/aolayer.h @@ -7,8 +7,12 @@ #include #include #include +#include +#include +#include class AOApplication; +class VPath; // "Brief" explanation of what the hell this is: // @@ -138,6 +142,18 @@ protected: // Center the QLabel in the viewport based on the dimensions of f_pixmap void center_pixmap(QPixmap f_pixmap); +private: + // Populates the frame and delay vectors. + void populate_vectors(); + + // used in populate_vectors + void load_next_frame(); + bool exit_loop; //awful solution but i'm not fucking using QThread + QFuture frame_loader; + QMutex mutex; + QWaitCondition frameAdded; + + signals: void done(); @@ -235,4 +251,5 @@ public: StickerLayer(QWidget *p_parent, AOApplication *p_ao_app); void load_image(QString p_charname); }; + #endif // AOLAYER_H diff --git a/include/aolineedit.h b/include/aolineedit.h deleted file mode 100644 index 5dce3aa..0000000 --- a/include/aolineedit.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef AOLINEEDIT_H -#define AOLINEEDIT_H - -#include -#include - -class AOLineEdit : public QLineEdit { - Q_OBJECT - -public: - AOLineEdit(QWidget *parent); - - void preserve_selection(bool toggle) { p_selection = toggle; } - -private: - bool p_selection = false; - -protected: - void mouseDoubleClickEvent(QMouseEvent *e); - void focusOutEvent(QFocusEvent *ev); - -signals: - void double_clicked(); -}; - -#endif // AOLINEEDIT_H diff --git a/include/aooptionsdialog.h b/include/aooptionsdialog.h index d8ef49f..84a9648 100644 --- a/include/aooptionsdialog.h +++ b/include/aooptionsdialog.h @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -62,6 +63,8 @@ private: QSpinBox *ui_log_margin_spinbox; QLabel *ui_log_timestamp_lbl; QCheckBox *ui_log_timestamp_cb; + QLabel *ui_log_timestamp_format_lbl; + QComboBox *ui_log_timestamp_format_combobox; QLabel *ui_stay_time_lbl; QSpinBox *ui_stay_time_spinbox; QLabel *ui_desync_logs_lbl; @@ -175,12 +178,25 @@ private: QLabel *ui_log_lbl; QCheckBox *ui_log_cb; + QWidget *ui_assets_tab; + QVBoxLayout *ui_assets_tab_layout; + QGridLayout *ui_mount_buttons_layout; + QLabel *ui_asset_lbl; + QListWidget *ui_mount_list; + QPushButton *ui_mount_add; + QPushButton *ui_mount_remove; + QPushButton *ui_mount_up; + QPushButton *ui_mount_down; + QPushButton *ui_mount_clear_cache; + QWidget *ui_privacy_tab; QVBoxLayout *ui_privacy_layout; QCheckBox *ui_privacy_optout_cb; QFrame *ui_privacy_separator; QTextBrowser *ui_privacy_policy; + bool asset_cache_dirty = false; + bool needs_default_audiodev(); void update_values(); @@ -190,6 +206,8 @@ public slots: void save_pressed(); void discard_pressed(); void button_clicked(QAbstractButton *button); + void on_timestamp_format_edited(); + void timestamp_cb_changed(int state); void on_reload_theme_clicked(); void theme_changed(int i); }; diff --git a/include/aotextedit.h b/include/aotextedit.h deleted file mode 100644 index 8d876f1..0000000 --- a/include/aotextedit.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef AOTEXTEDIT_H -#define AOTEXTEDIT_H - -#include - -class AOTextEdit : public QPlainTextEdit { - Q_OBJECT -public: - AOTextEdit(QWidget *parent); - -protected: - void mouseDoubleClickEvent(QMouseEvent *e); - -signals: - void double_clicked(); - -private slots: - void on_enter_pressed(); -}; - -#endif // AOTEXTEDIT_H diff --git a/include/courtroom.h b/include/courtroom.h index e814514..4bc8624 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -11,13 +11,11 @@ #include "aoevidencedisplay.h" #include "aoimage.h" #include "aolayer.h" -#include "aolineedit.h" #include "aomusicplayer.h" #include "aooptionsdialog.h" #include "aopacket.h" #include "aosfxplayer.h" #include "aotextarea.h" -#include "aotextedit.h" #include "chatlogpiece.h" #include "datatypes.h" #include "debug_functions.h" @@ -25,6 +23,7 @@ #include "hardware_functions.h" #include "lobby.h" #include "scrolltext.h" +#include "eventfilters.h" #include #include @@ -417,6 +416,9 @@ private: // True, if the log should have a timestamp. bool log_timestamp = false; + // format string for aforementioned log timestamp + QString log_timestamp_format; + // How long in miliseconds should the objection wait before appearing. int objection_threshold = 1500; @@ -648,7 +650,8 @@ private: QComboBox *ui_pair_order_dropdown; - AOLineEdit *ui_ic_chat_message; + QLineEdit *ui_ic_chat_message; + AOLineEditFilter *ui_ic_chat_message_filter; QLineEdit *ui_ic_chat_name; QLineEdit *ui_ooc_chat_message; @@ -730,7 +733,8 @@ private: AOButton *ui_evidence_button; AOImage *ui_evidence; - AOLineEdit *ui_evidence_name; + QLineEdit *ui_evidence_name; + AOLineEditFilter *ui_evidence_name_filter; QWidget *ui_evidence_buttons; QVector ui_evidence_list; AOButton *ui_evidence_left; @@ -738,7 +742,8 @@ private: AOButton *ui_evidence_present; AOImage *ui_evidence_overlay; AOButton *ui_evidence_delete; - AOLineEdit *ui_evidence_image_name; + QLineEdit *ui_evidence_image_name; + AOLineEditFilter *ui_evidence_image_name_filter; AOButton *ui_evidence_image_button; AOButton *ui_evidence_x; AOButton *ui_evidence_ok; @@ -746,7 +751,9 @@ private: AOButton *ui_evidence_transfer; AOButton *ui_evidence_save; AOButton *ui_evidence_load; - AOTextEdit *ui_evidence_description; + AOButton *ui_evidence_edit; + QPlainTextEdit *ui_evidence_description; + AOImage *ui_char_select_background; @@ -873,6 +880,7 @@ private slots: void on_evidence_image_button_clicked(); void on_evidence_clicked(int p_id); void on_evidence_double_clicked(int p_id); + void on_evidence_edit_clicked(); void on_evidence_hover(int p_id, bool p_state); @@ -928,8 +936,6 @@ private slots: void on_showname_enable_clicked(); - void on_evidence_name_double_clicked(); - void on_evidence_image_name_double_clicked(); void on_evidence_button_clicked(); void on_evidence_delete_clicked(); diff --git a/include/eventfilters.h b/include/eventfilters.h new file mode 100644 index 0000000..7847608 --- /dev/null +++ b/include/eventfilters.h @@ -0,0 +1,36 @@ +#ifndef EVENTFILTERS_H +#define EVENTFILTERS_H + +#include +#include + +class AOLineEditFilter : public QObject +{ + Q_OBJECT +public: + bool preserve_selection = false; + +protected: + bool eventFilter(QObject *obj, QEvent *event) override { + QLineEdit *lineEdit = qobject_cast(obj); + if (event->type() == QEvent::FocusOut && lineEdit != nullptr && preserve_selection) { // lost focus + int start = lineEdit->selectionStart(); + #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) + int len = lineEdit->selectionLength(); + #else + int len = lineEdit->selectedText().length(); + #endif + if (start != -1 && len != -1) { + lineEdit->setSelection(start, len);\ + return true; + } + } + return false; + } +signals: + void double_clicked(); +}; + + + +#endif // EVENTFILTERS_H diff --git a/include/lobby.h b/include/lobby.h index 1d2cbc6..8083249 100644 --- a/include/lobby.h +++ b/include/lobby.h @@ -86,7 +86,7 @@ private: QProgressBar *ui_progress_bar; AOButton *ui_cancel; - int last_index; + int last_index = -1; void set_size_and_pos(QWidget *p_widget, QString p_identifier); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b04db8b..32e924a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -10,13 +10,11 @@ aoevidencebutton.cpp aoevidencedisplay.cpp aoimage.cpp aolayer.cpp -aolineedit.cpp aomusicplayer.cpp aooptionsdialog.cpp aopacket.cpp aosfxplayer.cpp aotextarea.cpp -aotextedit.cpp charselect.cpp chatlogpiece.cpp courtroom.cpp diff --git a/src/aoapplication.cpp b/src/aoapplication.cpp index a870156..f516be3 100644 --- a/src/aoapplication.cpp +++ b/src/aoapplication.cpp @@ -17,6 +17,8 @@ AOApplication::AOApplication(int &argc, char **argv) : QApplication(argc, argv) net_manager = new NetworkManager(this); discord = new AttorneyOnline::Discord(); qApp->setStyleSheet("QFrame {background-color:transparent;} QAbstractItemView {background-color: transparent; color: black;}; QLineEdit {background-color:transparent;}"); + + asset_lookup_cache.reserve(2048); } AOApplication::~AOApplication() @@ -164,13 +166,14 @@ void AOApplication::call_announce_menu(Courtroom *court) } // Callback for when BASS device is lost +// Only actually used for music syncs void CALLBACK AOApplication::BASSreset(HSTREAM handle, DWORD channel, DWORD data, void *user) { - UNUSED(handle); - UNUSED(channel); - UNUSED(data); - UNUSED(user); + Q_UNUSED(handle); + Q_UNUSED(channel); + Q_UNUSED(data); + Q_UNUSED(user); doBASSreset(); } @@ -183,6 +186,7 @@ void AOApplication::doBASSreset() void AOApplication::initBASS() { + BASS_SetConfig(BASS_CONFIG_DEV_DEFAULT, 1); BASS_Free(); // Change the default audio output device to be the one the user has given // in his config.ini file for now. diff --git a/src/aoblipplayer.cpp b/src/aoblipplayer.cpp index 6607d46..307a0bd 100644 --- a/src/aoblipplayer.cpp +++ b/src/aoblipplayer.cpp @@ -34,12 +34,6 @@ void AOBlipPlayer::blip_tick() HSTREAM f_stream = m_stream_list[f_cycle]; BASS_ChannelSetDevice(f_stream, BASS_GetDevice()); - int f_bass_error = BASS_ErrorGetCode(); - if (f_bass_error == BASS_ERROR_DEVICE) { - ao_app->doBASSreset(); - BASS_ChannelSetDevice(f_stream, BASS_GetDevice()); - } - BASS_ChannelPlay(f_stream, false); } diff --git a/src/aobutton.cpp b/src/aobutton.cpp index 7f8c13f..242fe79 100644 --- a/src/aobutton.cpp +++ b/src/aobutton.cpp @@ -20,14 +20,9 @@ void AOButton::set_image(QString p_path, QString p_misc) { 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 - // 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)) { + p_image = ao_app->get_image(p_path, ao_app->current_theme, ao_app->get_subtheme(), + ao_app->default_theme, p_misc, "", "", !ao_app->get_animated_theme()); + if (p_image.isEmpty()) { this->setIcon(QIcon()); this->setIconSize(this->size()); this->setStyleSheet(""); diff --git a/src/aocaseannouncerdialog.cpp b/src/aocaseannouncerdialog.cpp index aea6405..0c9ee0f 100644 --- a/src/aocaseannouncerdialog.cpp +++ b/src/aocaseannouncerdialog.cpp @@ -23,10 +23,10 @@ AOCaseAnnouncerDialog::AOCaseAnnouncerDialog(QWidget *parent, ui_announcer_buttons->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - QObject::connect(ui_announcer_buttons, SIGNAL(accepted()), this, - SLOT(ok_pressed())); - QObject::connect(ui_announcer_buttons, SIGNAL(rejected()), this, - SLOT(cancel_pressed())); + connect(ui_announcer_buttons, &QDialogButtonBox::accepted, this, + &AOCaseAnnouncerDialog::ok_pressed); + connect(ui_announcer_buttons, &QDialogButtonBox::rejected, this, + &AOCaseAnnouncerDialog::cancel_pressed); setUpdatesEnabled(false); diff --git a/src/aoemotebutton.cpp b/src/aoemotebutton.cpp index 3260a94..638d49d 100644 --- a/src/aoemotebutton.cpp +++ b/src/aoemotebutton.cpp @@ -11,7 +11,7 @@ AOEmoteButton::AOEmoteButton(QWidget *p_parent, AOApplication *p_ao_app, this->move(p_x, p_y); this->resize(p_w, p_h); - connect(this, SIGNAL(clicked()), this, SLOT(on_clicked())); + connect(this, &AOEmoteButton::clicked, this, &AOEmoteButton::on_clicked); } void AOEmoteButton::set_image(QString p_image, QString p_emote_comment) @@ -67,4 +67,4 @@ void AOEmoteButton::set_char_image(QString p_char, int p_emote, QString suffix) this->set_image(image_path, ao_app->get_emote_comment(p_char, p_emote)); } -void AOEmoteButton::on_clicked() { emote_clicked(m_id); } +void AOEmoteButton::on_clicked() { emit emote_clicked(m_id); } diff --git a/src/aoevidencebutton.cpp b/src/aoevidencebutton.cpp index fee7327..800c8b4 100644 --- a/src/aoevidencebutton.cpp +++ b/src/aoevidencebutton.cpp @@ -27,12 +27,12 @@ AOEvidenceButton::AOEvidenceButton(QWidget *p_parent, AOApplication *p_ao_app, this->resize(p_w, p_h); // this->setAcceptDrops(true); - connect(this, SIGNAL(clicked()), this, SLOT(on_clicked())); + connect(this, &AOEvidenceButton::clicked, this, &AOEvidenceButton::on_clicked); } void AOEvidenceButton::set_image(QString p_image) { - QString image_path = ao_app->get_evidence_path(p_image); + QString image_path = ao_app->get_real_path(ao_app->get_evidence_path(p_image)); if (file_exists(p_image)) { this->setText(""); this->setStyleSheet( @@ -57,8 +57,10 @@ 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_theme_path(p_image, ao_app->default_theme); + QString theme_image_path = ao_app->get_real_path( + ao_app->get_theme_path(p_image)); + QString default_image_path = ao_app->get_real_path( + ao_app->get_theme_path(p_image, ao_app->default_theme)); QString final_image_path; @@ -78,12 +80,12 @@ void AOEvidenceButton::set_selected(bool p_selected) ui_selected->hide(); } -void AOEvidenceButton::on_clicked() { evidence_clicked(m_id); } +void AOEvidenceButton::on_clicked() { emit evidence_clicked(m_id); } void AOEvidenceButton::mouseDoubleClickEvent(QMouseEvent *e) { QPushButton::mouseDoubleClickEvent(e); - evidence_double_clicked(m_id); + emit evidence_double_clicked(m_id); } /* @@ -106,7 +108,7 @@ void AOEvidenceButton::enterEvent(QEvent *e) { ui_selector->show(); - on_hover(m_id, true); + emit on_hover(m_id, true); setFlat(false); QPushButton::enterEvent(e); @@ -116,6 +118,6 @@ void AOEvidenceButton::leaveEvent(QEvent *e) { ui_selector->hide(); - on_hover(m_id, false); + emit on_hover(m_id, false); QPushButton::leaveEvent(e); } diff --git a/src/aoevidencedisplay.cpp b/src/aoevidencedisplay.cpp index ba1c170..0d3eae7 100644 --- a/src/aoevidencedisplay.cpp +++ b/src/aoevidencedisplay.cpp @@ -13,7 +13,7 @@ AOEvidenceDisplay::AOEvidenceDisplay(QWidget *p_parent, AOApplication *p_ao_app) evidence_movie = new InterfaceLayer(this, ao_app); - connect(evidence_movie, SIGNAL(done()), this, SLOT(show_done())); + connect(evidence_movie, &InterfaceLayer::done, this, &AOEvidenceDisplay::show_done); } void AOEvidenceDisplay::show_evidence(QString p_evidence_image, @@ -35,7 +35,8 @@ void AOEvidenceDisplay::show_evidence(QString p_evidence_image, gif_name = "evidence_appear_right"; } - QString f_evidence_path = ao_app->get_evidence_path(p_evidence_image); + QString f_evidence_path = ao_app->get_real_path( + ao_app->get_evidence_path(p_evidence_image)); QPixmap f_pixmap(f_evidence_path); pos_size_type icon_dimensions = diff --git a/src/aoimage.cpp b/src/aoimage.cpp index 656528e..82e17b9 100644 --- a/src/aoimage.cpp +++ b/src/aoimage.cpp @@ -24,21 +24,16 @@ AOImage::AOImage(QWidget *parent, AOApplication *p_ao_app, bool make_static) : Q AOImage::~AOImage() {} -bool AOImage::set_image(QString p_path, QString p_misc) +bool AOImage::set_image(QString p_image, QString p_misc) { - // Check if the user wants animated themes - if (!is_static && 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); + p_image = ao_app->get_image(p_image, ao_app->current_theme, ao_app->get_subtheme(), + ao_app->default_theme, p_misc, "", "", is_static || !ao_app->get_animated_theme()); - if (!file_exists(p_path)) { - qDebug() << "Warning: Image" << p_path << "not found! Can't set!"; + if (!file_exists(p_image)) { + qDebug() << "Warning: Image" << p_image << "not found! Can't set!"; return false; } - path = p_path; + path = p_image; if (!is_static) { movie->stop(); movie->setFileName(path); diff --git a/src/aolayer.cpp b/src/aolayer.cpp index 2c6c911..dd1fe76 100644 --- a/src/aolayer.cpp +++ b/src/aolayer.cpp @@ -12,16 +12,16 @@ AOLayer::AOLayer(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_parent) shfx_timer = new QTimer(this); shfx_timer->setTimerType(Qt::PreciseTimer); shfx_timer->setSingleShot(true); - connect(shfx_timer, SIGNAL(timeout()), this, SLOT(shfx_timer_done())); + connect(shfx_timer, &QTimer::timeout, this, &AOLayer::shfx_timer_done); ticker = new QTimer(this); ticker->setTimerType(Qt::PreciseTimer); ticker->setSingleShot(false); - connect(ticker, SIGNAL(timeout()), this, SLOT(movie_ticker())); + connect(ticker, &QTimer::timeout, this, &AOLayer::movie_ticker); preanim_timer = new QTimer(this); preanim_timer->setSingleShot(true); - connect(preanim_timer, SIGNAL(timeout()), this, SLOT(preanim_done())); + connect(preanim_timer, &QTimer::timeout, this, &AOLayer::preanim_done); } BackgroundLayer::BackgroundLayer(QWidget *p_parent, AOApplication *p_ao_app) @@ -52,7 +52,7 @@ StickerLayer::StickerLayer(QWidget *p_parent, AOApplication *p_ao_app) QString AOLayer::find_image(QStringList p_list) { QString image_path; - for (QString path : p_list) { + for (const QString &path : p_list) { #ifdef DEBUG_MOVIE qDebug() << "checking path " << path; #endif @@ -138,14 +138,15 @@ void BackgroundLayer::load_image(QString p_filename) { play_once = false; cull_image = false; - QString design_path = ao_app->get_background_path("design.ini"); + VPath design_path = ao_app->get_background_path("design.ini"); transform_mode = ao_app->get_scaling(ao_app->read_design_ini("scaling", design_path)); stretch = ao_app->read_design_ini("stretch", design_path).startsWith("true"); #ifdef DEBUG_MOVIE qDebug() << "[BackgroundLayer] BG loaded: " << p_filename; #endif - start_playback(ao_app->get_image_suffix(ao_app->get_background_path(p_filename))); + QString final_path = ao_app->get_image_suffix(ao_app->get_background_path(p_filename)); + start_playback(final_path); play(); } @@ -179,15 +180,16 @@ void CharLayer::load_image(QString p_filename, QString p_charname, last_emote = current_emote; last_prefix = prefix; is_preanim = p_is_preanim; - if ((p_filename.left(3) == "(a)") || (p_filename.left(3) == "(b)")) { - prefix = p_filename.left(3); + if ((p_filename.left(3) == "(a)") || (p_filename.left(3) == "(b)")) { // if we are playing an idle or talking animation + prefix = p_filename.left(3); // separate the prefix from the emote name current_emote = p_filename.mid(3, -1); } - else if ((duration > 0) || (p_filename.left(3) == "(c)")) { - if (p_filename.left(3) == "(c)") { - prefix = "(c)"; + else if ((duration > 0) || (p_filename.left(3) == "(c)")) { // else if we are playing a preanim or postanim + if (p_filename.left(3) == "(c)") { // if we are playing a postanim + prefix = "(c)"; // separate the prefix from the emote name current_emote = p_filename.mid(3, -1); } + // pre/postanim specific flags is_preanim = true; play_once = true; preanim_timer->start(duration); @@ -197,7 +199,7 @@ void CharLayer::load_image(QString p_filename, QString p_charname, << current_emote << " from character: " << p_charname << " continuous: " << continuous; #endif - QStringList pathlist = { + QVector pathlist { // cursed character path resolution vector ao_app->get_character_path( p_charname, prefix + current_emote), // Default path ao_app->get_character_path( @@ -207,7 +209,7 @@ void CharLayer::load_image(QString p_filename, QString p_charname, ao_app->get_character_path( p_charname, current_emote), // Just use the non-prefixed image, animated or not - current_emote, // The path by itself after the above fail + VPath(current_emote), // The path by itself after the above fail ao_app->get_theme_path("placeholder"), // Theme placeholder path ao_app->get_theme_path( "placeholder", ao_app->default_theme)}; // Default theme placeholder path @@ -232,7 +234,7 @@ void EffectLayer::load_image(QString p_filename, bool p_looping) play_once = true; continuous = false; force_continuous = true; - start_playback(p_filename); // handled in its own file before we see it + start_playback(p_filename); // path resolution is handled by the caller for EffectLayer objects play(); } @@ -269,6 +271,13 @@ void CharLayer::start_playback(QString p_image) void AOLayer::start_playback(QString p_image) { + if (p_image == "") {// image wasn't found by the path resolution function + this->kill(); + return; + } + QMutexLocker locker(&mutex); + if (frame_loader.isRunning()) + exit_loop = true; // tell the loader to stop, we have a new image to load this->show(); if (!ao_app->is_continuous_enabled()) { @@ -276,7 +285,7 @@ void AOLayer::start_playback(QString p_image) force_continuous = true; } - if ((last_path == p_image) && (!force_continuous)) + if (((last_path == p_image) && (!force_continuous)) || p_image == "") return; #ifdef DEBUG_MOVIE @@ -296,55 +305,36 @@ void AOLayer::start_playback(QString p_image) stretch = stretch_override.startsWith("true"); #ifdef DEBUG_MOVIE - qDebug() << "stretch:" << stretch << "filename:" << p_image; + qDebug() << "[AOLayer::start_playback] Stretch:" << stretch << "Filename:" << p_image; #endif m_reader.setFileName(p_image); if (m_reader.loopCount() == 0) play_once = true; - if (!continuous) - frame = 0; last_max_frames = max_frames; max_frames = m_reader.imageCount(); - if (((continuous) && (max_frames != last_max_frames)) || max_frames == 0) { + if (!continuous + || ((continuous) && (max_frames != last_max_frames)) + || max_frames == 0 + || frame >= max_frames) { frame = 0; continuous = false; } - // CANTFIX: this causes a hitch - // The correct way of doing this would be to use QImageReader::jumpToImage() - // and populate missing data in the movie ticker when it's needed. This is - // unfortunately completely impossible, because QImageReader::jumpToImage() is - // not implemented in any image format AO2 is equipped to use. Instead, the - // default behavior is used - that is, absolutely nothing. - // This is why continuous playback can be toggled off. - if (continuous) { - for (int i = frame; i--;) { - if (i <= -1) - break; - QPixmap l_pixmap = this->get_pixmap(m_reader.read()); - int l_delay = m_reader.nextImageDelay(); - movie_frames.append(l_pixmap); - movie_delays.append(l_delay); - } - } + frame_loader = QtConcurrent::run(this, &AOLayer::populate_vectors); last_path = p_image; - QPixmap f_pixmap = this->get_pixmap(m_reader.read()); - int f_delay = m_reader.nextImageDelay(); + while (movie_frames.size() <= frame) // if we haven't loaded the frame we need yet + frameAdded.wait(&mutex); // wait for the frame loader to add another frame, then check again + this->set_frame(movie_frames[frame]); - this->set_frame(f_pixmap); - if (max_frames > 1) { - movie_frames.append(f_pixmap); - movie_delays.append(f_delay); - } - else if (max_frames <= 1) { + if (max_frames <= 1) { duration = static_duration; #ifdef DEBUG_MOVIE - qDebug() << "max_frames is <= 1, using static duration"; + qDebug() << "[AOLayer::start_playback] max_frames is <= 1, using static duration"; #endif } if (duration > 0 && cull_image == true) shfx_timer->start(duration); #ifdef DEBUG_MOVIE - qDebug() << max_frames << "Setting image to " << image_path + qDebug() << "[AOLayer::start_playback] Max frames:" << max_frames << "Setting image to " << p_image << "Time taken to process image:" << actual_time.elapsed(); actual_time.restart(); @@ -375,8 +365,12 @@ void AOLayer::play() else this->freeze(); } - else + else { + while (movie_delays.size() <= frame) { + frameAdded.wait(&mutex); + } ticker->start(this->get_frame_delay(movie_delays[frame])); + } } void AOLayer::set_play_once(bool p_play_once) { play_once = p_play_once; } @@ -454,7 +448,7 @@ void CharLayer::load_network_effects() // data, let's yank it in. effect += f_data; #ifdef DEBUG_MOVIE - qDebug() << effect << f_data << "frame" << f_frame << "for" + qDebug() << "[CharLayer::load_network_effects]" << effect << f_data << "frame" << f_frame << "for" << m_emote; #endif movie_effects[f_frame].append(effect); @@ -473,24 +467,24 @@ void CharLayer::play_frame_effect(int p_frame) if (p_frame < max_frames) { foreach (QString effect, movie_effects[p_frame]) { if (effect == "shake") { - shake(); + emit shake(); #ifdef DEBUG_MOVIE - qDebug() << "Attempting to play shake on frame" << frame; + qDebug() << "[CharLayer::play_frame_effect] Attempting to play shake on frame" << frame; #endif } if (effect == "flash") { - flash(); + emit flash(); #ifdef DEBUG_MOVIE - qDebug() << "Attempting to play flash on frame" << frame; + qDebug() << "[CharLayer::play_frame_effect] Attempting to play flash on frame" << frame; #endif } if (effect.startsWith("sfx^")) { QString sfx = effect.section("^", 1); - play_sfx(sfx); + emit play_sfx(sfx); #ifdef DEBUG_MOVIE - qDebug() << "Attempting to play sfx" << sfx << "on frame" << frame; + qDebug() << "[CharLayer::play_frame_effect] Attempting to play sfx" << sfx << "on frame" << frame; #endif } } @@ -544,21 +538,38 @@ void AOLayer::movie_ticker() else frame = 0; } - // qint64 difference = elapsed - movie_delays[frame]; - if (frame >= movie_frames.size()) { - movie_frames.append(this->get_pixmap(m_reader.read())); - movie_delays.append(m_reader.nextImageDelay()); + mutex.lock(); + while (frame >= movie_frames.size() && frame < max_frames) { // oops! our frame isn't ready yet + frameAdded.wait(&mutex); // wait for a new frame to be added, then check again } - + mutex.unlock(); #ifdef DEBUG_MOVIE - qDebug() << frame << movie_delays[frame] - << "actual time taken from last frame:" << actual_time.restart(); + qDebug() << "[AOLayer::movie_ticker] Frame:" << frame << "Delay:" << movie_delays[frame] + << "Actual time taken from last frame:" << actual_time.restart(); #endif - this->set_frame(movie_frames[frame]); ticker->setInterval(this->get_frame_delay(movie_delays[frame])); } +void AOLayer::populate_vectors() { + while (movie_frames.size() < max_frames && !exit_loop) { + load_next_frame(); +#ifdef DEBUG_MOVIE + qDebug() << "[AOLayer::populate_vectors] Loaded frame" << movie_frames.size(); +#endif + } + exit_loop = false; +} + +void AOLayer::load_next_frame() { + //QMutexLocker locker(&mutex); + mutex.lock(); + movie_frames.append(this->get_pixmap(m_reader.read())); + movie_delays.append(m_reader.nextImageDelay()); + mutex.unlock(); + frameAdded.wakeAll(); +} + void CharLayer::preanim_done() { if (is_preanim) @@ -571,7 +582,7 @@ void AOLayer::preanim_done() { ticker->stop(); preanim_timer->stop(); - done(); + emit done(); } void AOLayer::shfx_timer_done() @@ -581,5 +592,5 @@ void AOLayer::shfx_timer_done() qDebug() << "shfx timer signaled done"; #endif // signal connected to courtroom object, let it figure out what to do - done(); + emit done(); } diff --git a/src/aolineedit.cpp b/src/aolineedit.cpp deleted file mode 100644 index d80fa01..0000000 --- a/src/aolineedit.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "aolineedit.h" - -AOLineEdit::AOLineEdit(QWidget *parent) : QLineEdit(parent) {} - -void AOLineEdit::mouseDoubleClickEvent(QMouseEvent *e) -{ - QLineEdit::mouseDoubleClickEvent(e); - - double_clicked(); -} -void AOLineEdit::focusOutEvent(QFocusEvent *ev) -{ - int start = selectionStart(); -#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) - int len = selectionLength(); -#else - int len = selectedText().length(); -#endif - QLineEdit::focusOutEvent(ev); - if (p_selection && start != -1 && len != -1) - this->setSelection(start, len); -} diff --git a/src/aomusicplayer.cpp b/src/aomusicplayer.cpp index e8bd690..d0d9563 100644 --- a/src/aomusicplayer.cpp +++ b/src/aomusicplayer.cpp @@ -19,7 +19,7 @@ int AOMusicPlayer::play(QString p_song, int channel, bool loop, channel = channel % m_channelmax; if (channel < 0) // wtf? return BASS_ERROR_NOCHAN; - QString f_path = ao_app->get_music_path(p_song); + QString f_path = ao_app->get_real_path(ao_app->get_music_path(p_song)); unsigned int flags = BASS_STREAM_PRESCAN | BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE; @@ -150,8 +150,8 @@ void AOMusicPlayer::set_volume(int p_value, int channel) void CALLBACK loopProc(HSYNC handle, DWORD channel, DWORD data, void *user) { - UNUSED(handle); - UNUSED(data); + Q_UNUSED(handle); + Q_UNUSED(data); QWORD loop_start = *(static_cast(user)); BASS_ChannelLock(channel, true); BASS_ChannelSetPosition(channel, loop_start, BASS_POS_BYTE); diff --git a/src/aooptionsdialog.cpp b/src/aooptionsdialog.cpp index 03c7334..54a11e1 100644 --- a/src/aooptionsdialog.cpp +++ b/src/aooptionsdialog.cpp @@ -5,6 +5,8 @@ #include "bass.h" #include "networkmanager.h" +#include + AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint) { @@ -13,7 +15,7 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) // Setting up the basics. setWindowFlag(Qt::WindowCloseButtonHint); setWindowTitle(tr("Settings")); - resize(400, 408); + resize(450, 408); ui_settings_buttons = new QDialogButtonBox(this); @@ -28,12 +30,12 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) QDialogButtonBox::Save | QDialogButtonBox::RestoreDefaults); - QObject::connect(ui_settings_buttons, SIGNAL(accepted()), this, - SLOT(save_pressed())); - QObject::connect(ui_settings_buttons, SIGNAL(rejected()), this, - SLOT(discard_pressed())); - QObject::connect(ui_settings_buttons, SIGNAL(clicked(QAbstractButton*)), this, - SLOT(button_clicked(QAbstractButton*))); + connect(ui_settings_buttons, &QDialogButtonBox::accepted, this, + &AOOptionsDialog::save_pressed); + connect(ui_settings_buttons, &QDialogButtonBox::rejected, this, + &AOOptionsDialog::discard_pressed); + connect(ui_settings_buttons, &QDialogButtonBox::clicked, this, + &AOOptionsDialog::button_clicked); // We'll stop updates so that the window won't flicker while it's being made. setUpdatesEnabled(false); @@ -74,16 +76,23 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) ui_theme_combobox = new QComboBox(ui_form_layout_widget); // Fill the combobox with the names of the themes. - QDirIterator it(ao_app->get_base_path() + "themes", QDir::Dirs, - QDirIterator::NoIteratorFlags); - while (it.hasNext()) { - QString actualname = QDir(it.next()).dirName(); - if (actualname != "." && actualname != "..") - ui_theme_combobox->addItem(actualname); + QSet themes; + QStringList bases = ao_app->get_mount_paths(); + bases.push_front(ao_app->get_base_path()); + for (const QString &base : bases) { + QDirIterator it(base + "/themes", QDir::Dirs | QDir::NoDotAndDotDot, + QDirIterator::NoIteratorFlags); + while (it.hasNext()) { + QString actualname = QDir(it.next()).dirName(); + if (!themes.contains(actualname)) { + ui_theme_combobox->addItem(actualname); + themes.insert(actualname); + } + } } - QObject::connect(ui_theme_combobox, SIGNAL(currentIndexChanged(int)), this, - SLOT(theme_changed(int))); + connect(ui_theme_combobox, QOverload::of(&QComboBox::currentIndexChanged), this, + &AOOptionsDialog::theme_changed); ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_theme_combobox); row += 1; @@ -116,8 +125,8 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) ui_theme_reload_button->setToolTip( tr("Refresh the theme and update all of the ui elements to match.")); 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())); + connect(ui_theme_reload_button, &QPushButton::clicked, this, + &AOOptionsDialog::on_reload_theme_clicked); row += 1; ui_animated_theme_lbl = new QLabel(ui_form_layout_widget); @@ -208,8 +217,33 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) ui_log_timestamp_cb = new QCheckBox(ui_form_layout_widget); + connect(ui_log_timestamp_cb, &QCheckBox::stateChanged, this, &AOOptionsDialog::timestamp_cb_changed); + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_log_timestamp_cb); + row += 1; + ui_log_timestamp_format_lbl = new QLabel(ui_form_layout_widget); + ui_log_timestamp_format_lbl->setText(tr("Log timestamp format:\n") + QDateTime::currentDateTime().toString(ao_app->get_log_timestamp_format())); + ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_log_timestamp_format_lbl); + + ui_log_timestamp_format_combobox = new QComboBox(ui_form_layout_widget); + ui_log_timestamp_format_combobox->setEditable(true); + + QString l_current_format = ao_app->get_log_timestamp_format(); + + ui_log_timestamp_format_combobox->setCurrentText(l_current_format); + ui_log_timestamp_format_combobox->addItem("h:mm:ss AP"); // 2:13:09 PM + ui_log_timestamp_format_combobox->addItem("hh:mm:ss"); // 14:13:09 + ui_log_timestamp_format_combobox->addItem("h:mm AP"); // 2:13 PM + ui_log_timestamp_format_combobox->addItem("hh:mm"); // 14:13 + + ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_log_timestamp_format_combobox); + + connect(ui_log_timestamp_format_combobox, &QComboBox::currentTextChanged, this, &AOOptionsDialog::on_timestamp_format_edited); + + if(!ao_app->get_log_timestamp()) + ui_log_timestamp_format_combobox->setDisabled(true); + row += 1; ui_log_ic_actions_lbl = new QLabel(ui_form_layout_widget); ui_log_ic_actions_lbl->setText(tr("Log IC actions:")); @@ -222,7 +256,6 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_log_ic_actions_cb); - row += 1; ui_stay_time_lbl = new QLabel(ui_form_layout_widget); ui_stay_time_lbl->setText(tr("Text Stay Time:")); @@ -903,7 +936,130 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) ui_casing_layout->setWidget(row, QFormLayout::FieldRole, ui_log_cb); - // privacy policy. + // Assets tab + ui_assets_tab = new QWidget(this); + ui_assets_tab_layout = new QVBoxLayout(ui_assets_tab); + ui_assets_tab->setLayout(ui_assets_tab_layout); + ui_settings_tabs->addTab(ui_assets_tab, tr("Assets")); + + ui_asset_lbl = new QLabel(ui_assets_tab); + ui_asset_lbl->setText( + tr("Add or remove base folders for use by assets. " + "Base folders will be searched in the order provided.")); + ui_asset_lbl->setWordWrap(true); + ui_assets_tab_layout->addWidget(ui_asset_lbl); + + ui_mount_list = new QListWidget(ui_assets_tab); + ui_assets_tab_layout->addWidget(ui_mount_list); + + ui_mount_buttons_layout = new QGridLayout(ui_assets_tab); + ui_assets_tab_layout->addLayout(ui_mount_buttons_layout); + + QSizePolicy stretch_btns(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); + stretch_btns.setHorizontalStretch(4); + + ui_mount_add = new QPushButton(tr("Add…"), ui_assets_tab); + ui_mount_add->setSizePolicy(stretch_btns); + ui_mount_buttons_layout->addWidget(ui_mount_add, 0, 0, 1, 1); + connect(ui_mount_add, &QPushButton::clicked, this, [this] { + QString dir = QFileDialog::getExistingDirectory(this, tr("Select a base folder"), + QApplication::applicationDirPath(), + QFileDialog::ShowDirsOnly); + if (dir.isEmpty()) + return; + QListWidgetItem *dir_item = new QListWidgetItem(dir); + ui_mount_list->addItem(dir_item); + ui_mount_list->setCurrentItem(dir_item); + + // quick hack to update buttons + emit ui_mount_list->itemSelectionChanged(); + }); + + ui_mount_remove = new QPushButton(tr("Remove"), ui_assets_tab); + ui_mount_remove->setSizePolicy(stretch_btns); + ui_mount_remove->setEnabled(false); + ui_mount_buttons_layout->addWidget(ui_mount_remove, 0, 1, 1, 1); + connect(ui_mount_remove, &QPushButton::clicked, this, [=] { + auto selected = ui_mount_list->selectedItems(); + if (selected.isEmpty()) + return; + delete selected[0]; + emit ui_mount_list->itemSelectionChanged(); + asset_cache_dirty = true; + }); + + auto *mount_buttons_spacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, + QSizePolicy::Minimum); + ui_mount_buttons_layout->addItem(mount_buttons_spacer, 0, 2, 1, 1); + + ui_mount_up = new QPushButton(tr("↑"), ui_assets_tab); + ui_mount_up->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); + ui_mount_up->setMaximumWidth(40); + ui_mount_up->setEnabled(false); + ui_mount_buttons_layout->addWidget(ui_mount_up, 0, 3, 1, 1); + connect(ui_mount_up, &QPushButton::clicked, this, [=] { + auto selected = ui_mount_list->selectedItems(); + if (selected.isEmpty()) + return; + auto *item = selected[0]; + int row = ui_mount_list->row(item); + ui_mount_list->takeItem(row); + int new_row = qMax(1, row - 1); + ui_mount_list->insertItem(new_row, item); + ui_mount_list->setCurrentRow(new_row); + asset_cache_dirty = true; + }); + + ui_mount_down = new QPushButton(tr("↓"), ui_assets_tab); + ui_mount_down->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); + ui_mount_down->setMaximumWidth(40); + ui_mount_down->setEnabled(false); + ui_mount_buttons_layout->addWidget(ui_mount_down, 0, 4, 1, 1); + connect(ui_mount_down, &QPushButton::clicked, this, [=] { + auto selected = ui_mount_list->selectedItems(); + if (selected.isEmpty()) + return; + auto *item = selected[0]; + int row = ui_mount_list->row(item); + ui_mount_list->takeItem(row); + int new_row = qMin(ui_mount_list->count() + 1, row + 1); + ui_mount_list->insertItem(new_row, item); + ui_mount_list->setCurrentRow(new_row); + asset_cache_dirty = true; + }); + + auto *mount_buttons_spacer_2 = new QSpacerItem(40, 20, QSizePolicy::Expanding, + QSizePolicy::Minimum); + ui_mount_buttons_layout->addItem(mount_buttons_spacer_2, 0, 5, 1, 1); + + ui_mount_clear_cache = new QPushButton(tr("Clear Cache"), ui_assets_tab); + ui_mount_clear_cache->setToolTip(tr("Clears the lookup cache for assets. " + "Use this when you have added an asset that takes precedence over another " + "existing asset.")); + ui_mount_buttons_layout->addWidget(ui_mount_clear_cache, 0, 6, 1, 1); + connect(ui_mount_clear_cache, &QPushButton::clicked, this, [=] { + asset_cache_dirty = true; + ui_mount_clear_cache->setEnabled(false); + }); + + connect(ui_mount_list, &QListWidget::itemSelectionChanged, this, [=] { + auto selected_items = ui_mount_list->selectedItems(); + bool row_selected = !ui_mount_list->selectedItems().isEmpty(); + ui_mount_remove->setEnabled(row_selected); + ui_mount_up->setEnabled(row_selected); + ui_mount_down->setEnabled(row_selected); + + if (!row_selected) + return; + + int row = ui_mount_list->row(selected_items[0]); + if (row <= 1) + ui_mount_up->setEnabled(false); + if (row >= ui_mount_list->count() - 1) + ui_mount_down->setEnabled(false); + }); + + // Privacy tab ui_privacy_tab = new QWidget(this); ui_settings_tabs->addTab(ui_privacy_tab, tr("Privacy")); @@ -965,6 +1121,7 @@ void AOOptionsDialog::update_values() { ui_downwards_cb->setChecked(ao_app->get_log_goes_downwards()); ui_log_newline_cb->setChecked(ao_app->get_log_newline()); ui_log_timestamp_cb->setChecked(ao_app->get_log_timestamp()); + ui_log_timestamp_format_combobox->setCurrentText(ao_app->get_log_timestamp_format()); ui_log_ic_actions_cb->setChecked(ao_app->get_log_ic_actions()); ui_desync_logs_cb->setChecked(ao_app->is_desyncrhonized_logs_enabled()); ui_instant_objection_cb->setChecked(ao_app->is_instant_objection_enabled()); @@ -1002,6 +1159,13 @@ void AOOptionsDialog::update_values() { ui_blips_volume_spinbox->setValue(ao_app->get_default_blip()); ui_bliprate_spinbox->setValue(ao_app->read_blip_rate()); ui_default_showname_textbox->setText(ao_app->get_default_showname()); + + auto *defaultMount = new QListWidgetItem(tr("%1 (default)") + .arg(ao_app->get_base_path())); + defaultMount->setFlags(Qt::ItemFlag::NoItemFlags); + ui_mount_list->addItem(defaultMount); + ui_mount_list->addItems(ao_app->get_mount_paths()); + ui_privacy_optout_cb->setChecked(ao_app->get_player_count_optout()); ao_app->net_manager->request_document(MSDocumentType::PrivacyPolicy, [this](QString document) { @@ -1028,6 +1192,7 @@ void AOOptionsDialog::save_pressed() 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("log_timestamp_format", ui_log_timestamp_format_combobox->currentText()); configini->setValue("log_ic_actions", ui_log_ic_actions_cb->isChecked()); configini->setValue("desync_logs", ui_desync_logs_cb->isChecked()); configini->setValue("stay_time", ui_stay_time_spinbox->value()); @@ -1083,9 +1248,16 @@ void AOOptionsDialog::save_pressed() configini->setValue("casing_cm_enabled", ui_casing_cm_cb->isChecked()); configini->setValue("casing_can_host_cases", ui_casing_cm_cases_textbox->text()); - configini->setValue("player_count_optout", ui_privacy_optout_cb->isChecked()); + QStringList mountPaths; + for (int i = 1; i < ui_mount_list->count(); i++) + mountPaths.append(ui_mount_list->item(i)->text()); + configini->setValue("mount_paths", mountPaths); + + if (asset_cache_dirty) + ao_app->invalidate_lookup_cache(); + if (audioChanged) ao_app->initBASS(); @@ -1147,6 +1319,10 @@ void AOOptionsDialog::theme_changed(int i) { } +void AOOptionsDialog::on_timestamp_format_edited() { ui_log_timestamp_format_lbl->setText(tr("Log timestamp format:\n") + QDateTime::currentDateTime().toString(ui_log_timestamp_format_combobox->currentText())); } + +void AOOptionsDialog::timestamp_cb_changed(int state) { ui_log_timestamp_format_combobox->setDisabled(state == 0); } + #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 000b6a7..fcdeb94 100644 --- a/src/aosfxplayer.cpp +++ b/src/aosfxplayer.cpp @@ -47,12 +47,6 @@ void AOSfxPlayer::play(QString p_sfx, QString p_character, QString p_misc) set_volume_internal(m_volume); BASS_ChannelSetDevice(m_stream_list[m_channel], BASS_GetDevice()); - int f_bass_error = BASS_ErrorGetCode(); - if (f_bass_error == BASS_ERROR_DEVICE) { - ao_app->doBASSreset(); - BASS_ChannelSetDevice(m_stream_list[m_channel], BASS_GetDevice()); - } - BASS_ChannelPlay(m_stream_list[m_channel], false); BASS_ChannelSetSync(m_stream_list[m_channel], BASS_SYNC_DEV_FAIL, 0, ao_app->BASSreset, 0); diff --git a/src/aotextedit.cpp b/src/aotextedit.cpp deleted file mode 100644 index 22d9a62..0000000 --- a/src/aotextedit.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "aotextedit.h" - -AOTextEdit::AOTextEdit(QWidget *parent) : QPlainTextEdit(parent) -{ - this->setReadOnly(true); - - // connect(this, SIGNAL(returnPressed()), this, SLOT(on_enter_pressed())); -} - -void AOTextEdit::mouseDoubleClickEvent(QMouseEvent *e) -{ - QPlainTextEdit::mouseDoubleClickEvent(e); - - this->setReadOnly(false); -} - -void AOTextEdit::on_enter_pressed() { this->setReadOnly(true); } diff --git a/src/charselect.cpp b/src/charselect.cpp index 53269b5..8928f44 100644 --- a/src/charselect.cpp +++ b/src/charselect.cpp @@ -52,25 +52,25 @@ void Courtroom::construct_char_select() ui_char_taken->setText(tr("Taken")); ui_char_taken->setObjectName("ui_char_taken"); - connect(ui_char_list, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), - this, SLOT(on_char_list_double_clicked(QTreeWidgetItem *, int))); + connect(ui_char_list, &QTreeWidget::itemDoubleClicked, + this, &Courtroom::on_char_list_double_clicked); - connect(ui_back_to_lobby, SIGNAL(clicked()), this, - SLOT(on_back_to_lobby_clicked())); + connect(ui_back_to_lobby, &AOButton::clicked, this, + &Courtroom::on_back_to_lobby_clicked); - connect(ui_char_select_left, SIGNAL(clicked()), this, - SLOT(on_char_select_left_clicked())); - connect(ui_char_select_right, SIGNAL(clicked()), this, - SLOT(on_char_select_right_clicked())); + connect(ui_char_select_left, &AOButton::clicked, this, + &Courtroom::on_char_select_left_clicked); + connect(ui_char_select_right, &AOButton::clicked, this, + &Courtroom::on_char_select_right_clicked); - connect(ui_spectator, SIGNAL(clicked()), this, SLOT(on_spectator_clicked())); + connect(ui_spectator, &AOButton::clicked, this, &Courtroom::on_spectator_clicked); - connect(ui_char_search, SIGNAL(textEdited(const QString &)), this, - SLOT(on_char_search_changed())); - connect(ui_char_passworded, SIGNAL(stateChanged(int)), this, - SLOT(on_char_passworded_clicked())); - connect(ui_char_taken, SIGNAL(stateChanged(int)), this, - SLOT(on_char_taken_clicked())); + connect(ui_char_search, &QLineEdit::textEdited,this, + &Courtroom::on_char_search_changed); + connect(ui_char_passworded, &QCheckBox::stateChanged, this, + &Courtroom::on_char_passworded_clicked); + connect(ui_char_taken, &QCheckBox::stateChanged, this, + &Courtroom::on_char_taken_clicked); } @@ -116,7 +116,7 @@ void Courtroom::set_char_select_page() ui_char_select_left->hide(); ui_char_select_right->hide(); - for (AOCharButton *i_button : ui_char_button_list) { + for (AOCharButton *i_button : qAsConst(ui_char_button_list)) { i_button->reset(); i_button->hide(); i_button->move(0, 0); @@ -147,7 +147,7 @@ void Courtroom::set_char_select_page() void Courtroom::on_char_list_double_clicked(QTreeWidgetItem *p_item, int column) { - UNUSED(column); + Q_UNUSED(column); int cid = p_item->text(1).toInt(); if (cid == -1 && !p_item->isExpanded()) { p_item->setExpanded(true); @@ -164,8 +164,8 @@ void Courtroom::char_clicked(int n_char) { if (n_char != -1) { - QString char_ini_path = - ao_app->get_character_path(char_list.at(n_char).name, "char.ini"); + QString char_ini_path = ao_app->get_real_path( + ao_app->get_character_path(char_list.at(n_char).name, "char.ini")); qDebug() << "char_ini_path" << char_ini_path; @@ -298,9 +298,9 @@ void Courtroom::character_loading_finished() 100); ao_app->w_lobby->set_loading_value(loading_value); ao_app->w_lobby->set_loading_text( - tr("Generating chars:\n%1/%2") - .arg(QString::number(ao_app->generated_chars)) - .arg(QString::number(ao_app->char_list_size))); + tr("Generating chars:\n%1/%2").arg( + QString::number(ao_app->generated_chars), + QString::number(ao_app->char_list_size))); } } ui_char_list->expandAll(); diff --git a/src/chatlogpiece.cpp b/src/chatlogpiece.cpp index 05a924c..f4cb225 100644 --- a/src/chatlogpiece.cpp +++ b/src/chatlogpiece.cpp @@ -7,7 +7,7 @@ chatlogpiece::chatlogpiece() message = tr("UNKNOWN"); color = 0; action = ""; - datetime = QDateTime::currentDateTime().toUTC(); + datetime = QDateTime::currentDateTimeUtc(); } chatlogpiece::chatlogpiece(QString p_name, QString p_showname, @@ -18,7 +18,7 @@ chatlogpiece::chatlogpiece(QString p_name, QString p_showname, message = p_message; action = p_action; color = p_color; - datetime = QDateTime::currentDateTime().toUTC(); + datetime = QDateTime::currentDateTimeUtc(); } chatlogpiece::chatlogpiece(QString p_name, QString p_showname, diff --git a/src/courtroom.cpp b/src/courtroom.cpp index f551c9e..e549526 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -109,6 +109,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() log_newline = ao_app->get_log_newline(); log_margin = ao_app->get_log_margin(); log_timestamp = ao_app->get_log_timestamp(); + log_timestamp_format = ao_app->get_log_timestamp_format(); ui_ms_chatlog = new AOTextArea(this); ui_ms_chatlog->setReadOnly(true); @@ -150,7 +151,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_music_name->setText(tr("None")); ui_music_name->setAttribute(Qt::WA_TransparentForMouseEvents); ui_music_name->setObjectName("ui_music_name"); - + for (int i = 0; i < max_clocks; i++) { ui_clock[i] = new AOClockLabel(this); ui_clock[i]->setAttribute(Qt::WA_TransparentForMouseEvents); @@ -164,10 +165,12 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_ic_chat_name->setText(p_ao_app->get_default_showname()); ui_ic_chat_name->setObjectName("ui_ic_chat_name"); - ui_ic_chat_message = new AOLineEdit(this); + ui_ic_chat_message = new QLineEdit(this); ui_ic_chat_message->setFrame(false); ui_ic_chat_message->setPlaceholderText(tr("Message")); - ui_ic_chat_message->preserve_selection(true); + ui_ic_chat_message_filter = new AOLineEditFilter(); + ui_ic_chat_message_filter->preserve_selection = true; + ui_ic_chat_message->installEventFilter(ui_ic_chat_message_filter); ui_ic_chat_message->setObjectName("ui_ic_chat_message"); ui_vp_sticker = new StickerLayer(ui_viewport, ao_app); @@ -396,154 +399,154 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() construct_char_select(); - connect(keepalive_timer, SIGNAL(timeout()), this, SLOT(ping_server())); + connect(keepalive_timer, &QTimer::timeout, this, &Courtroom::ping_server); - connect(ui_vp_objection, SIGNAL(done()), this, SLOT(objection_done())); - connect(ui_vp_effect, SIGNAL(done()), this, SLOT(effect_done())); - connect(ui_vp_wtce, SIGNAL(done()), this, SLOT(effect_done())); - connect(ui_vp_player_char, SIGNAL(done()), this, SLOT(preanim_done())); - connect(ui_vp_player_char, SIGNAL(shake()), this, SLOT(do_screenshake())); - connect(ui_vp_player_char, SIGNAL(flash()), this, SLOT(do_flash())); - connect(ui_vp_player_char, SIGNAL(play_sfx(QString)), this, - SLOT(play_char_sfx(QString))); + connect(ui_vp_objection, &SplashLayer::done, this, &Courtroom::objection_done); + connect(ui_vp_effect, &EffectLayer::done, this, &Courtroom::effect_done); + connect(ui_vp_wtce, &SplashLayer::done, this, &Courtroom::effect_done); + connect(ui_vp_player_char, &CharLayer::done, this, &Courtroom::preanim_done); + connect(ui_vp_player_char, &CharLayer::shake, this, &Courtroom::do_screenshake); + connect(ui_vp_player_char, &CharLayer::flash, this, &Courtroom::do_flash); + connect(ui_vp_player_char, &CharLayer::play_sfx, this, + &Courtroom::play_char_sfx); - connect(text_delay_timer, SIGNAL(timeout()), this, - SLOT(start_chat_ticking())); + connect(text_delay_timer, &QTimer::timeout, this, + &Courtroom::start_chat_ticking); - connect(text_queue_timer, SIGNAL(timeout()), this, - SLOT(chatmessage_dequeue())); + connect(text_queue_timer, &QTimer::timeout, this, + &Courtroom::chatmessage_dequeue); - connect(sfx_delay_timer, SIGNAL(timeout()), this, SLOT(play_sfx())); + connect(sfx_delay_timer, &QTimer::timeout, this, &Courtroom::play_sfx); - connect(chat_tick_timer, SIGNAL(timeout()), this, SLOT(chat_tick())); + connect(chat_tick_timer, &QTimer::timeout, this, &Courtroom::chat_tick); - connect(ui_pos_dropdown, SIGNAL(currentIndexChanged(int)), this, - SLOT(on_pos_dropdown_changed(int))); - connect(ui_pos_dropdown, SIGNAL(editTextChanged(QString)), this, - SLOT(on_pos_dropdown_changed(QString))); - connect(ui_pos_remove, SIGNAL(clicked()), this, SLOT(on_pos_remove_clicked())); + connect(ui_pos_dropdown, QOverload::of(&QComboBox::currentIndexChanged), this, + QOverload::of(&Courtroom::on_pos_dropdown_changed)); + connect(ui_pos_dropdown, &QComboBox::editTextChanged, this, + QOverload::of(&Courtroom::on_pos_dropdown_changed)); + connect(ui_pos_remove, &AOButton::clicked, this, &Courtroom::on_pos_remove_clicked); - connect(ui_iniswap_dropdown, SIGNAL(currentIndexChanged(int)), this, - SLOT(on_iniswap_dropdown_changed(int))); - connect(ui_iniswap_dropdown, SIGNAL(customContextMenuRequested(QPoint)), this, - SLOT(on_iniswap_context_menu_requested(QPoint))); - connect(ui_iniswap_remove, SIGNAL(clicked()), this, - SLOT(on_iniswap_remove_clicked())); + connect(ui_iniswap_dropdown, QOverload::of(&QComboBox::currentIndexChanged), this, + &Courtroom::on_iniswap_dropdown_changed); + connect(ui_iniswap_dropdown, &QComboBox::customContextMenuRequested, this, + &Courtroom::on_iniswap_context_menu_requested); + connect(ui_iniswap_remove, &AOButton::clicked, this, + &Courtroom::on_iniswap_remove_clicked); - connect(ui_sfx_dropdown, SIGNAL(currentIndexChanged(int)), this, - SLOT(on_sfx_dropdown_changed(int))); - connect(ui_sfx_dropdown, SIGNAL(editTextChanged(QString)), this, - SLOT(on_sfx_dropdown_custom(QString))); - connect(ui_sfx_dropdown, SIGNAL(customContextMenuRequested(QPoint)), this, - SLOT(on_sfx_context_menu_requested(QPoint))); - connect(ui_sfx_remove, SIGNAL(clicked()), this, - SLOT(on_sfx_remove_clicked())); + connect(ui_sfx_dropdown, QOverload::of(&QComboBox::currentIndexChanged), this, + &Courtroom::on_sfx_dropdown_changed); + connect(ui_sfx_dropdown, &QComboBox::editTextChanged, this, + &Courtroom::on_sfx_dropdown_custom); + connect(ui_sfx_dropdown, &QComboBox::customContextMenuRequested, this, + &Courtroom::on_sfx_context_menu_requested); + connect(ui_sfx_remove, &AOButton::clicked, this, + &Courtroom::on_sfx_remove_clicked); - connect(ui_effects_dropdown, SIGNAL(currentIndexChanged(int)), this, - SLOT(on_effects_dropdown_changed(int))); - connect(ui_effects_dropdown, SIGNAL(customContextMenuRequested(QPoint)), this, - SLOT(on_effects_context_menu_requested(QPoint))); + connect(ui_effects_dropdown, QOverload::of(&QComboBox::currentIndexChanged), this, + &Courtroom::on_effects_dropdown_changed); + connect(ui_effects_dropdown, &QComboBox::customContextMenuRequested, this, + &Courtroom::on_effects_context_menu_requested); - connect(ui_music_search, SIGNAL(returnPressed()), this, - SLOT(on_music_search_return_pressed())); - connect(ui_mute_list, SIGNAL(clicked(QModelIndex)), this, - SLOT(on_mute_list_clicked(QModelIndex))); + connect(ui_music_search, &QLineEdit::returnPressed, this, + &Courtroom::on_music_search_return_pressed); + connect(ui_mute_list, &QListWidget::clicked, this, + &Courtroom::on_mute_list_clicked); - connect(ui_ic_chat_message, SIGNAL(returnPressed()), this, - SLOT(on_chat_return_pressed())); + connect(ui_ic_chat_message, &QLineEdit::returnPressed, this, + &Courtroom::on_chat_return_pressed); - connect(ui_ooc_chat_message, SIGNAL(returnPressed()), this, - SLOT(on_ooc_return_pressed())); + connect(ui_ooc_chat_message, &QLineEdit::returnPressed, this, + &Courtroom::on_ooc_return_pressed); - connect(ui_music_list, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), - this, SLOT(on_music_list_double_clicked(QTreeWidgetItem *, int))); - connect(ui_music_list, SIGNAL(customContextMenuRequested(QPoint)), this, - SLOT(on_music_list_context_menu_requested(QPoint))); + connect(ui_music_list, &QTreeWidget::itemDoubleClicked, + this, &Courtroom::on_music_list_double_clicked); + connect(ui_music_list, &QTreeWidget::customContextMenuRequested, this, + &Courtroom::on_music_list_context_menu_requested); - connect(ui_area_list, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, - SLOT(on_area_list_double_clicked(QTreeWidgetItem *, int))); + connect(ui_area_list, &QTreeWidget::itemDoubleClicked, this, + &Courtroom::on_area_list_double_clicked); - connect(ui_hold_it, SIGNAL(clicked()), this, SLOT(on_hold_it_clicked())); - connect(ui_objection, SIGNAL(clicked()), this, SLOT(on_objection_clicked())); - connect(ui_take_that, SIGNAL(clicked()), this, SLOT(on_take_that_clicked())); - connect(ui_custom_objection, SIGNAL(clicked()), this, - SLOT(on_custom_objection_clicked())); + connect(ui_hold_it, &AOButton::clicked, this, &Courtroom::on_hold_it_clicked); + connect(ui_objection, &AOButton::clicked, this, &Courtroom::on_objection_clicked); + connect(ui_take_that, &AOButton::clicked, this, &Courtroom::on_take_that_clicked); + connect(ui_custom_objection, &AOButton::clicked, this, + &Courtroom::on_custom_objection_clicked); connect(ui_custom_objection, - SIGNAL(customContextMenuRequested(const QPoint &)), this, - SLOT(show_custom_objection_menu(const QPoint &))); + &AOButton::customContextMenuRequested, this, + &Courtroom::show_custom_objection_menu); - connect(ui_realization, SIGNAL(clicked()), this, - SLOT(on_realization_clicked())); - connect(ui_screenshake, SIGNAL(clicked()), this, - SLOT(on_screenshake_clicked())); + connect(ui_realization, &AOButton::clicked, this, + &Courtroom::on_realization_clicked); + connect(ui_screenshake, &AOButton::clicked, this, + &Courtroom::on_screenshake_clicked); - connect(ui_mute, SIGNAL(clicked()), this, SLOT(on_mute_clicked())); + connect(ui_mute, &AOButton::clicked, this, &Courtroom::on_mute_clicked); - connect(ui_defense_minus, SIGNAL(clicked()), this, - SLOT(on_defense_minus_clicked())); - connect(ui_defense_plus, SIGNAL(clicked()), this, - SLOT(on_defense_plus_clicked())); - connect(ui_prosecution_minus, SIGNAL(clicked()), this, - SLOT(on_prosecution_minus_clicked())); - connect(ui_prosecution_plus, SIGNAL(clicked()), this, - SLOT(on_prosecution_plus_clicked())); + connect(ui_defense_minus, &AOButton::clicked, this, + &Courtroom::on_defense_minus_clicked); + connect(ui_defense_plus, &AOButton::clicked, this, + &Courtroom::on_defense_plus_clicked); + connect(ui_prosecution_minus, &AOButton::clicked, this, + &Courtroom::on_prosecution_minus_clicked); + connect(ui_prosecution_plus, &AOButton::clicked, this, + &Courtroom::on_prosecution_plus_clicked); - connect(ui_text_color, SIGNAL(currentIndexChanged(int)), this, - SLOT(on_text_color_changed(int))); + connect(ui_text_color, QOverload::of(&QComboBox::currentIndexChanged), this, + &Courtroom::on_text_color_changed); - connect(ui_music_slider, SIGNAL(valueChanged(int)), this, - SLOT(on_music_slider_moved(int))); - connect(ui_sfx_slider, SIGNAL(valueChanged(int)), this, - SLOT(on_sfx_slider_moved(int))); - connect(ui_blip_slider, SIGNAL(valueChanged(int)), this, - SLOT(on_blip_slider_moved(int))); + connect(ui_music_slider, &QSlider::valueChanged, this, + &Courtroom::on_music_slider_moved); + connect(ui_sfx_slider, &QSlider::valueChanged, this, + &Courtroom::on_sfx_slider_moved); + connect(ui_blip_slider, &QSlider::valueChanged, this, + &Courtroom::on_blip_slider_moved); - connect(ui_ooc_toggle, SIGNAL(clicked()), this, - SLOT(on_ooc_toggle_clicked())); + connect(ui_ooc_toggle, &AOButton::clicked, this, + &Courtroom::on_ooc_toggle_clicked); - connect(ui_music_search, SIGNAL(textChanged(QString)), this, - SLOT(on_music_search_edited(QString))); + connect(ui_music_search, &QLineEdit::textChanged, this, + &Courtroom::on_music_search_edited); - connect(ui_witness_testimony, SIGNAL(clicked()), this, - SLOT(on_witness_testimony_clicked())); - connect(ui_cross_examination, SIGNAL(clicked()), this, - SLOT(on_cross_examination_clicked())); - connect(ui_guilty, SIGNAL(clicked()), this, SLOT(on_guilty_clicked())); - connect(ui_not_guilty, SIGNAL(clicked()), this, - SLOT(on_not_guilty_clicked())); + connect(ui_witness_testimony, &AOButton::clicked, this, + &Courtroom::on_witness_testimony_clicked); + connect(ui_cross_examination, &AOButton::clicked, this, + &Courtroom::on_cross_examination_clicked); + connect(ui_guilty, &AOButton::clicked, this, &Courtroom::on_guilty_clicked); + connect(ui_not_guilty, &AOButton::clicked, this, + &Courtroom::on_not_guilty_clicked); - connect(ui_change_character, SIGNAL(clicked()), this, - SLOT(on_change_character_clicked())); - connect(ui_reload_theme, SIGNAL(clicked()), this, - SLOT(on_reload_theme_clicked())); - connect(ui_call_mod, SIGNAL(clicked()), this, SLOT(on_call_mod_clicked())); - connect(ui_settings, SIGNAL(clicked()), this, SLOT(on_settings_clicked())); - connect(ui_announce_casing, SIGNAL(clicked()), this, - SLOT(on_announce_casing_clicked())); - connect(ui_switch_area_music, SIGNAL(clicked()), this, - SLOT(on_switch_area_music_clicked())); + connect(ui_change_character, &AOButton::clicked, this, + &Courtroom::on_change_character_clicked); + connect(ui_reload_theme, &AOButton::clicked, this, + &Courtroom::on_reload_theme_clicked); + connect(ui_call_mod, &AOButton::clicked, this, &Courtroom::on_call_mod_clicked); + connect(ui_settings, &AOButton::clicked, this, &Courtroom::on_settings_clicked); + connect(ui_announce_casing, &AOButton::clicked, this, + &Courtroom::on_announce_casing_clicked); + connect(ui_switch_area_music, &AOButton::clicked, this, + &Courtroom::on_switch_area_music_clicked); - connect(ui_pre, SIGNAL(clicked()), this, SLOT(on_pre_clicked())); - connect(ui_flip, SIGNAL(clicked()), this, SLOT(on_flip_clicked())); - connect(ui_additive, SIGNAL(clicked()), this, SLOT(on_additive_clicked())); - connect(ui_guard, SIGNAL(clicked()), this, SLOT(on_guard_clicked())); - connect(ui_casing, SIGNAL(clicked()), this, SLOT(on_casing_clicked())); + connect(ui_pre, &AOButton::clicked, this, &Courtroom::on_pre_clicked); + connect(ui_flip, &AOButton::clicked, this, &Courtroom::on_flip_clicked); + connect(ui_additive, &AOButton::clicked, this, &Courtroom::on_additive_clicked); + connect(ui_guard, &AOButton::clicked, this, &Courtroom::on_guard_clicked); + connect(ui_casing, &AOButton::clicked, this, &Courtroom::on_casing_clicked); - connect(ui_showname_enable, SIGNAL(clicked()), this, - SLOT(on_showname_enable_clicked())); + connect(ui_showname_enable, &AOButton::clicked, this, + &Courtroom::on_showname_enable_clicked); - connect(ui_pair_button, SIGNAL(clicked()), this, SLOT(on_pair_clicked())); - connect(ui_pair_list, SIGNAL(clicked(QModelIndex)), this, - SLOT(on_pair_list_clicked(QModelIndex))); - connect(ui_pair_offset_spinbox, SIGNAL(valueChanged(int)), this, - SLOT(on_pair_offset_changed(int))); - connect(ui_pair_vert_offset_spinbox, SIGNAL(valueChanged(int)), this, - SLOT(on_pair_vert_offset_changed(int))); - connect(ui_pair_order_dropdown, SIGNAL(currentIndexChanged(int)), this, - SLOT(on_pair_order_dropdown_changed(int))); + connect(ui_pair_button, &AOButton::clicked, this, &Courtroom::on_pair_clicked); + connect(ui_pair_list, &QListWidget::clicked, this, + &Courtroom::on_pair_list_clicked); + connect(ui_pair_offset_spinbox, QOverload::of(&QSpinBox::valueChanged), this, + &Courtroom::on_pair_offset_changed); + connect(ui_pair_vert_offset_spinbox, QOverload::of(&QSpinBox::valueChanged), this, + &Courtroom::on_pair_vert_offset_changed); + connect(ui_pair_order_dropdown, QOverload::of(&QComboBox::currentIndexChanged), this, + &Courtroom::on_pair_order_dropdown_changed); - connect(ui_evidence_button, SIGNAL(clicked()), this, - SLOT(on_evidence_button_clicked())); + connect(ui_evidence_button, &AOButton::clicked, this, + &Courtroom::on_evidence_button_clicked); set_widgets(); @@ -583,12 +586,12 @@ void Courtroom::set_mute_list() QStringList sorted_mute_list; - for (char_type i_char : char_list) + for (const char_type &i_char : qAsConst(char_list)) sorted_mute_list.append(i_char.name); sorted_mute_list.sort(); - for (QString i_name : sorted_mute_list) { + for (const QString &i_name : sorted_mute_list) { // mute_map.insert(i_name, false); ui_mute_list->addItem(i_name); } @@ -598,12 +601,12 @@ void Courtroom::set_pair_list() { QStringList sorted_pair_list; - for (char_type i_char : char_list) + for (const char_type &i_char : qAsConst(char_list)) sorted_pair_list.append(i_char.name); sorted_pair_list.sort(); - for (QString i_name : sorted_pair_list) { + for (const QString &i_name : sorted_pair_list) { ui_pair_list->addItem(i_name); } } @@ -612,7 +615,7 @@ 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); + QSettings settings(ao_app->get_real_path(ao_app->get_theme_path(filename, ao_app->current_theme)), QSettings::IniFormat); ao_app->default_theme = settings.value("default_theme", "default").toString(); set_fonts(); @@ -706,12 +709,14 @@ void Courtroom::set_widgets() 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_timestamp != ao_app->get_log_timestamp() || + log_timestamp_format != ao_app->get_log_timestamp_format(); 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_timestamp_format = ao_app->get_log_timestamp_format(); if (regenerate) regenerate_ic_chatlog(); @@ -767,7 +772,7 @@ void Courtroom::set_widgets() ui_music_list->resetIndentation(); else ui_music_list->setIndentation(music_list_indentation.toInt()); - + 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); @@ -1222,6 +1227,12 @@ void Courtroom::set_stylesheet(QWidget *widget) void Courtroom::set_stylesheets() { set_stylesheet(this); + this->setStyleSheet( + "QFrame { background-color:transparent; } " + "QAbstractItemView { background-color: transparent; color: black; } " + "QLineEdit { background-color:transparent; }" + + this->styleSheet() + ); } void Courtroom::set_window_title(QString p_title) @@ -1326,7 +1337,7 @@ void Courtroom::set_background(QString p_background, bool display) // Populate the dropdown list with all pos that exist on this bg QStringList pos_list = {}; - for (QString key : default_pos.keys()) { + for (const QString &key : default_pos) { if (file_exists(ao_app->get_image_suffix( ao_app->get_background_path(default_pos[key]))) || // if we have 2.8-style positions, e.g. def.png, wit.webp, hld.apng file_exists( @@ -1334,7 +1345,7 @@ void Courtroom::set_background(QString p_background, bool display) pos_list.append(default_pos[key]); } } - for (QString pos : ao_app->read_design_ini("positions", ao_app->get_background_path("design.ini")).split(",")) { + for (const QString &pos : ao_app->read_design_ini("positions", ao_app->get_background_path("design.ini")).split(",")) { if (file_exists(ao_app->get_image_suffix(ao_app->get_background_path(pos)))) { pos_list.append(pos); } @@ -1492,11 +1503,11 @@ void Courtroom::update_character(int p_cid) custom_obj_menu->setDefaultAction(action); objection_custom = ""; } - if (dir_exists( - ao_app->get_character_path(current_char, "custom_objections"))) { - ui_custom_objection->show(); - QDir directory( + QString custom_objection_dir = ao_app->get_real_path( ao_app->get_character_path(current_char, "custom_objections")); + if (dir_exists(custom_objection_dir)) { + ui_custom_objection->show(); + QDir directory(custom_objection_dir); QStringList custom_obj = directory.entryList(QStringList() << "*.png" << "*.gif" << "*.apng" @@ -1631,7 +1642,7 @@ void Courtroom::list_music() treeItem->setText(0, i_song_listname); treeItem->setText(1, i_song); - QString song_path = ao_app->get_music_path(i_song); + QString song_path = ao_app->get_real_path(ao_app->get_music_path(i_song)); if (file_exists(song_path)) treeItem->setBackground(0, found_brush); @@ -1661,7 +1672,7 @@ void Courtroom::list_areas() int n_listed_areas = 0; for (int n_area = 0; n_area < area_list.size(); ++n_area) { - QString i_area = ""; + QString i_area = ""; i_area.append(area_list.at(n_area)); if (ao_app->arup_enabled) { @@ -1751,7 +1762,7 @@ void Courtroom::append_server_chatmessage(QString p_name, QString p_message, ui_server_chatlog->append_chatmessage(p_name, p_message, color); if (ao_app->get_auto_logging_enabled() && !ao_app->log_filename.isEmpty()) { - QString full = "[OOC][" + QDateTime::currentDateTime().toUTC().toString() + "] " + p_name + ": " + p_message; + QString full = "[OOC][" + QDateTime::currentDateTimeUtc().toString() + "] " + p_name + ": " + p_message; ao_app->append_to_file(full, ao_app->log_filename, true); } } @@ -2190,7 +2201,7 @@ void Courtroom::log_chatmessage(QString f_message, int f_char_id, QString f_show objection_mod = f_objection_mod.toInt(); } - QString f_custom_theme = ao_app->get_chat(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) { @@ -2257,7 +2268,7 @@ void Courtroom::log_chatmessage(QString f_message, int f_char_id, QString f_show if ((f_log_mode != IO_ONLY) && // if we're not in I/O only mode, f_message.isEmpty() && // our current message is a blankpost, !ic_chatlog_history.isEmpty() && // the chat log isn't empty, - last_ic_message == f_displayname + ":" && // the chat log's last message is a blank post, and + last_ic_message == f_displayname + ":" && // the chat log's last message is a blank post, and last_ic_message.mid(0, last_ic_message.lastIndexOf(":")) == f_displayname) // the blankpost's showname is the same as ours return; // Skip adding message switch (f_log_mode) { @@ -2325,7 +2336,7 @@ bool Courtroom::handle_objection() "custom", m_chatmessage[CHAR_NAME], ao_app->get_chat(m_chatmessage[CHAR_NAME])); } - break; + break; m_chatmessage[EMOTE_MOD] = 1; } ui_vp_objection->load_image( @@ -2440,6 +2451,7 @@ void Courtroom::display_pair_character(QString other_charid, QString other_offse // Play the other pair character's idle animation QString filename = "(a)" + m_chatmessage[OTHER_EMOTE]; + ui_vp_sideplayer_char->set_play_once(false); ui_vp_sideplayer_char->load_image(filename, m_chatmessage[OTHER_NAME], 0, false); } @@ -2751,7 +2763,7 @@ void Courtroom::handle_callwords() // Obtain the current call words (Really? It does File I/O on every single message???) QStringList call_words = ao_app->get_call_words(); // Loop through each word in the call words list - for (QString word : call_words) { + for (const QString &word : qAsConst(call_words)) { // 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 @@ -2771,7 +2783,7 @@ void Courtroom::display_evidence_image() 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_evi_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 = !(side == "def" || side == "hlp" || side == "jud" || side == "jur"); @@ -3119,7 +3131,7 @@ void Courtroom::append_ic_text(QString p_text, QString p_name, QString p_action, if (log_timestamp) { if (timestamp.isValid()) { ui_ic_chatlog->textCursor().insertText( - "[" + timestamp.toString("h:mm:ss AP") + "] ", normal); + "[" + timestamp.toString(log_timestamp_format) + "] ", normal); } else { qDebug() << "could not insert invalid timestamp"; } @@ -3275,7 +3287,7 @@ void Courtroom::play_preanim(bool immediate) void Courtroom::preanim_done() { // Currently, someone's talking over us mid-preanim... - if (anim_state != 1 && anim_state != 4) + if (anim_state != 1 && anim_state != 4 && anim_state != 5) return; anim_state = 1; switch(m_chatmessage[DESK_MOD].toInt()) { @@ -3435,7 +3447,7 @@ void Courtroom::chat_tick() } ui_vp_chat_arrow->transform_mode = ao_app->get_misc_scaling(f_custom_theme); ui_vp_chat_arrow->load_image("chat_arrow", f_custom_theme); // Chat stopped being processed, indicate that. - QString f_message_filtered = filter_ic_text(f_message, true, -1, m_chatmessage[TEXT_COLOR].toInt()); + QString f_message_filtered = filter_ic_text(f_message, true, -1, m_chatmessage[TEXT_COLOR].toInt()); for (int c = 0; c < max_colors; ++c) { additive_previous = additive_previous.replace("$c" + QString::number(c), char_color_rgb_list.at(c).name(QColor::HexRgb)); f_message_filtered = f_message_filtered.replace("$c" + QString::number(c), char_color_rgb_list.at(c).name(QColor::HexRgb)); @@ -3740,7 +3752,7 @@ void Courtroom::set_self_offset(QString p_list) { int self_offset_v; if (self_offsets.length() <= 1) self_offset_v = 0; - else + else self_offset_v = self_offsets[1].toInt(); ui_vp_player_char->move(ui_viewport->width() * self_offset / 100, ui_viewport->height() * self_offset_v / 100); } @@ -3875,7 +3887,7 @@ void Courtroom::handle_song(QStringList *p_contents) void Courtroom::handle_wtce(QString p_wtce, int variant) { - QString sfx_file = "courtroom_sounds.ini"; + //QString sfx_file = "courtroom_sounds.ini"; QString bg_misc = ao_app->read_design_ini("misc", ao_app->get_background_path("design.ini")); QString sfx_name; QString filename; @@ -3987,7 +3999,9 @@ void Courtroom::on_ooc_return_pressed() { QString ooc_message = ui_ooc_chat_message->text(); - if (ooc_message.startsWith("/pos")) { + //We ignore it when the server is compatible with 2.8 + //Using an arbitrary 2.8 feature flag certainly won't cause issues someday. + if (ooc_message.startsWith("/pos") & !ao_app->effects_enabled) { if (ooc_message == "/pos jud") { toggle_judge_buttons(true); } @@ -3995,149 +4009,13 @@ void Courtroom::on_ooc_return_pressed() toggle_judge_buttons(false); } } - else if (ooc_message.startsWith("/settings")) { - ui_ooc_chat_message->clear(); - ao_app->call_settings_menu(); - append_server_chatmessage("CLIENT", tr("You opened the settings menu."), - "1"); - return; - } - else if (ooc_message.startsWith("/pair")) { - ui_ooc_chat_message->clear(); - ooc_message.remove(0, 6); - bool ok; - int whom = ooc_message.toInt(&ok); - if (ok) { - if (whom > -1) { - other_charid = whom; - QString msg = tr("You will now pair up with %1 if they also choose " - "your character in return.") - .arg(char_list.at(whom).name); - append_server_chatmessage("CLIENT", msg, "1"); - } - else { - other_charid = -1; - append_server_chatmessage( - "CLIENT", tr("You are no longer paired with anyone."), "1"); - } - } - else { - append_server_chatmessage("CLIENT", - tr("Are you sure you typed that well? The char " - "ID could not be recognised."), - "1"); - } - return; - } - else if (ooc_message.startsWith("/offset")) { - ui_ooc_chat_message->clear(); - ooc_message.remove(0, 8); - - bool ok; - int off = ooc_message.toInt(&ok); - if (ok) { - if (off >= -100 && off <= 100) { - char_offset = off; - QString msg = - tr("You have set your offset to %1%%.").arg(QString::number(off)); - append_server_chatmessage("CLIENT", msg, "1"); - } - else { - append_server_chatmessage( - "CLIENT", tr("Your offset must be between -100% and 100%!"), "1"); - } - } - else { - append_server_chatmessage("CLIENT", - tr("That offset does not look like one."), "1"); - } - return; - } - else if (ooc_message.startsWith("/voffset")) { - ui_ooc_chat_message->clear(); - ooc_message.remove(0, 8); - - bool ok; - int off = ooc_message.toInt(&ok); - if (ok) { - if (off >= -100 && off <= 100) { - char_vert_offset = off; - QString msg = tr("You have set your vertical offset to %1%%.") - .arg(QString::number(off)); - append_server_chatmessage("CLIENT", msg, "1"); - } - else { - append_server_chatmessage( - "CLIENT", - tr("Your vertical offset must be between -100% and 100%!"), "1"); - } - } - else { - append_server_chatmessage( - "CLIENT", tr("That vertical offset does not look like one."), "1"); - } - return; - } - else if (ooc_message.startsWith("/switch_am")) { - append_server_chatmessage( - "CLIENT", tr("You switched your music and area list."), "1"); - on_switch_area_music_clicked(); - ui_ooc_chat_message->clear(); - return; - } - else if (ooc_message.startsWith("/enable_blocks")) { - append_server_chatmessage("CLIENT", - tr("You have forcefully enabled features that " - "the server may not support. You may not be " - "able to talk IC, or worse, because of this."), - "1"); - ao_app->cccc_ic_support_enabled = true; - ao_app->arup_enabled = true; - ao_app->modcall_reason_enabled = true; - on_reload_theme_clicked(); - ui_ooc_chat_message->clear(); - return; - } - else if (ooc_message.startsWith("/non_int_pre")) { - if (ui_immediate->isChecked()) - append_server_chatmessage( - "CLIENT", tr("Your pre-animations interrupt again."), "1"); - else - append_server_chatmessage( - "CLIENT", tr("Your pre-animations will not interrupt text."), "1"); - ui_immediate->setChecked(!ui_immediate->isChecked()); - ui_ooc_chat_message->clear(); - return; - } - else if (ooc_message.startsWith("/save_chatlog")) { - QFile file("chatlog.txt"); - - if (!file.open(QIODevice::WriteOnly | QIODevice::Text | - QIODevice::Truncate)) { - append_server_chatmessage( - "CLIENT", tr("Couldn't open chatlog.txt to write into."), "1"); - ui_ooc_chat_message->clear(); - return; - } - - QTextStream out(&file); - out.setCodec("UTF-8"); - - foreach (chatlogpiece item, ic_chatlog_history) { - out << item.get_full() << '\n'; - } - - file.close(); - - append_server_chatmessage("CLIENT", tr("The IC chatlog has been saved."), - "1"); - ui_ooc_chat_message->clear(); - return; - } - else if (ooc_message.startsWith("/load_case")) { + if (ooc_message.startsWith("/load_case")) { +#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) QStringList command = ooc_message.split(" ", QString::SkipEmptyParts); - +#else + QStringList command = ooc_message.split(" ", Qt::SkipEmptyParts); +#endif QDir casefolder("base/cases"); if (!casefolder.exists()) { QDir::current().mkdir("base/" + casefolder.dirName()); @@ -4234,8 +4112,11 @@ void Courtroom::on_ooc_return_pressed() return; } else if (ooc_message.startsWith("/save_case")) { +#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) QStringList command = ooc_message.split(" ", QString::SkipEmptyParts); - +#else + QStringList command = ooc_message.split(" ", Qt::SkipEmptyParts); +#endif QDir casefolder("base/cases"); if (!casefolder.exists()) { QDir::current().mkdir("base/" + casefolder.dirName()); @@ -4429,8 +4310,9 @@ void Courtroom::set_iniswap_dropdown() ui_iniswap_remove->hide(); return; } - QStringList iniswaps = ao_app->get_list_file( - ao_app->get_character_path(char_list.at(m_cid).name, "iniswaps.ini")) + ao_app->get_list_file(ao_app->get_base_path() + "iniswaps.ini"); + QStringList iniswaps = + ao_app->get_list_file(ao_app->get_character_path(char_list.at(m_cid).name, "iniswaps.ini")) + + ao_app->get_list_file(ao_app->get_base_path() + "iniswaps.ini"); iniswaps.removeDuplicates(); iniswaps.prepend(char_list.at(m_cid).name); if (iniswaps.size() <= 0) { @@ -4486,7 +4368,8 @@ void Courtroom::on_iniswap_context_menu_requested(const QPoint &pos) menu->setAttribute(Qt::WA_DeleteOnClose); menu->addSeparator(); - if (file_exists(ao_app->get_character_path(current_char, "char.ini"))) + if (file_exists(ao_app->get_real_path( + ao_app->get_character_path(current_char, "char.ini")))) menu->addAction(QString("Edit " + current_char + "/char.ini"), this, SLOT(on_iniswap_edit_requested())); if (ui_iniswap_dropdown->itemText(ui_iniswap_dropdown->currentIndex()) != @@ -4497,7 +4380,7 @@ void Courtroom::on_iniswap_context_menu_requested(const QPoint &pos) } void Courtroom::on_iniswap_edit_requested() { - QString p_path = ao_app->get_character_path(current_char, "char.ini"); + QString p_path = ao_app->get_real_path(ao_app->get_character_path(current_char, "char.ini")); if (!file_exists(p_path)) return; QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); @@ -4536,7 +4419,7 @@ void Courtroom::set_sfx_dropdown() ao_app->get_base_path() + "soundlist.ini"); QStringList display_sounds; - for (QString sound : sound_list) { + for (const QString &sound : qAsConst(sound_list)) { QStringList unpacked = sound.split("="); QString display = unpacked[0].trimmed(); if (unpacked.size() > 1) @@ -4556,7 +4439,7 @@ void Courtroom::set_sfx_dropdown() void Courtroom::on_sfx_dropdown_changed(int p_index) { - UNUSED(p_index); + Q_UNUSED(p_index); ui_ic_chat_message->setFocus(); ui_sfx_remove->hide(); custom_sfx = ""; @@ -4574,7 +4457,8 @@ void Courtroom::on_sfx_context_menu_requested(const QPoint &pos) menu->setAttribute(Qt::WA_DeleteOnClose); menu->addSeparator(); - if (file_exists(ao_app->get_character_path(current_char, "soundlist.ini"))) + if (file_exists(ao_app->get_real_path( + ao_app->get_character_path(current_char, "soundlist.ini")))) menu->addAction(QString("Edit " + current_char + "/soundlist.ini"), this, SLOT(on_sfx_edit_requested())); else @@ -4587,10 +4471,10 @@ void Courtroom::on_sfx_context_menu_requested(const QPoint &pos) void Courtroom::on_sfx_edit_requested() { - QString p_path = ao_app->get_character_path(current_char, "soundlist.ini"); + QString p_path = ao_app->get_real_path(ao_app->get_character_path(current_char, "soundlist.ini")); if (!file_exists(p_path)) { p_path = ao_app->get_base_path() + "soundlist.ini"; - } + } QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); } @@ -4623,12 +4507,11 @@ void Courtroom::set_effects_dropdown() // ICON-MAKING HELL QString p_effect = ao_app->read_char_ini(current_char, "effects", "Options"); - 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_theme_path("effects/icons/", "default"); + VPath custom_path("misc/" + p_effect + "/icons/"); + VPath theme_path = ao_app->get_theme_path("effects/icons/"); + VPath 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); + VPath entry = VPath(ui_effects_dropdown->itemText(i)); QString iconpath = ao_app->get_image_suffix(custom_path + entry); if (!file_exists(iconpath)) { iconpath = ao_app->get_image_suffix(theme_path + entry); @@ -4662,9 +4545,9 @@ void Courtroom::on_effects_context_menu_requested(const QPoint &pos) } void Courtroom::on_effects_edit_requested() { - QString p_path = ao_app->get_theme_path("effects/"); + QString p_path = ao_app->get_real_path(ao_app->get_theme_path("effects/")); if (!dir_exists(p_path)) { - p_path = ao_app->get_theme_path("effects/", "default"); + p_path = ao_app->get_real_path(ao_app->get_theme_path("effects/", "default")); if (!dir_exists(p_path)) { return; } @@ -4674,7 +4557,7 @@ void Courtroom::on_effects_edit_requested() void Courtroom::on_character_effects_edit_requested() { QString p_effect = ao_app->read_char_ini(current_char, "effects", "Options"); - QString p_path = ao_app->get_base_path() + "misc/" + p_effect + "/"; + QString p_path = ao_app->get_real_path(VPath("misc/" + p_effect + "/")); if (!dir_exists(p_path)) return; @@ -4781,7 +4664,7 @@ void Courtroom::on_pair_list_clicked(QModelIndex p_index) // Redo the character list. QStringList sorted_pair_list; - for (char_type i_char : char_list) + for (const char_type &i_char : qAsConst(char_list)) sorted_pair_list.append(i_char.name); sorted_pair_list.sort(); @@ -4818,32 +4701,32 @@ void Courtroom::on_music_list_context_menu_requested(const QPoint &pos) { QMenu *menu = new QMenu(this); menu->setAttribute(Qt::WA_DeleteOnClose); - menu->addAction(QString(tr("Stop Current Song")), this, SLOT(music_stop())); - menu->addAction(QString(tr("Play Random Song")), this, SLOT(music_random())); + menu->addAction(QString(tr("Stop Current Song")), this, &Courtroom::music_stop); + menu->addAction(QString(tr("Play Random Song")), this, &Courtroom::music_random); menu->addSeparator(); menu->addAction(QString(tr("Expand All Categories")), this, - SLOT(music_list_expand_all())); + &Courtroom::music_list_expand_all); menu->addAction(QString(tr("Collapse All Categories")), this, - SLOT(music_list_collapse_all())); + &Courtroom::music_list_collapse_all); menu->addSeparator(); menu->addAction(new QAction(tr("Fade Out Previous"), this)); menu->actions().back()->setCheckable(true); menu->actions().back()->setChecked(music_flags & FADE_OUT); - connect(menu->actions().back(), SIGNAL(toggled(bool)), this, - SLOT(music_fade_out(bool))); + connect(menu->actions().back(), &QAction::toggled, this, + &Courtroom::music_fade_out); menu->addAction(new QAction(tr("Fade In"), this)); menu->actions().back()->setCheckable(true); menu->actions().back()->setChecked(music_flags & FADE_IN); - connect(menu->actions().back(), SIGNAL(toggled(bool)), this, - SLOT(music_fade_in(bool))); + connect(menu->actions().back(), &QAction::toggled, this, + &Courtroom::music_fade_in); menu->addAction(new QAction(tr("Synchronize"), this)); menu->actions().back()->setCheckable(true); menu->actions().back()->setChecked(music_flags & SYNC_POS); - connect(menu->actions().back(), SIGNAL(toggled(bool)), this, - SLOT(music_synchronize(bool))); + connect(menu->actions().back(), &QAction::toggled, this, + &Courtroom::music_synchronize); menu->popup(ui_music_list->mapToGlobal(pos)); } @@ -4908,7 +4791,7 @@ void Courtroom::music_stop(bool no_effects) // If the fake song is not present in the music list if (!music_list.contains(fake_song)) { // Loop through our music list - for (QString song : music_list) { + for (const QString &song : qAsConst(music_list)) { // Pick first song that does not contain a file extension if (!song.contains('.')) { // Use it as a fake song as the server we're working with must recognize song categories @@ -4936,7 +4819,7 @@ void Courtroom::music_stop(bool no_effects) void Courtroom::on_area_list_double_clicked(QTreeWidgetItem *p_item, int column) { column = 0; // The metadata - UNUSED(column); // so gcc shuts up + Q_UNUSED(column); // so gcc shuts up QString p_area = p_item->text(0); QStringList packet_contents; diff --git a/src/debug_functions.cpp b/src/debug_functions.cpp index 1613a7d..456aee8 100644 --- a/src/debug_functions.cpp +++ b/src/debug_functions.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/src/demoserver.cpp b/src/demoserver.cpp index ee0fcf2..db5e1bc 100644 --- a/src/demoserver.cpp +++ b/src/demoserver.cpp @@ -97,7 +97,7 @@ void DemoServer::recv_data() QStringList packet_list = in_data.split("%", QString::SplitBehavior(QString::SkipEmptyParts)); - for (QString packet : packet_list) { + for (const QString &packet : packet_list) { AOPacket ao_packet(packet); handle_packet(ao_packet); } @@ -297,7 +297,7 @@ void DemoServer::load_demo(QString filename) QTextStream out(&demo_file); out.setCodec("UTF-8"); out << p_demo_data.dequeue(); - for (QString line : p_demo_data) { + for (const QString &line : qAsConst(p_demo_data)) { out << "\n" << line; } demo_file.flush(); diff --git a/src/emotes.cpp b/src/emotes.cpp index 8272007..541a6e2 100644 --- a/src/emotes.cpp +++ b/src/emotes.cpp @@ -15,13 +15,13 @@ void Courtroom::initialize_emotes() ui_emote_dropdown = new QComboBox(this); ui_emote_dropdown->setObjectName("ui_emote_dropdown"); - connect(ui_emote_left, SIGNAL(clicked()), this, - SLOT(on_emote_left_clicked())); - connect(ui_emote_right, SIGNAL(clicked()), this, - SLOT(on_emote_right_clicked())); + connect(ui_emote_left, &AOButton::clicked, this, + &Courtroom::on_emote_left_clicked); + connect(ui_emote_right, &AOButton::clicked, this, + &Courtroom::on_emote_right_clicked); - connect(ui_emote_dropdown, SIGNAL(activated(int)), this, - SLOT(on_emote_dropdown_changed(int))); + connect(ui_emote_dropdown, QOverload::of(&QComboBox::activated), this, + &Courtroom::on_emote_dropdown_changed); } void Courtroom::refresh_emotes() @@ -74,8 +74,8 @@ void Courtroom::refresh_emotes() f_emote->set_id(n); - connect(f_emote, SIGNAL(emote_clicked(int)), this, - SLOT(on_emote_clicked(int))); + connect(f_emote, &AOEmoteButton::emote_clicked, this, + &Courtroom::on_emote_clicked); ++x_mod_count; @@ -96,7 +96,7 @@ void Courtroom::set_emote_page() ui_emote_left->hide(); ui_emote_right->hide(); - for (AOEmoteButton *i_button : ui_emote_list) { + for (AOEmoteButton *i_button : qAsConst(ui_emote_list)) { i_button->hide(); } diff --git a/src/evidence.cpp b/src/evidence.cpp index 2cc1d75..fc305d2 100644 --- a/src/evidence.cpp +++ b/src/evidence.cpp @@ -6,7 +6,9 @@ void Courtroom::initialize_evidence() ui_evidence->setObjectName("ui_evidence"); // ui_evidence_name = new QLabel(ui_evidence); - ui_evidence_name = new AOLineEdit(ui_evidence); + ui_evidence_name = new QLineEdit(ui_evidence); + ui_evidence_name_filter = new AOLineEditFilter(); + ui_evidence_name->installEventFilter(ui_evidence_name_filter); ui_evidence_name->setAlignment(Qt::AlignCenter); ui_evidence_name->setFrame(false); ui_evidence_name->setObjectName("ui_evidence_name"); @@ -41,11 +43,14 @@ void Courtroom::initialize_evidence() ui_evidence_delete = new AOButton(ui_evidence_overlay, ao_app); ui_evidence_delete->setToolTip(tr("Destroy this piece of evidence")); ui_evidence_delete->setObjectName("ui_evidence_delete"); - ui_evidence_image_name = new AOLineEdit(ui_evidence_overlay); + ui_evidence_image_name = new QLineEdit(ui_evidence_overlay); + ui_evidence_image_name_filter = new AOLineEditFilter(); + ui_evidence_image_name->installEventFilter(ui_evidence_image_name_filter); ui_evidence_image_name->setObjectName("ui_evidence_image_name"); ui_evidence_image_button = new AOButton(ui_evidence_overlay, ao_app); ui_evidence_image_button->setText(tr("Choose..")); ui_evidence_image_button->setObjectName("ui_evidence_image_button"); + ui_evidence_image_button->setDisabled(true); ui_evidence_x = new AOButton(ui_evidence_overlay, ao_app); ui_evidence_x->setToolTip( tr("Close the evidence display/editing overlay.\n" @@ -56,50 +61,51 @@ void Courtroom::initialize_evidence() "evidence and send them to server.")); ui_evidence_ok->setObjectName("ui_evidence_ok"); - ui_evidence_description = new AOTextEdit(ui_evidence_overlay); + ui_evidence_description = new QPlainTextEdit(ui_evidence_overlay); ui_evidence_description->setFrameStyle(QFrame::NoFrame); ui_evidence_description->setToolTip( - tr("Double-click to edit. Press [X] to update your changes.")); + tr("Click the pencil icon to edit. Press [X] to update your changes.")); ui_evidence_description->setObjectName("ui_evidence_description"); - connect(ui_evidence_name, SIGNAL(returnPressed()), this, - SLOT(on_evidence_name_edited())); - connect(ui_evidence_name, SIGNAL(double_clicked()), this, - SLOT(on_evidence_name_double_clicked())); - connect(ui_evidence_left, SIGNAL(clicked()), this, - SLOT(on_evidence_left_clicked())); - connect(ui_evidence_right, SIGNAL(clicked()), this, - SLOT(on_evidence_right_clicked())); - connect(ui_evidence_present, SIGNAL(clicked()), this, - SLOT(on_evidence_present_clicked())); - connect(ui_evidence_switch, SIGNAL(clicked()), this, - SLOT(on_evidence_switch_clicked())); - connect(ui_evidence_transfer, SIGNAL(clicked()), this, - SLOT(on_evidence_transfer_clicked())); - connect(ui_evidence_save, SIGNAL(clicked()), this, - SLOT(on_evidence_save_clicked())); - connect(ui_evidence_load, SIGNAL(clicked()), this, - SLOT(on_evidence_load_clicked())); + ui_evidence_edit = new AOButton(ui_evidence_overlay, ao_app); + ui_evidence_edit->setToolTip(tr("Edit this piece of evidence.")); + ui_evidence_edit->setObjectName("ui_evidence_edit"); - connect(ui_evidence_delete, SIGNAL(clicked()), this, - SLOT(on_evidence_delete_clicked())); - connect(ui_evidence_image_name, SIGNAL(returnPressed()), this, - SLOT(on_evidence_image_name_edited())); - connect(ui_evidence_image_name, SIGNAL(double_clicked()), this, - SLOT(on_evidence_image_name_double_clicked())); - connect(ui_evidence_image_button, SIGNAL(clicked()), this, - SLOT(on_evidence_image_button_clicked())); - connect(ui_evidence_x, SIGNAL(clicked()), this, - SLOT(on_evidence_x_clicked())); - connect(ui_evidence_ok, SIGNAL(clicked()), this, - SLOT(on_evidence_ok_clicked())); + connect(ui_evidence_name, &QLineEdit::returnPressed, this, + &Courtroom::on_evidence_name_edited); + connect(ui_evidence_left, &AOButton::clicked, this, + &Courtroom::on_evidence_left_clicked); + connect(ui_evidence_right, &AOButton::clicked, this, + &Courtroom::on_evidence_right_clicked); + connect(ui_evidence_present, &AOButton::clicked, this, + &Courtroom::on_evidence_present_clicked); + connect(ui_evidence_switch, &AOButton::clicked, this, + &Courtroom::on_evidence_switch_clicked); + connect(ui_evidence_transfer, &AOButton::clicked, this, + &Courtroom::on_evidence_transfer_clicked); + connect(ui_evidence_save, &AOButton::clicked, this, + &Courtroom::on_evidence_save_clicked); + connect(ui_evidence_load, &AOButton::clicked, this, + &Courtroom::on_evidence_load_clicked); - connect(ui_evidence_name, SIGNAL(textChanged(QString)), this, - SLOT(on_evidence_edited())); - connect(ui_evidence_image_name, SIGNAL(textChanged(QString)), this, - SLOT(on_evidence_edited())); - connect(ui_evidence_description, SIGNAL(textChanged()), this, - SLOT(on_evidence_edited())); + connect(ui_evidence_delete, &AOButton::clicked, this, + &Courtroom::on_evidence_delete_clicked); + connect(ui_evidence_image_name, &QLineEdit::returnPressed, this, + &Courtroom::on_evidence_image_name_edited); + connect(ui_evidence_image_button, &AOButton::clicked, this, + &Courtroom::on_evidence_image_button_clicked); + connect(ui_evidence_x, &AOButton::clicked, this, + &Courtroom::on_evidence_x_clicked); + connect(ui_evidence_ok, &AOButton::clicked, this, + &Courtroom::on_evidence_ok_clicked); + + connect(ui_evidence_name, &QLineEdit::textChanged, this, + &Courtroom::on_evidence_edited); + connect(ui_evidence_image_name, &QLineEdit::textChanged, this, + &Courtroom::on_evidence_image_name_edited); + connect(ui_evidence_description, &QPlainTextEdit::textChanged, this, + &Courtroom::on_evidence_edited); + connect(ui_evidence_edit, &AOButton::clicked, this, &Courtroom::on_evidence_edit_clicked); ui_evidence->hide(); } @@ -156,6 +162,9 @@ void Courtroom::refresh_evidence() set_size_and_pos(ui_evidence_ok, "evidence_ok"); ui_evidence_ok->set_image("evidence_ok"); + set_size_and_pos(ui_evidence_edit, "evidence_edit"); + ui_evidence_edit->set_image("evidence_edit"); + set_size_and_pos(ui_evidence_switch, "evidence_switch"); if (current_evidence_global) { ui_evidence_switch->set_image("evidence_global"); @@ -227,12 +236,12 @@ void Courtroom::refresh_evidence() f_evidence->set_id(n); - connect(f_evidence, SIGNAL(evidence_clicked(int)), this, - SLOT(on_evidence_clicked(int))); - connect(f_evidence, SIGNAL(evidence_double_clicked(int)), this, - SLOT(on_evidence_double_clicked(int))); - connect(f_evidence, SIGNAL(on_hover(int, bool)), this, - SLOT(on_evidence_hover(int, bool))); + connect(f_evidence, &AOEvidenceButton::evidence_clicked, this, + &Courtroom::on_evidence_clicked); + connect(f_evidence, &AOEvidenceButton::evidence_double_clicked, this, + &Courtroom::on_evidence_double_clicked); + connect(f_evidence, &AOEvidenceButton::on_hover, this, + &Courtroom::on_evidence_hover); ++x_mod_count; @@ -281,7 +290,11 @@ void Courtroom::set_evidence_list(QVector &p_evi_list) msgBox->setDetailedText(tr( "Name: %1\n" "Image: %2\n" - "Description:\n%3").arg(local_evidence_list.at(current_evidence).name).arg(local_evidence_list.at(current_evidence).image).arg(local_evidence_list.at(current_evidence).description)); + "Description:\n%3").arg( + local_evidence_list.at(current_evidence).name, + local_evidence_list.at(current_evidence).image, + local_evidence_list.at(current_evidence).description) + ); msgBox->setStandardButtons(QMessageBox::Yes | QMessageBox::No); msgBox->setDefaultButton(QMessageBox::LastButton); // msgBox->setWindowModality(Qt::NonModal); @@ -309,7 +322,7 @@ void Courtroom::set_evidence_page() ui_evidence_left->hide(); ui_evidence_right->hide(); - for (AOEvidenceButton *i_button : ui_evidence_list) { + for (AOEvidenceButton *i_button : qAsConst(ui_evidence_list)) { i_button->hide(); } @@ -368,26 +381,10 @@ void Courtroom::set_evidence_page() void Courtroom::on_evidence_name_edited() { - ui_evidence_name->setReadOnly(true); if (current_evidence >= local_evidence_list.size()) return; } -void Courtroom::on_evidence_name_double_clicked() -{ - if (ui_evidence_overlay->isVisible()) { - ui_evidence_name->setReadOnly(false); - } - else { - ui_evidence_name->setReadOnly(true); - } -} - -void Courtroom::on_evidence_image_name_double_clicked() -{ - ui_evidence_image_name->setReadOnly(false); -} - void Courtroom::on_evidence_image_name_edited() { ui_evidence_image_name->setReadOnly(true); @@ -445,7 +442,7 @@ void Courtroom::on_evidence_clicked(int p_id) ui_evidence_name->setText(local_evidence_list.at(f_real_id).name); - for (AOEvidenceButton *i_button : ui_evidence_list) + for (AOEvidenceButton *i_button : qAsConst(ui_evidence_list)) i_button->set_selected(false); ui_evidence_list.at(p_id)->set_selected(true); @@ -469,14 +466,14 @@ void Courtroom::on_evidence_double_clicked(int p_id) ui_evidence_description->clear(); ui_evidence_description->appendPlainText(f_evi.description); ui_evidence_description->setReadOnly(true); - ui_evidence_description->setToolTip(tr("Double-click to edit...")); + ui_evidence_description->setToolTip(tr("Click the pencil to edit...")); ui_evidence_name->setText(f_evi.name); ui_evidence_name->setReadOnly(true); - ui_evidence_name->setToolTip(tr("Double-click to edit...")); + ui_evidence_name->setToolTip(tr("Click the pencil to edit...")); ui_evidence_image_name->setText(f_evi.image); ui_evidence_image_name->setReadOnly(true); - ui_evidence_image_name->setToolTip(tr("Double-click to edit...")); + ui_evidence_image_name->setToolTip(tr("Click the pencil to edit...")); ui_evidence_overlay->show(); ui_evidence_ok->hide(); @@ -598,6 +595,8 @@ void Courtroom::on_evidence_ok_clicked() ui_evidence_name->setReadOnly(true); ui_evidence_description->setReadOnly(true); ui_evidence_image_name->setReadOnly(true); + ui_evidence_edit->show(); + ui_evidence_image_button->setDisabled(true); if (current_evidence < local_evidence_list.size()) { evi_type f_evi = local_evidence_list.at(current_evidence); if (current_evidence_global) { @@ -680,6 +679,22 @@ void Courtroom::on_evidence_transfer_clicked() msgBox->exec(); } +void Courtroom::on_evidence_edit_clicked() +{ + if (!ui_evidence_overlay->isVisible()) + return; + if (!ui_evidence_edit->isHidden()) { + ui_evidence_name->setReadOnly(false); + ui_evidence_image_name->setReadOnly(false); + ui_evidence_description->setReadOnly(false); + ui_evidence_image_button->setDisabled(false); + ui_evidence_edit->hide(); + } + else { + return; + } +} + void Courtroom::on_evidence_edited() { if (current_evidence >= @@ -704,6 +719,8 @@ void Courtroom::evidence_close() ui_evidence_name->setToolTip(""); ui_evidence_image_name->setReadOnly(true); ui_evidence_image_name->setToolTip(""); + ui_evidence_edit->show(); + ui_evidence_image_button->setDisabled(true); ui_evidence_overlay->hide(); ui_ic_chat_message->setFocus(); } diff --git a/src/file_functions.cpp b/src/file_functions.cpp index e64a46b..95e9b5f 100644 --- a/src/file_functions.cpp +++ b/src/file_functions.cpp @@ -2,6 +2,9 @@ bool file_exists(QString file_path) { + if (file_path.isEmpty()) + return false; + QFileInfo check_file(file_path); return check_file.exists() && check_file.isFile(); @@ -9,6 +12,9 @@ bool file_exists(QString file_path) bool dir_exists(QString dir_path) { + if (dir_path == "") + return false; + QDir check_dir(dir_path); return check_dir.exists(); diff --git a/src/lobby.cpp b/src/lobby.cpp index 5c3ff11..39b63e5 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -75,28 +75,28 @@ Lobby::Lobby(AOApplication *p_ao_app) : QMainWindow() ui_cancel = new AOButton(ui_loading_background, ao_app); ui_cancel->setObjectName("ui_cancel"); - connect(ui_public_servers, SIGNAL(clicked()), this, - SLOT(on_public_servers_clicked())); - connect(ui_favorites, SIGNAL(clicked()), this, SLOT(on_favorites_clicked())); - connect(ui_refresh, SIGNAL(pressed()), this, SLOT(on_refresh_pressed())); - connect(ui_refresh, SIGNAL(released()), this, SLOT(on_refresh_released())); - connect(ui_add_to_fav, SIGNAL(pressed()), this, - SLOT(on_add_to_fav_pressed())); - connect(ui_add_to_fav, SIGNAL(released()), this, - SLOT(on_add_to_fav_released())); - connect(ui_connect, SIGNAL(pressed()), this, SLOT(on_connect_pressed())); - connect(ui_connect, SIGNAL(released()), this, SLOT(on_connect_released())); - connect(ui_about, SIGNAL(clicked()), this, SLOT(on_about_clicked())); - connect(ui_settings, SIGNAL(clicked()), this, SLOT(on_settings_clicked())); - connect(ui_server_list, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, - SLOT(on_server_list_clicked(QTreeWidgetItem *, int))); - connect(ui_server_list, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), - this, SLOT(on_server_list_doubleclicked(QTreeWidgetItem *, int))); - connect(ui_server_search, SIGNAL(textChanged(QString)), this, - SLOT(on_server_search_edited(QString))); - connect(ui_chatmessage, SIGNAL(returnPressed()), this, - SLOT(on_chatfield_return_pressed())); - connect(ui_cancel, SIGNAL(clicked()), ao_app, SLOT(loading_cancelled())); + connect(ui_public_servers, &AOButton::clicked, this, + &Lobby::on_public_servers_clicked); + connect(ui_favorites, &AOButton::clicked, this, &Lobby::on_favorites_clicked); + connect(ui_refresh, &AOButton::pressed, this, &Lobby::on_refresh_pressed); + connect(ui_refresh, &AOButton::released, this, &Lobby::on_refresh_released); + connect(ui_add_to_fav, &AOButton::pressed, this, + &Lobby::on_add_to_fav_pressed); + connect(ui_add_to_fav, &AOButton::released, this, + &Lobby::on_add_to_fav_released); + connect(ui_connect, &AOButton::pressed, this, &Lobby::on_connect_pressed); + connect(ui_connect, &AOButton::released, this, &Lobby::on_connect_released); + connect(ui_about, &AOButton::clicked, this, &Lobby::on_about_clicked); + connect(ui_settings, &AOButton::clicked, this, &Lobby::on_settings_clicked); + connect(ui_server_list, &QTreeWidget::itemClicked, this, + &Lobby::on_server_list_clicked); + connect(ui_server_list, &QTreeWidget::itemDoubleClicked, + this, &Lobby::on_server_list_doubleclicked); + connect(ui_server_search, &QLineEdit::textChanged, this, + &Lobby::on_server_search_edited); + connect(ui_chatmessage, &QLineEdit::returnPressed, this, + &Lobby::on_chatfield_return_pressed); + connect(ui_cancel, &AOButton::clicked, ao_app, &AOApplication::loading_cancelled); ui_connect->setEnabled(false); @@ -237,6 +237,12 @@ void Lobby::set_stylesheet(QWidget *widget) void Lobby::set_stylesheets() { set_stylesheet(this); + this->setStyleSheet( + "QFrame { background-color:transparent; } " + "QAbstractItemView { background-color: transparent; color: black; } " + "QLineEdit { background-color:transparent; }" + + this->styleSheet() + ); } void Lobby::set_font(QWidget *widget, QString p_identifier) @@ -510,7 +516,7 @@ void Lobby::list_servers() ui_server_search->setText(""); int i = 0; - for (server_type i_server : ao_app->get_server_list()) { + for (const server_type &i_server : qAsConst(ao_app->get_server_list())) { QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_server_list); treeItem->setData(0, Qt::DisplayRole, i); treeItem->setText(1, i_server.name); @@ -526,7 +532,7 @@ void Lobby::list_favorites() ui_server_list->clear(); int i = 0; - for (server_type i_server : ao_app->get_favorite_list()) { + for (const server_type &i_server : qAsConst(ao_app->get_favorite_list())) { QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_server_list); treeItem->setData(0, Qt::DisplayRole, i); treeItem->setText(1, i_server.name); @@ -573,9 +579,9 @@ void Lobby::append_error(QString f_message) void Lobby::set_player_count(int players_online, int max_players) { - QString f_string = tr("Online: %1/%2") - .arg(QString::number(players_online)) - .arg(QString::number(max_players)); + QString f_string = tr("Online: %1/%2").arg( + QString::number(players_online), + QString::number(max_players)); ui_player_count->setText(f_string); } diff --git a/src/networkmanager.cpp b/src/networkmanager.cpp index 89a9bff..c1e8480 100644 --- a/src/networkmanager.cpp +++ b/src/networkmanager.cpp @@ -16,10 +16,10 @@ NetworkManager::NetworkManager(AOApplication *parent) : QObject(parent) http = new QNetworkAccessManager(this); heartbeat_timer = new QTimer(this); - connect(server_socket, SIGNAL(readyRead()), this, - SLOT(handle_server_packet())); - connect(server_socket, SIGNAL(disconnected()), ao_app, - SLOT(server_disconnected())); + connect(server_socket, &QTcpSocket::readyRead, this, + &NetworkManager::handle_server_packet); + connect(server_socket, &QTcpSocket::disconnected, ao_app, + &AOApplication::server_disconnected); QString master_config = ao_app->configini->value("master", "").value(); diff --git a/src/path_functions.cpp b/src/path_functions.cpp index dbf1cc4..6fd06e7 100644 --- a/src/path_functions.cpp +++ b/src/path_functions.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #ifdef BASE_OVERRIDE #include "base_override.h" @@ -39,72 +40,57 @@ QString AOApplication::get_base_path() return base_path; } -QString AOApplication::get_data_path() { return get_base_path() + "data/"; } - -QString AOApplication::get_theme_path(QString p_file, QString p_theme) +VPath 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); + return VPath("themes/" + p_theme + "/" + p_file); } -QString AOApplication::get_character_path(QString p_char, QString p_file) +VPath AOApplication::get_character_path(QString p_char, QString p_file) { - QString path = get_base_path() + "characters/" + p_char + "/" + p_file; - return get_case_sensitive_path(path); + return VPath("characters/" + p_char + "/" + p_file); } -QString AOApplication::get_misc_path(QString p_misc, QString p_file) +VPath AOApplication::get_misc_path(QString p_misc, QString p_file) { - QString path = get_base_path() + "misc/" + p_misc + "/" + p_file; -#ifndef CASE_SENSITIVE_FILESYSTEM - return path; -#else - return get_case_sensitive_path(path); -#endif + return VPath("misc/" + p_misc + "/" + p_file); } -QString AOApplication::get_sounds_path(QString p_file) +VPath AOApplication::get_sounds_path(QString p_file) { - QString path = get_base_path() + "sounds/general/" + p_file; - return get_case_sensitive_path(path); + return VPath("sounds/general/" + p_file); } -QString AOApplication::get_music_path(QString p_song) +VPath AOApplication::get_music_path(QString p_song) { if (p_song.startsWith("http")) { - return p_song; // url + return VPath(p_song); // url } - QString path = get_base_path() + "sounds/music/" + p_song; - return get_case_sensitive_path(path); + return VPath("sounds/music/" + p_song); } -QString AOApplication::get_background_path(QString p_file) +VPath AOApplication::get_background_path(QString p_file) { - QString path = get_base_path() + "background/" + - w_courtroom->get_current_background() + "/" + p_file; if (courtroom_constructed) { - return get_case_sensitive_path(path); + return VPath("background/" + w_courtroom->get_current_background() + "/" + p_file); } return get_default_background_path(p_file); } -QString AOApplication::get_default_background_path(QString p_file) +VPath AOApplication::get_default_background_path(QString p_file) { - QString path = get_base_path() + "background/default/" + p_file; - return get_case_sensitive_path(path); + return VPath("background/default/" + p_file); } -QString AOApplication::get_evidence_path(QString p_file) +VPath AOApplication::get_evidence_path(QString p_file) { - QString path = get_base_path() + "evidence/" + p_file; - return get_case_sensitive_path(path); + return VPath("evidence/" + p_file); } -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) +QVector 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; + QVector pathlist; if (p_character != "") pathlist += get_character_path(p_character, p_element); // Character folder if (p_misc != "" && p_theme != "" && p_subtheme != "") @@ -119,7 +105,7 @@ QStringList AOApplication::get_asset_paths(QString p_element, QString p_theme, Q 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 - pathlist += p_element; // The path by itself + pathlist += VPath(p_element); // The path by itself if (p_placeholder != "" && p_theme != "") pathlist += get_theme_path(p_placeholder, p_theme); // Placeholder path if (p_placeholder != "" && p_default_theme != "") @@ -127,52 +113,48 @@ QStringList AOApplication::get_asset_paths(QString p_element, QString p_theme, Q return pathlist; } -QString AOApplication::get_asset_path(QStringList pathlist) +QString AOApplication::get_asset_path(QVector pathlist) { - QString path; - for (QString p : pathlist) { - p = get_case_sensitive_path(p); - if (file_exists(p)) { - path = p; - break; + for (const VPath &p : pathlist) { + QString path = get_real_path(p); + if (!path.isEmpty()) { + return path; } } - return path; + return QString(); } -QString AOApplication::get_image_path(QStringList pathlist, bool static_image) +QString AOApplication::get_image_path(QVector 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; + for (const VPath &p : pathlist) { + QString path = get_image_suffix(p, static_image); + if (!path.isEmpty()) { + return path; } } - return path; + return QString(); } + +QString AOApplication::get_sfx_path(QVector pathlist) +{ + for (const VPath &p : pathlist) { + QString path = get_sfx_suffix(p); + if (!path.isEmpty()) { + return path; + } + } + return QString(); +} + 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); + const auto paths = get_asset_paths(p_config, p_theme, p_subtheme, p_default_theme, p_misc); + for (const VPath &p : paths) { + path = get_real_path(p); + if (!path.isEmpty()) { + QSettings settings(path, QSettings::IniFormat); settings.setIniCodec("UTF-8"); QVariant value = settings.value(p_identifier); if (value.type() == QVariant::StringList) { @@ -193,25 +175,22 @@ QString AOApplication::get_asset(QString p_element, QString p_theme, QString p_s 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) +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, + bool static_image) { - return get_image_path(get_asset_paths(p_element, p_theme, p_subtheme, p_default_theme, p_misc, p_character, p_placeholder)); + return get_image_path(get_asset_paths(p_element, p_theme, p_subtheme, p_default_theme, p_misc, p_character, p_placeholder), static_image); } 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); + QVector 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) { - // no path traversal above base folder - if (!(p_file.startsWith(get_base_path()))) - return get_base_path() + p_file; - - #ifdef CASE_SENSITIVE_FILESYSTEM +#ifdef CASE_SENSITIVE_FILESYSTEM // first, check to see if it's actually there (also serves as base case for // recursion) QFileInfo file(p_file); @@ -219,6 +198,7 @@ QString AOApplication::get_case_sensitive_path(QString p_file) if (exists(p_file)) return p_file; + QString file_parent_dir = get_case_sensitive_path(file.absolutePath()); // second, does it exist in the new parent dir? @@ -226,14 +206,20 @@ QString AOApplication::get_case_sensitive_path(QString p_file) return file_parent_dir + "/" + file_basename; // last resort, dirlist parent dir and find case insensitive match - QRegExp file_rx = - QRegExp(file_basename, Qt::CaseInsensitive, QRegExp::FixedString); - QStringList files = QDir(file_parent_dir).entryList(); - int result = files.indexOf(file_rx); + if (!dir_listing_exist_cache.contains(qHash(file_parent_dir))) { + QStringList files = QDir(file_parent_dir).entryList(); + for (const QString &file : files) { + dir_listing_cache.insert(qHash(file_parent_dir % QChar('/') % file.toLower()), file); + } + dir_listing_exist_cache.insert(qHash(file_parent_dir)); + } + QString found_file = dir_listing_cache.value( + qHash(file_parent_dir % QChar('/') % file_basename.toLower())); - if (result != -1) - return file_parent_dir + "/" + files.at(result); + if (!found_file.isEmpty()) { + return file_parent_dir + "/" + found_file; + } // if nothing is found, let the caller handle the missing file return file_parent_dir + "/" + file_basename; @@ -241,3 +227,81 @@ QString AOApplication::get_case_sensitive_path(QString p_file) return p_file; #endif } + +QString AOApplication::get_real_path(const VPath &vpath) { + // Try cache first + QString phys_path = asset_lookup_cache.value(qHash(vpath)); + if (!phys_path.isEmpty() && exists(phys_path)) { + return phys_path; + } + + // Cache miss; try all known mount paths + QStringList bases = get_mount_paths(); + bases.push_front(get_base_path()); + + for (const QString &base : bases) { + QDir baseDir(base); + QString path = baseDir.absoluteFilePath(vpath.toQString()); + if (!path.startsWith(baseDir.absolutePath())) { + qWarning() << "invalid path" << path << "(path is outside vfs)"; + break; + } + path = get_case_sensitive_path(path); + if (exists(path)) { + asset_lookup_cache.insert(qHash(vpath), path); + return path; + } + } + + // Not found in mount paths; check if the file is remote + QString remotePath = vpath.toQString(); + if (remotePath.startsWith("http:") || remotePath.startsWith("https:")) { + return remotePath; + } + + // File or directory not found + return QString(); +} + +// Special case of get_real_path where multiple suffixes need to be tried +// on each mount path. +QString AOApplication::get_real_suffixed_path(const VPath &vpath, + const QStringList &suffixes) { + // Try cache first + QString phys_path = asset_lookup_cache.value(qHash(vpath)); + if (!phys_path.isEmpty() && exists(phys_path)) { + for (const QString &suffix : suffixes) { // make sure cached asset is the right type + if (phys_path.endsWith(suffix, Qt::CaseInsensitive)) + return phys_path; + } + } + + // Cache miss; try each suffix on all known mount paths + QStringList bases = get_mount_paths(); + bases.push_front(get_base_path()); + + for (const QString &base : bases) { + for (const QString &suffix : suffixes) { + QDir baseDir(base); + QString path = baseDir.absoluteFilePath(vpath.toQString() + suffix); + if (!path.startsWith(baseDir.absolutePath())) { + qWarning() << "invalid path" << path << "(path is outside vfs)"; + break; + } + path = get_case_sensitive_path(path); + if (exists(path)) { + asset_lookup_cache.insert(qHash(vpath), path); + return path; + } + } + } + + // File or directory not found + return QString(); +} + +void AOApplication::invalidate_lookup_cache() { + asset_lookup_cache.clear(); + dir_listing_cache.clear(); + dir_listing_exist_cache.clear(); +} diff --git a/src/scrolltext.cpp b/src/scrolltext.cpp index d5da6ce..b526a8a 100644 --- a/src/scrolltext.cpp +++ b/src/scrolltext.cpp @@ -9,7 +9,7 @@ ScrollText::ScrollText(QWidget *parent) : QWidget(parent), scrollPos(0) setSeparator(" --- "); - connect(&timer, SIGNAL(timeout()), this, SLOT(timer_timeout())); + connect(&timer, &QTimer::timeout, this, &ScrollText::timer_timeout); timer.setInterval(50); } diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index d0bebbb..07a9393 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -89,6 +89,12 @@ bool AOApplication::get_log_timestamp() return result.startsWith("true"); } +QString AOApplication::get_log_timestamp_format() +{ + QString result = configini->value("log_timestamp_format", "h:mm:ss AP").value(); + return result; +} + bool AOApplication::get_log_ic_actions() { QString result = @@ -130,6 +136,11 @@ QStringList AOApplication::get_call_words() return get_list_file(get_base_path() + "callwords.ini"); } +QStringList AOApplication::get_list_file(VPath path) +{ + return get_list_file(get_real_path(path)); +} + QStringList AOApplication::get_list_file(QString p_file) { QStringList return_value; @@ -279,6 +290,12 @@ QVector AOApplication::read_serverlist_txt() return f_server_list; } +QString AOApplication::read_design_ini(QString p_identifier, + VPath p_design_path) +{ + return read_design_ini(p_identifier, get_real_path(p_design_path)); +} + QString AOApplication::read_design_ini(QString p_identifier, QString p_design_path) { @@ -448,12 +465,14 @@ QString AOApplication::get_chat_markup(QString p_identifier, QString p_chat) return value.toUtf8(); // Backwards ass compatibility - QStringList backwards_paths{get_theme_path("misc/" + p_chat + "/config.ini"), - get_base_path() + "misc/" + p_chat + - "/config.ini", - get_theme_path("misc/default/config.ini"), - get_base_path() + "misc/default/config.ini"}; - for (const QString &p : backwards_paths) { + QVector backwards_paths { + get_theme_path("misc/" + p_chat + "/config.ini"), + VPath("misc/" + p_chat + "/config.ini"), + get_theme_path("misc/default/config.ini"), + VPath("misc/default/config.ini") + }; + + for (const VPath &p : backwards_paths) { QString value = read_design_ini(p_identifier, p); if (!value.isEmpty()) { return value.toUtf8(); @@ -490,36 +509,21 @@ QString AOApplication::get_court_sfx(QString p_identifier, QString p_misc) return ""; } -QString AOApplication::get_sfx_suffix(QString sound_to_check) +QString AOApplication::get_sfx_suffix(VPath sound_to_check) { - if (file_exists(sound_to_check)) - return sound_to_check; - if (file_exists(sound_to_check + ".opus")) - return sound_to_check + ".opus"; - if (file_exists(sound_to_check + ".ogg")) - return sound_to_check + ".ogg"; - if (file_exists(sound_to_check + ".mp3")) - return sound_to_check + ".mp3"; - if (file_exists(sound_to_check + ".mp4")) - return sound_to_check + ".mp4"; - return sound_to_check + ".wav"; + return get_real_suffixed_path(sound_to_check, + {".opus", ".ogg", ".mp3", ".wav" }); } -QString AOApplication::get_image_suffix(QString path_to_check, bool static_image) +QString AOApplication::get_image_suffix(VPath path_to_check, bool static_image) { - if (file_exists(path_to_check)) - return 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. + QStringList suffixes {}; 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"; + suffixes.append({ ".webp", ".apng", ".gif" }); } - return path_to_check + ".png"; + suffixes.append(".png"); + + return get_real_suffixed_path(path_to_check, suffixes); } // returns whatever is to the right of "search_line =" within target_tag and @@ -528,7 +532,7 @@ QString AOApplication::get_image_suffix(QString path_to_check, bool static_image QString AOApplication::read_char_ini(QString p_char, QString p_search_line, QString target_tag) { - QSettings settings(get_character_path(p_char, "char.ini"), + QSettings settings(get_real_path(get_character_path(p_char, "char.ini")), QSettings::IniFormat); settings.beginGroup(target_tag); settings.setIniCodec("UTF-8"); @@ -540,7 +544,7 @@ QString AOApplication::read_char_ini(QString p_char, QString p_search_line, void AOApplication::set_char_ini(QString p_char, QString value, QString p_search_line, QString target_tag) { - QSettings settings(get_character_path(p_char, "char.ini"), + QSettings settings(get_real_path(get_character_path(p_char, "char.ini")), QSettings::IniFormat); settings.beginGroup(target_tag); settings.setValue(p_search_line, value); @@ -548,10 +552,10 @@ void AOApplication::set_char_ini(QString p_char, QString value, } // returns all the values of target_tag -QStringList AOApplication::read_ini_tags(QString p_path, QString target_tag) +QStringList AOApplication::read_ini_tags(VPath p_path, QString target_tag) { QStringList r_values; - QSettings settings(p_path, QSettings::IniFormat); + QSettings settings(get_real_path(p_path), QSettings::IniFormat); settings.setIniCodec("UTF-8"); if (!target_tag.isEmpty()) settings.beginGroup(target_tag); @@ -1096,6 +1100,11 @@ QString AOApplication::get_default_scaling() return configini->value("default_scaling", "fast").value(); } +QStringList AOApplication::get_mount_paths() +{ + return configini->value("mount_paths").value(); +} + bool AOApplication::get_player_count_optout() { return configini->value("player_count_optout", "false").value()