diff options
Diffstat (limited to 'src')
78 files changed, 8418 insertions, 4088 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt deleted file mode 100644 index 297a4f46..00000000 --- a/src/CMakeLists.txt +++ /dev/null @@ -1,39 +0,0 @@ -target_sources(Attorney_Online PRIVATE -aoapplication.cpp -aoblipplayer.cpp -aobutton.cpp -aocaseannouncerdialog.cpp -aocharbutton.cpp -aoclocklabel.cpp -aoemotebutton.cpp -aoemotepreview.cpp -aoevidencebutton.cpp -aoevidencedisplay.cpp -aoimage.cpp -aolayer.cpp -aomusicplayer.cpp -aooptionsdialog.cpp -aoclocklabel.cpp -aopacket.cpp -aosfxplayer.cpp -aotextarea.cpp -aoutils.cpp -charselect.cpp -chatlogpiece.cpp -courtroom.cpp -debug_functions.cpp -demoserver.cpp -discord_rich_presence.cpp -emotes.cpp -evidence.cpp -file_functions.cpp -hardware_functions.cpp -lobby.cpp -main.cpp -misc_functions.cpp -networkmanager.cpp -packet_distribution.cpp -path_functions.cpp -scrolltext.cpp -text_file_functions.cpp -) diff --git a/src/aoapplication.cpp b/src/aoapplication.cpp index 24682bc2..edd241b6 100644 --- a/src/aoapplication.cpp +++ b/src/aoapplication.cpp @@ -11,14 +11,14 @@ static QtMessageHandler original_message_handler; static AOApplication *message_handler_context; -void message_handler(QtMsgType type, const QMessageLogContext &context, - const QString &msg) +void message_handler(QtMsgType type, const QMessageLogContext &context, const QString &msg) { - emit message_handler_context->qt_log_message(type, context, msg); + Q_EMIT message_handler_context->qt_log_message(type, context, msg); original_message_handler(type, context, msg); } -AOApplication::AOApplication(int &argc, char **argv) : QApplication(argc, argv) +AOApplication::AOApplication(int &argc, char **argv) + : QApplication(argc, argv) { net_manager = new NetworkManager(this); discord = new AttorneyOnline::Discord(); @@ -42,7 +42,8 @@ AOApplication::~AOApplication() void AOApplication::construct_lobby() { - if (lobby_constructed) { + if (lobby_constructed) + { qWarning() << "lobby was attempted constructed when it already exists"; return; } @@ -56,17 +57,22 @@ void AOApplication::construct_lobby() w_lobby->move(x, y); if (Options::getInstance().discordEnabled()) + { discord->state_lobby(); + } if (demo_server) - demo_server->deleteLater(); + { + demo_server->deleteLater(); + } demo_server = new DemoServer(this); w_lobby->show(); } void AOApplication::destruct_lobby() { - if (!lobby_constructed) { + if (!lobby_constructed) + { qWarning() << "lobby was attempted destructed when it did not exist"; return; } @@ -78,7 +84,8 @@ void AOApplication::destruct_lobby() void AOApplication::construct_courtroom() { - if (courtroom_constructed) { + if (courtroom_constructed) + { qWarning() << "courtroom was attempted constructed when it already exists"; return; } @@ -91,18 +98,20 @@ void AOApplication::construct_courtroom() int y = (geometry.height() - w_courtroom->height()) / 2; w_courtroom->move(x, y); - if (demo_server != nullptr) { - QObject::connect(demo_server, &DemoServer::skip_timers, - w_courtroom, &Courtroom::skip_clocks); + if (demo_server != nullptr) + { + QObject::connect(demo_server, &DemoServer::skip_timers, w_courtroom, &Courtroom::skip_clocks); } - else { + else + { qWarning() << "demo server did not exist during courtroom construction"; } } void AOApplication::destruct_courtroom() { - if (!courtroom_constructed) { + if (!courtroom_constructed) + { qWarning() << "courtroom was attempted destructed when it did not exist"; return; } @@ -114,13 +123,13 @@ void AOApplication::destruct_courtroom() QString AOApplication::get_version_string() { - return QString::number(RELEASE) + "." + QString::number(MAJOR_VERSION) + "." + - QString::number(MINOR_VERSION); + return QString::number(RELEASE) + "." + QString::number(MAJOR_VERSION) + "." + QString::number(MINOR_VERSION); } void AOApplication::server_disconnected() { - if (courtroom_constructed) { + if (courtroom_constructed) + { call_notice(tr("Disconnected from server.")); construct_lobby(); destruct_courtroom(); @@ -135,22 +144,21 @@ void AOApplication::loading_cancelled() void AOApplication::call_settings_menu() { - AOOptionsDialog* l_dialog = new AOOptionsDialog(nullptr, this); - if (courtroom_constructed) { - connect(l_dialog, &AOOptionsDialog::reloadThemeRequest, - w_courtroom, &Courtroom::on_reload_theme_clicked); - } + AOOptionsDialog *l_dialog = new AOOptionsDialog(this); + if (courtroom_constructed) + { + connect(l_dialog, &AOOptionsDialog::reloadThemeRequest, w_courtroom, &Courtroom::on_reload_theme_clicked); + } - if(lobby_constructed) { - } - l_dialog->exec(); - delete l_dialog; + if (lobby_constructed) + {} + l_dialog->exec(); + delete l_dialog; } // 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) +void CALLBACK AOApplication::BASSreset(HSTREAM handle, DWORD channel, DWORD data, void *user) { Q_UNUSED(handle); Q_UNUSED(channel); @@ -175,16 +183,19 @@ void AOApplication::initBASS() unsigned int a = 0; BASS_DEVICEINFO info; - if (Options::getInstance().audioOutputDevice() == "default") { + if (Options::getInstance().audioOutputDevice() == "default") + { BASS_Init(-1, 48000, BASS_DEVICE_LATENCY, nullptr, nullptr); load_bass_plugins(); } - else { - for (a = 0; BASS_GetDeviceInfo(a, &info); a++) { - if (Options::getInstance().audioOutputDevice() == info.name) { + else + { + for (a = 0; BASS_GetDeviceInfo(a, &info); a++) + { + if (Options::getInstance().audioOutputDevice() == info.name) + { BASS_SetDevice(a); - BASS_Init(static_cast<int>(a), 48000, BASS_DEVICE_LATENCY, nullptr, - nullptr); + BASS_Init(static_cast<int>(a), 48000, BASS_DEVICE_LATENCY, nullptr, nullptr); load_bass_plugins(); qInfo() << info.name << "was set as the default audio output device."; BASS_SetConfigPtr(BASS_CONFIG_MIDI_DEFFONT, QString(get_base_path() + "soundfont.sf2").toStdString().c_str()); diff --git a/src/aoapplication.h b/src/aoapplication.h new file mode 100644 index 00000000..41eabf50 --- /dev/null +++ b/src/aoapplication.h @@ -0,0 +1,369 @@ +#pragma once + +#include "aopacket.h" +#include "datatypes.h" +#include "demoserver.h" +#include "discord_rich_presence.h" +#include "widgets/aooptionsdialog.h" + +#include "bass.h" + +#include <QApplication> +#include <QFile> +#include <QSettings> +#include <QVector> + +#include <QDebug> +#include <QRect> + +#include <QCryptographicHash> + +#include <QDir> +#include <QStandardPaths> + +#include <QColor> +#include <QScreen> +#include <QStringList> +#include <QTextStream> +#include <QTime> + +#include <QElapsedTimer> + +class NetworkManager; +class Lobby; +class Courtroom; +class Options; + +class VPath : QString +{ + using QString::QString; + +public: + explicit VPath(const QString &str) + : QString(str) + {} + inline const QString &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 + +public: + AOApplication(int &argc, char **argv); + ~AOApplication(); + + NetworkManager *net_manager; + Lobby *w_lobby; + Courtroom *w_courtroom; + AttorneyOnline::Discord *discord; + + QFont default_font; + + bool lobby_constructed = false; + bool courtroom_constructed = false; + + void construct_lobby(); + void destruct_lobby(); + + void construct_courtroom(); + void destruct_courtroom(); + + void server_packet_received(AOPacket p_packet); + + void send_server_packet(AOPacket p_packet); + + void call_settings_menu(); + + qint64 latency = 0; + QString window_title; + + /////////////////server metadata////////////////// + + bool yellow_text_supported = false; + bool prezoom_supported = false; + bool flipping_supported = false; + bool custom_objection_supported = false; + bool desk_mod_supported = false; + bool evidence_supported = false; + bool cccc_ic_supported = false; + bool arup_supported = false; + bool casing_alerts_supported = false; + bool modcall_reason_supported = false; + bool looping_sfx_supported = false; + bool additive_text_supported = false; + bool effects_supported = false; + bool y_offset_supported = false; + bool expanded_desk_mods_supported = false; + bool auth_packet_supported = false; + + ///////////////loading info/////////////////// + + // client ID. Not useful, to be removed eventually + int client_id = 0; + + QString server_software; + + int char_list_size = 0; + int loaded_chars = 0; + int generated_chars = 0; + int evidence_list_size = 0; + int loaded_evidence = 0; + int music_list_size = 0; + int loaded_music = 0; + + bool courtroom_loaded = false; + + //////////////////versioning/////////////// + + QString get_version_string(); + + /////////////////////////////////////////// + + void set_server_list(QVector<server_type> &servers) { server_list = servers; } + QVector<server_type> &get_server_list() { return server_list; } + + // implementation in path_functions.cpp + VPath get_theme_path(QString p_file, QString p_theme = QString()); + 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<VPath> get_asset_paths(QString p_element, QString p_theme = QString(), QString p_subtheme = QString(), QString p_default_theme = QString(), QString p_misc = QString(), QString p_character = QString(), QString p_placeholder = QString()); + QString get_asset_path(QVector<VPath> pathlist); + QString get_image_path(QVector<VPath> pathlist, bool static_image = false); + QString get_sfx_path(QVector<VPath> pathlist); + QString get_config_value(QString p_identifier, QString p_config, QString p_theme = QString(), QString p_subtheme = QString(), QString p_default_theme = QString(), QString p_misc = QString()); + QString get_asset(QString p_element, QString p_theme = QString(), QString p_subtheme = QString(), QString p_default_theme = QString(), QString p_misc = QString(), QString p_character = QString(), QString p_placeholder = QString()); + QString get_image(QString p_element, QString p_theme = QString(), QString p_subtheme = QString(), QString p_default_theme = QString(), QString p_misc = QString(), QString p_character = QString(), QString p_placeholder = QString(), bool static_image = false); + QString get_sfx(QString p_sfx, QString p_misc = QString(), QString p_character = QString()); + QString get_pos_path(const QString &pos, bool desk = false); + QString get_case_sensitive_path(QString p_file); + QString get_real_path(const VPath &vpath, const QStringList &suffixes = {""}); + + ////// Functions for reading and writing files ////// + // Implementations file_functions.cpp + + // 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 + QString read_file(QString filename); + + // Write text to file. make_dir would auto-create the directory if it doesn't + // exist. + bool write_to_file(QString p_text, QString p_file, bool make_dir = false); + + // Append text to the end of the file. make_dir would auto-create the + // directory if it doesn't exist. + bool append_to_file(QString p_text, QString p_file, bool make_dir = false); + + // Append to the currently open demo file if there is one + void append_to_demofile(QString packet_string); + + /** + * @brief Reads the clients log folder and locates potential demo files to populate the demoserver list. + * + * @return A seperated list of servernames and demo logfile filenames. + * + * @details This is to remove the need of delimiters or deal with potential + * harmfully encoding or plattform differences. We always get a combo of servername and filename. + * + * Do note this function assumes all demo files have the .demo extension. + * + */ + QMultiMap<QString, QString> load_demo_logs_list() const; + + // 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 + QPoint get_button_spacing(QString p_identifier, QString p_file); + + // Returns the dimensions of widget with specified identifier from p_file + pos_size_type get_element_dimensions(QString p_identifier, QString p_file, QString p_misc = QString()); + + // Returns the value to you + QString get_design_element(QString p_identifier, QString p_file, QString p_misc = QString()); + + // Returns the color with p_identifier from p_file + QColor get_color(QString p_identifier, QString p_file); + + // Returns the markup symbol used for specified p_identifier such as colors + QString get_chat_markup(QString p_identifier, QString p_file); + + // Returns the color from the misc folder. + QColor get_chat_color(QString p_identifier, QString p_chat); + + // Returns the value with p_identifier from penalty/penalty.ini in the current + // theme path + QString get_penalty_value(QString p_identifier); + + // Returns the sfx with p_identifier from courtroom_sounds.ini in the current theme path + QString get_court_sfx(QString p_identifier, QString p_misc = QString()); + + // Figure out if we can opus this or if we should fall back to wav + 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(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(VPath p_file, QString target_tag = QString()); + + // Returns the text between target_tag and terminator_tag in p_file + QString get_stylesheet(QString p_file); + + // Returns the side of the p_char character from that characters ini file + QString get_char_side(QString p_char); + + // Returns the showname from the ini of p_char + QString get_showname(QString p_char); + + // Returns the category of this character + QString get_category(QString p_char); + + // Returns the value of chat image from the specific p_char's ini file + QString get_chat(QString p_char); + + // Returns the value of chat font from the specific p_char's ini file + QString get_chat_font(QString p_char); + + // Returns the value of chat font size from the specific p_char's ini file + int get_chat_size(QString p_char); + + // Returns the preanim duration of p_char's p_emote + int get_preanim_duration(QString p_char, QString p_emote); + + // Not in use + int get_text_delay(QString p_char, QString p_emote); + + // Get the theme's effects folder, read it and return the list of filenames in + // a string + QStringList get_effects(QString p_char); + + // Get the correct effect image + QString get_effect(QString effect, QString p_char, QString p_folder); + + // Return p_property of fx_name. If p_property is "sound", return + // the value associated with fx_name, otherwise use fx_name + '_' + p_property. + QString get_effect_property(QString fx_name, QString p_char, QString p_folder, QString p_property); + + // Returns the custom realisation used by the character. + QString get_custom_realization(QString p_char); + + // Returns whether the given pos is a judge position + bool get_pos_is_judge(const QString &p_pos); + + // Returns the total amount of emotes of p_char + int get_emote_number(QString p_char); + + // Returns the emote comment of p_char's p_emote + QString get_emote_comment(QString p_char, int p_emote); + + // Returns the base name of p_char's p_emote + QString get_emote(QString p_char, int p_emote); + + // Returns the preanimation name of p_char's p_emote + QString get_pre_emote(QString p_char, int p_emote); + + // Returns the sfx of p_char's p_emote + QString get_sfx_name(QString p_char, int p_emote); + + // Returns if the sfx is defined as looping in char.ini + QString get_sfx_looping(QString p_char, int p_emote); + + // Returns if an emote has a frame specific SFX for it + QString get_sfx_frame(QString p_char, QString p_emote, int n_frame); + + // Returns if an emote has a frame specific SFX for it + QString get_flash_frame(QString p_char, QString p_emote, int n_frame); + + // Returns if an emote has a frame specific SFX for it + QString get_screenshake_frame(QString p_char, QString p_emote, int n_frame); + + // Not in use + int get_sfx_delay(QString p_char, int p_emote); + + // Returns the modifier for p_char's p_emote + int get_emote_mod(QString p_char, int p_emote); + + // Returns the desk modifier for p_char's p_emote + int get_desk_mod(QString p_char, int p_emote); + + // Returns p_char's blips (previously called their "gender") + QString get_blips(QString p_char); + + // Get a property of a given emote, or get it from "options" if emote doesn't have it + QString get_emote_property(QString p_char, QString p_emote, QString p_property); + + // Return a transformation mode from a string ("smooth" for smooth, anything else for fast) + Qt::TransformationMode get_scaling(QString p_scaling); + + // Returns the scaling type for p_miscname + Qt::TransformationMode get_misc_scaling(QString p_miscname); + + // ====== + // These are all casing-related settings. + // ====== + + // Currently defined subtheme + QString subtheme; + + // Default is always default. + const QString default_theme = "default"; + + // The file name of the log file in base/logs. + QString log_filename; + + /** + * @brief A QString of an URL that defines the content repository + * send by the server. + * + * @details Introduced in Version 2.9.2. + * Addresses the issue of contenturl devlivery for WebAO + * without relying on someone adding the link manually. + */ + QString asset_url; + + void initBASS(); + static void load_bass_plugins(); + static void CALLBACK BASSreset(HSTREAM handle, DWORD channel, DWORD data, void *user); + static void doBASSreset(); + + QElapsedTimer demo_timer; + DemoServer *demo_server = nullptr; + +private: + const int RELEASE = 2; + const int MAJOR_VERSION = 11; + const int MINOR_VERSION = 0; + + QVector<server_type> server_list; + QHash<uint, QString> asset_lookup_cache; + QHash<uint, QString> dir_listing_cache; + QSet<uint> dir_listing_exist_cache; + +public Q_SLOTS: + void server_disconnected(); + void loading_cancelled(); + +Q_SIGNALS: + void qt_log_message(QtMsgType type, const QMessageLogContext &context, const QString &msg); +}; diff --git a/src/aoblipplayer.cpp b/src/aoblipplayer.cpp index 5dc24678..cf877fd7 100644 --- a/src/aoblipplayer.cpp +++ b/src/aoblipplayer.cpp @@ -1,24 +1,25 @@ #include "aoblipplayer.h" -AOBlipPlayer::AOBlipPlayer(QWidget *parent, AOApplication *p_ao_app) -{ - m_parent = parent; - ao_app = p_ao_app; -} +AOBlipPlayer::AOBlipPlayer(AOApplication *p_ao_app) + : ao_app(p_ao_app) +{} void AOBlipPlayer::set_blips(QString p_sfx) { QString f_path = ao_app->get_sfx_suffix(ao_app->get_sounds_path(p_sfx)); - for (int n_stream = 0; n_stream < 5; ++n_stream) { + for (int n_stream = 0; n_stream < 5; ++n_stream) + { BASS_StreamFree(m_stream_list[n_stream]); if (f_path.endsWith(".opus")) - m_stream_list[n_stream] = BASS_OPUS_StreamCreateFile( - FALSE, f_path.utf16(), 0, 0, BASS_UNICODE | BASS_ASYNCFILE); + { + m_stream_list[n_stream] = BASS_OPUS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, BASS_UNICODE | BASS_ASYNCFILE); + } else - m_stream_list[n_stream] = BASS_StreamCreateFile( - FALSE, f_path.utf16(), 0, 0, BASS_UNICODE | BASS_ASYNCFILE); + { + m_stream_list[n_stream] = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, BASS_UNICODE | BASS_ASYNCFILE); + } } set_volume_internal(m_volume); @@ -29,7 +30,9 @@ void AOBlipPlayer::blip_tick() int f_cycle = m_cycle++; if (m_cycle == 5) + { m_cycle = 0; + } HSTREAM f_stream = m_stream_list[f_cycle]; @@ -54,7 +57,8 @@ void AOBlipPlayer::set_volume_internal(qreal p_value) // If muted, volume will always be 0 float volume = static_cast<float>(p_value) * !m_muted; - for (int n_stream = 0; n_stream < 5; ++n_stream) { + for (int n_stream = 0; n_stream < 5; ++n_stream) + { BASS_ChannelSetAttribute(m_stream_list[n_stream], BASS_ATTRIB_VOL, volume); } } diff --git a/src/aoblipplayer.h b/src/aoblipplayer.h new file mode 100644 index 00000000..bc878b80 --- /dev/null +++ b/src/aoblipplayer.h @@ -0,0 +1,31 @@ +#pragma once + +#include "bass.h" +#include "bassopus.h" + +#include "aoapplication.h" + +#include <QDebug> +#include <QElapsedTimer> +#include <QWidget> +#include <string.h> + +class AOBlipPlayer +{ +public: + AOBlipPlayer(AOApplication *p_ao_app); + + void set_blips(QString p_sfx); + void blip_tick(); + void set_volume(int p_volume); + void set_muted(bool toggle); + +private: + AOApplication *ao_app; + qreal m_volume = 0.0; + int m_cycle = 0; + bool m_muted = false; + HSTREAM m_stream_list[5]; + + void set_volume_internal(qreal p_volume); +}; diff --git a/src/aobutton.cpp b/src/aobutton.cpp index 5ef2a066..4fc50d65 100644 --- a/src/aobutton.cpp +++ b/src/aobutton.cpp @@ -4,40 +4,44 @@ #include "file_functions.h" #include "options.h" -AOButton::AOButton(QWidget *parent, AOApplication *p_ao_app) +AOButton::AOButton(AOApplication *p_ao_app, QWidget *parent) : QPushButton(parent) + , ao_app(p_ao_app) { - ao_app = p_ao_app; - movie = new QMovie(this); - connect(movie, &QMovie::frameChanged, [this]{ - this->setIcon(movie->currentPixmap().scaled(this->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + m_movie = new QMovie(this); + + connect(m_movie, &QMovie::frameChanged, this, [this] { + this->setIcon(m_movie->currentPixmap().scaled(this->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); this->setIconSize(QSize(this->width(), this->height())); }); } -AOButton::~AOButton() {} +AOButton::~AOButton() +{} void AOButton::set_image(QString p_path, QString p_misc) { - movie->stop(); + m_movie->stop(); QString p_image; - p_image = ao_app->get_image(p_path, Options::getInstance().theme(), Options::getInstance().subTheme(), - ao_app->default_theme, p_misc, "", "", !Options::getInstance().animatedThemeEnabled()); - if (p_image.isEmpty()) { - this->setIcon(QIcon()); - this->setIconSize(this->size()); - this->setStyleSheet(""); - return; + p_image = ao_app->get_image(p_path, Options::getInstance().theme(), Options::getInstance().subTheme(), ao_app->default_theme, p_misc, "", "", !Options::getInstance().animatedThemeEnabled()); + if (p_image.isEmpty()) + { + this->setIcon(QIcon()); + this->setIconSize(this->size()); + this->setStyleSheet(""); + return; } this->setText(""); this->setStyleSheet("QPushButton { background-color: transparent; border: 0px }"); - movie->setFileName(p_image); + m_movie->setFileName(p_image); // We double-check if the user wants animated themes, so even if an animated image slipped through, // we still set it static - if (Options::getInstance().animatedThemeEnabled() && movie->frameCount() > 1) { - movie->start(); + if (Options::getInstance().animatedThemeEnabled() && m_movie->frameCount() > 1) + { + m_movie->start(); } - else { + else + { this->setIcon(QPixmap(p_image).scaled(this->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); this->setIconSize(this->size()); } diff --git a/src/aobutton.h b/src/aobutton.h new file mode 100644 index 00000000..058d9e5c --- /dev/null +++ b/src/aobutton.h @@ -0,0 +1,22 @@ +#pragma once + +#include "aoapplication.h" + +#include <QDebug> +#include <QMovie> +#include <QPushButton> + +class AOButton : public QPushButton +{ + Q_OBJECT + +public: + AOButton(AOApplication *p_ao_app, QWidget *parent = nullptr); + ~AOButton(); + + void set_image(QString p_image, QString p_misc = QString()); + +private: + AOApplication *ao_app; + QMovie *m_movie; +}; diff --git a/src/aocharbutton.cpp b/src/aocharbutton.cpp index 4f00e3c8..cab7fddd 100644 --- a/src/aocharbutton.cpp +++ b/src/aocharbutton.cpp @@ -2,35 +2,24 @@ #include "file_functions.h" -AOCharButton::AOCharButton(QWidget *parent, AOApplication *p_ao_app, int x_pos, - int y_pos, bool is_taken) +AOCharButton::AOCharButton(AOApplication *p_ao_app, int x_pos, int y_pos, bool is_taken, QWidget *parent) : QPushButton(parent) + , ao_app(p_ao_app) + , m_taken(is_taken) { - m_parent = parent; - - ao_app = p_ao_app; - - taken = is_taken; - int size = 60 * Options::getInstance().themeScalingFactor(); int selector_size = 62 * Options::getInstance().themeScalingFactor(); this->resize(size, size); this->move(x_pos, y_pos); - ui_taken = new AOImage(this, ao_app, true); + ui_taken = new AOImage(ao_app, this); ui_taken->resize(size, size); ui_taken->set_image("char_taken"); ui_taken->setAttribute(Qt::WA_TransparentForMouseEvents); ui_taken->hide(); - ui_passworded = new AOImage(this, ao_app, true); - ui_passworded->resize(size, size); - ui_passworded->set_image("char_passworded"); - ui_passworded->setAttribute(Qt::WA_TransparentForMouseEvents); - ui_passworded->hide(); - - ui_selector = new AOImage(parent, ao_app, true); + ui_selector = new AOImage(ao_app, parent); ui_selector->resize(selector_size, selector_size); int offset = Options::getInstance().themeScalingFactor(); ui_selector->move(x_pos - offset, y_pos - offset); @@ -42,39 +31,42 @@ AOCharButton::AOCharButton(QWidget *parent, AOApplication *p_ao_app, int x_pos, void AOCharButton::reset() { ui_taken->hide(); - ui_passworded->hide(); ui_selector->hide(); } -void AOCharButton::set_taken(bool is_taken) { taken = is_taken; } +void AOCharButton::set_taken(bool is_taken) +{ + m_taken = is_taken; +} void AOCharButton::apply_taken_image() { - if (taken) { + if (m_taken) + { ui_taken->move(0, 0); ui_taken->show(); } - else { + else + { ui_taken->hide(); } } -void AOCharButton::set_passworded() { ui_passworded->show(); } - void AOCharButton::set_image(QString p_character) { - QString image_path = ao_app->get_image_suffix( - ao_app->get_character_path(p_character, "char_icon"), true); + QString image_path = ao_app->get_image_suffix(ao_app->get_character_path(p_character, "char_icon"), true); this->setText(""); - if (file_exists(image_path)) { + if (file_exists(image_path)) + { this->setStyleSheet("QPushButton { border-image: url(\"" + image_path + "\") 0 0 0 0 stretch stretch; }" "QToolTip { background-image: url(); color: #000000; " "background-color: #ffffff; border: 0px; }"); } - else { + else + { this->setStyleSheet("QPushButton { border-image: url(); }" "QToolTip { background-image: url(); color: #000000; " "background-color: #ffffff; border: 0px; }"); diff --git a/src/aocharbutton.h b/src/aocharbutton.h new file mode 100644 index 00000000..54117f48 --- /dev/null +++ b/src/aocharbutton.h @@ -0,0 +1,40 @@ +#pragma once + +#include "aoapplication.h" +#include "aoimage.h" + +#include <QEnterEvent> +#include <QFile> +#include <QPushButton> +#include <QString> +#include <QWidget> + +class AOCharButton : public QPushButton +{ + Q_OBJECT + +public: + AOCharButton(AOApplication *p_ao_app, int x_pos, int y_pos, bool is_taken, QWidget *parent); + + void refresh(); + void reset(); + void set_taken(bool is_taken); + + void apply_taken_image(); + + void set_image(QString p_character); + +protected: +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + void enterEvent(QEvent *e) override; +#else + void enterEvent(QEnterEvent *e) override; +#endif + void leaveEvent(QEvent *e) override; + +private: + AOApplication *ao_app; + bool m_taken = false; + AOImage *ui_taken; + AOImage *ui_selector; +}; diff --git a/src/aoclocklabel.cpp b/src/aoclocklabel.cpp index ce62f320..afd4d1e3 100644 --- a/src/aoclocklabel.cpp +++ b/src/aoclocklabel.cpp @@ -1,10 +1,12 @@ #include "aoclocklabel.h" -AOClockLabel::AOClockLabel(QWidget *parent) : QLabel(parent) {} +AOClockLabel::AOClockLabel(QWidget *parent) + : QLabel(parent) +{} void AOClockLabel::start() { - timer.start(1000 / 60, this); + m_timer.start(1000 / 60, this); } void AOClockLabel::start(qint64 msecs) @@ -15,16 +17,16 @@ void AOClockLabel::start(qint64 msecs) void AOClockLabel::set(qint64 msecs, bool update_text) { - target_time = QDateTime::currentDateTime().addMSecs(msecs); + m_target_time = QDateTime::currentDateTime().addMSecs(msecs); if (update_text) { - if (QDateTime::currentDateTime() >= target_time) + if (QDateTime::currentDateTime() >= m_target_time) { this->setText("00:00:00.000"); } else { - qint64 ms_left = QDateTime::currentDateTime().msecsTo(target_time); + qint64 ms_left = QDateTime::currentDateTime().msecsTo(m_target_time); QTime timeleft = QTime(0, 0).addMSecs(ms_left % (1000 * 3600 * 24)); QString timestring = timeleft.toString("hh:mm:ss.zzz"); this->setText(timestring); @@ -34,39 +36,42 @@ void AOClockLabel::set(qint64 msecs, bool update_text) void AOClockLabel::pause() { - timer.stop(); + m_timer.stop(); } void AOClockLabel::stop() { this->setText("00:00:00.000"); - timer.stop(); + m_timer.stop(); } void AOClockLabel::skip(qint64 msecs) { - qint64 ms_left = QDateTime::currentDateTime().msecsTo(target_time); + qint64 ms_left = QDateTime::currentDateTime().msecsTo(m_target_time); this->set(ms_left - msecs, true); } bool AOClockLabel::active() { - return timer.isActive(); + return m_timer.isActive(); } void AOClockLabel::timerEvent(QTimerEvent *event) { - if (event->timerId() == timer.timerId()) { - if (QDateTime::currentDateTime() >= target_time) + if (event->timerId() == m_timer.timerId()) + { + if (QDateTime::currentDateTime() >= m_target_time) { this->stop(); return; } - qint64 ms_left = QDateTime::currentDateTime().msecsTo(target_time); + qint64 ms_left = QDateTime::currentDateTime().msecsTo(m_target_time); QTime timeleft = QTime(0, 0).addMSecs(ms_left % (1000 * 3600 * 24)); QString timestring = timeleft.toString("hh:mm:ss.zzz"); this->setText(timestring); - } else { + } + else + { QWidget::timerEvent(event); } } diff --git a/src/aoclocklabel.h b/src/aoclocklabel.h new file mode 100644 index 00000000..415179b3 --- /dev/null +++ b/src/aoclocklabel.h @@ -0,0 +1,30 @@ +#pragma once + +#include <QBasicTimer> +#include <QDateTime> +#include <QDebug> +#include <QLabel> +#include <QTimerEvent> + +class AOClockLabel : public QLabel +{ + Q_OBJECT + +public: + AOClockLabel(QWidget *parent); + + void start(); + void start(qint64 msecs); + void set(qint64 msecs, bool update_text = false); + void pause(); + void stop(); + void skip(qint64 msecs); + bool active(); + +protected: + void timerEvent(QTimerEvent *event) override; + +private: + QBasicTimer m_timer; + QDateTime m_target_time; +}; diff --git a/src/aoemotebutton.cpp b/src/aoemotebutton.cpp index c0539844..32e50ff8 100644 --- a/src/aoemotebutton.cpp +++ b/src/aoemotebutton.cpp @@ -1,13 +1,10 @@ #include "aoemotebutton.h" #include "file_functions.h" -AOEmoteButton::AOEmoteButton(QWidget *p_parent, AOApplication *p_ao_app, - int p_x, int p_y, int p_w, int p_h) +AOEmoteButton::AOEmoteButton(AOApplication *p_ao_app, int p_x, int p_y, int p_w, int p_h, QWidget *p_parent) : QPushButton(p_parent) + , ao_app(p_ao_app) { - parent = p_parent; - ao_app = p_ao_app; - this->move(p_x, p_y); this->resize(p_w, p_h); @@ -21,27 +18,38 @@ AOEmoteButton::AOEmoteButton(QWidget *p_parent, AOApplication *p_ao_app, void AOEmoteButton::set_selected_image(QString p_image) { - if (file_exists(p_image)) { + if (file_exists(p_image)) + { ui_selected->setStyleSheet("border-image: url(\"" + p_image + "\")"); } - else { + else + { ui_selected->setStyleSheet("background-color: rgba(0, 0, 0, 128)"); } } -void AOEmoteButton::set_image(QString p_image, QString p_emote_comment) +void AOEmoteButton::set_id(int p_id) +{ + m_id = p_id; +} + +int AOEmoteButton::get_id() { - QString tmp_p_image = p_image; + return m_id; +} - if (file_exists(p_image)) { +void AOEmoteButton::set_image(QString p_image, QString p_emote_comment) +{ + if (file_exists(p_image)) + { this->setText(""); - this->setStyleSheet( - "QPushButton { border: none; }" - "QToolTip { color: #000000; background-color: #ffffff; border: 0px; }"); + this->setStyleSheet("QPushButton { border: none; }" + "QToolTip { color: #000000; background-color: #ffffff; border: 0px; }"); this->setIcon(QPixmap(p_image).scaled(this->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); this->setIconSize(this->size()); } - else { + else + { this->setText(p_emote_comment); this->setStyleSheet("QPushButton { border-image: url(); }" "QToolTip { background-image: url(); color: #000000; " @@ -54,25 +62,29 @@ void AOEmoteButton::set_image(QString p_image, QString p_emote_comment) void AOEmoteButton::set_char_image(QString p_char, int p_emote, bool on) { QString emotion_number = QString::number(p_emote + 1); - QStringList suffixes { "_off", "_on" }; + QStringList suffixes{"_off", "_on"}; QStringList suffixedPaths; - for (const QString &suffix : suffixes) { - suffixedPaths.append(ao_app->get_image_suffix(ao_app->get_character_path( - p_char, "emotions/button" + emotion_number + suffix))); + for (const QString &suffix : suffixes) + { + suffixedPaths.append(ao_app->get_image_suffix(ao_app->get_character_path(p_char, "emotions/button" + emotion_number + suffix))); } QString image = suffixedPaths[static_cast<int>(on)]; QString emoteComment = ao_app->get_emote_comment(p_char, p_emote); - if (on && !file_exists(suffixedPaths[1])) {; + if (on && !file_exists(suffixedPaths[1])) + { ui_selected->show(); image = suffixedPaths[0]; } - else { + else + { ui_selected->hide(); } set_image(image, emoteComment); } -void AOEmoteButton::on_clicked() { emit emote_clicked(m_id); } - +void AOEmoteButton::on_clicked() +{ + Q_EMIT emote_clicked(m_id); +} diff --git a/src/aoemotebutton.h b/src/aoemotebutton.h new file mode 100644 index 00000000..93149492 --- /dev/null +++ b/src/aoemotebutton.h @@ -0,0 +1,36 @@ +#pragma once + +#include "aoapplication.h" +#include <QDebug> +#include <QLabel> +#include <QPainter> +#include <QPushButton> + +class AOEmoteButton : public QPushButton +{ + Q_OBJECT + +public: + AOEmoteButton(AOApplication *p_ao_app, int p_x, int p_y, int p_w, int p_h, QWidget *p_parent); + + void set_image(QString p_image, QString p_emote_comment); + void set_char_image(QString p_char, int p_emote, bool on); + + void set_selected_image(QString p_image); + + void set_id(int p_id); + int get_id(); + +Q_SIGNALS: + void emote_clicked(int p_id); + +private: + AOApplication *ao_app; + + int m_id = 0; + + QLabel *ui_selected = nullptr; + +private Q_SLOTS: + void on_clicked(); +}; diff --git a/src/aoemotepreview.cpp b/src/aoemotepreview.cpp index 5afeebda..8df35dd6 100644 --- a/src/aoemotepreview.cpp +++ b/src/aoemotepreview.cpp @@ -1,11 +1,11 @@ #include "aoemotepreview.h" -AOEmotePreview::AOEmotePreview(QWidget *parent, AOApplication *p_ao_app) : QWidget(parent) +AOEmotePreview::AOEmotePreview(AOApplication *p_ao_app, QWidget *parent) + : QWidget(parent) + , ao_app(p_ao_app) { - ao_app = p_ao_app; - ui_viewport = new QWidget(this); - ui_vp_player_char = new CharLayer(ui_viewport, ao_app); + ui_vp_player_char = new CharLayer(ao_app, ui_viewport); ui_vp_player_char->setObjectName("ui_vp_player_char"); ui_vp_player_char->masked = false; ui_size_label = new QLabel(this); diff --git a/src/aoemotepreview.h b/src/aoemotepreview.h new file mode 100644 index 00000000..ac86ff00 --- /dev/null +++ b/src/aoemotepreview.h @@ -0,0 +1,31 @@ +#pragma once + +#include "aolayer.h" +#include <QWidget> + +class AOEmotePreview : public QWidget +{ + Q_OBJECT + +public: + AOEmotePreview(AOApplication *p_ao_app, QWidget *parent = nullptr); + + void set_widgets(); + void play(QString emote, QString char_name, bool flipped = false, int self_offset = 0, int self_offset_v = 0); + +protected: + void resizeEvent(QResizeEvent *); + +private: + AOApplication *ao_app; + + QString m_emote; + QString m_char; + + QWidget *ui_viewport; + BackgroundLayer *ui_vp_background; + SplashLayer *ui_vp_speedlines; + CharLayer *ui_vp_player_char; + BackgroundLayer *ui_vp_desk; + QLabel *ui_size_label; +}; diff --git a/src/aoevidencebutton.cpp b/src/aoevidencebutton.cpp index d731682e..b026c13e 100644 --- a/src/aoevidencebutton.cpp +++ b/src/aoevidencebutton.cpp @@ -2,21 +2,18 @@ #include "file_functions.h" -AOEvidenceButton::AOEvidenceButton(QWidget *p_parent, AOApplication *p_ao_app, - int p_x, int p_y, int p_w, int p_h) +AOEvidenceButton::AOEvidenceButton(AOApplication *p_ao_app, int p_x, int p_y, int p_w, int p_h, QWidget *p_parent) : QPushButton(p_parent) + , ao_app(p_ao_app) { - ao_app = p_ao_app; - m_parent = p_parent; - - ui_selected = new AOImage(this, ao_app, true); + ui_selected = new AOImage(ao_app, this); ui_selected->resize(p_w, p_h); // ui_selected->move(p_x, p_y); ui_selected->set_image("evidence_selected"); ui_selected->setAttribute(Qt::WA_TransparentForMouseEvents); ui_selected->hide(); - ui_selector = new AOImage(this, ao_app, true); + ui_selector = new AOImage(ao_app, this); ui_selector->resize(p_w, p_h); // ui_selector->move(p_x - 1, p_y - 1); ui_selector->set_image("evidence_selector"); @@ -33,21 +30,22 @@ AOEvidenceButton::AOEvidenceButton(QWidget *p_parent, AOApplication *p_ao_app, void AOEvidenceButton::set_image(QString p_image) { QString image_path = ao_app->get_real_path(ao_app->get_evidence_path(p_image)); - if (file_exists(p_image)) { + if (file_exists(p_image)) + { this->setText(""); - this->setStyleSheet( - "QPushButton { border-image: url(\"" + p_image + - "\") 0 0 0 0 stretch stretch; }" - "QToolTip { color: #000000; background-color: #ffffff; border: 0px; }"); + this->setStyleSheet("QPushButton { border-image: url(\"" + p_image + + "\") 0 0 0 0 stretch stretch; }" + "QToolTip { color: #000000; background-color: #ffffff; border: 0px; }"); } - else if (file_exists(image_path)) { + else if (file_exists(image_path)) + { this->setText(""); - this->setStyleSheet( - "QPushButton { border-image: url(\"" + image_path + - "\") 0 0 0 0 stretch stretch; }" - "QToolTip { color: #000000; background-color: #ffffff; border: 0px; }"); + this->setStyleSheet("QPushButton { border-image: url(\"" + image_path + + "\") 0 0 0 0 stretch stretch; }" + "QToolTip { color: #000000; background-color: #ffffff; border: 0px; }"); } - else { + else + { this->setText(p_image); this->setStyleSheet("QPushButton { border-image: url(); }" "QToolTip { background-image: url(); color: #000000; " @@ -57,17 +55,19 @@ void AOEvidenceButton::set_image(QString p_image) void AOEvidenceButton::set_theme_image(QString p_image) { - 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 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; if (file_exists(theme_image_path)) + { final_image_path = theme_image_path; + } else + { final_image_path = default_image_path; + } this->set_image(final_image_path); } @@ -75,17 +75,24 @@ void AOEvidenceButton::set_theme_image(QString p_image) void AOEvidenceButton::set_selected(bool p_selected) { if (p_selected) + { ui_selected->show(); + } else + { ui_selected->hide(); + } } -void AOEvidenceButton::on_clicked() { emit evidence_clicked(m_id); } +void AOEvidenceButton::on_clicked() +{ + Q_EMIT evidence_clicked(m_id); +} void AOEvidenceButton::mouseDoubleClickEvent(QMouseEvent *e) { QPushButton::mouseDoubleClickEvent(e); - emit evidence_double_clicked(m_id); + Q_EMIT evidence_double_clicked(m_id); } /* @@ -112,7 +119,7 @@ void AOEvidenceButton::enterEvent(QEnterEvent *e) { ui_selector->show(); - emit on_hover(m_id, true); + Q_EMIT on_hover(m_id, true); setFlat(false); QPushButton::enterEvent(e); @@ -122,6 +129,6 @@ void AOEvidenceButton::leaveEvent(QEvent *e) { ui_selector->hide(); - emit on_hover(m_id, false); + Q_EMIT on_hover(m_id, false); QPushButton::leaveEvent(e); } diff --git a/src/aoevidencebutton.h b/src/aoevidencebutton.h new file mode 100644 index 00000000..adaaa17a --- /dev/null +++ b/src/aoevidencebutton.h @@ -0,0 +1,48 @@ +#pragma once + +#include "aoapplication.h" +#include "aoimage.h" + +#include <QDebug> +#include <QEnterEvent> +#include <QPushButton> +#include <QString> + +class AOEvidenceButton : public QPushButton +{ + Q_OBJECT + +public: + AOEvidenceButton(AOApplication *p_ao_app, int p_x, int p_y, int p_w, int p_h, QWidget *p_parent = nullptr); + + void set_image(QString p_image); + void set_theme_image(QString p_image); + void set_id(int p_id) { m_id = p_id; } + + void set_selected(bool p_selected); + +Q_SIGNALS: + void evidence_clicked(int p_id); + void evidence_double_clicked(int p_id); + void on_hover(int p_id, bool p_state); + +protected: +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + void enterEvent(QEvent *e) override; +#else + void enterEvent(QEnterEvent *e) override; +#endif + void leaveEvent(QEvent *e) override; + void mouseDoubleClickEvent(QMouseEvent *e) override; + +private: + AOApplication *ao_app; + + int m_id = 0; + + AOImage *ui_selected; + AOImage *ui_selector; + +private Q_SLOTS: + void on_clicked(); +}; diff --git a/src/aoevidencedisplay.cpp b/src/aoevidencedisplay.cpp index ed27c007..6a5cf95c 100644 --- a/src/aoevidencedisplay.cpp +++ b/src/aoevidencedisplay.cpp @@ -2,77 +2,81 @@ #include "datatypes.h" #include "file_functions.h" -#include "misc_functions.h" -AOEvidenceDisplay::AOEvidenceDisplay(QWidget *p_parent, AOApplication *p_ao_app) +AOEvidenceDisplay::AOEvidenceDisplay(AOApplication *p_ao_app, QWidget *p_parent) : QLabel(p_parent) + , ao_app(p_ao_app) { - ao_app = p_ao_app; - evidence_icon = new QPushButton(this); - evidence_icon->hide(); - sfx_player = new AOSfxPlayer(this, ao_app); + ui_prompt_details = new QPushButton(this); + ui_prompt_details->hide(); - evidence_movie = new InterfaceLayer(this, ao_app); + m_sfx_player = new AOSfxPlayer(ao_app); - connect(evidence_movie, &InterfaceLayer::done, this, &AOEvidenceDisplay::show_done); - connect(evidence_icon, &QPushButton::clicked, this, &AOEvidenceDisplay::icon_clicked); + m_evidence_movie = new InterfaceLayer(ao_app, this); + + connect(m_evidence_movie, &InterfaceLayer::done, this, &AOEvidenceDisplay::show_done); + connect(ui_prompt_details, &QPushButton::clicked, this, &AOEvidenceDisplay::icon_clicked); } -void AOEvidenceDisplay::show_evidence(int p_index, QString p_evidence_image, - bool is_left_side, int p_volume) +void AOEvidenceDisplay::show_evidence(int p_index, QString p_evidence_image, bool is_left_side, int p_volume) { this->reset(); - last_evidence_index = p_index; + m_last_evidence_index = p_index; - sfx_player->set_volume(p_volume); + m_sfx_player->set_volume(p_volume); QString gif_name; QString icon_identifier; - if (is_left_side) { + if (is_left_side) + { icon_identifier = "left_evidence_icon"; gif_name = "evidence_appear_left"; } - else { + else + { icon_identifier = "right_evidence_icon"; gif_name = "evidence_appear_right"; } - QString f_evidence_path = ao_app->get_real_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 = - ao_app->get_element_dimensions(icon_identifier, "courtroom_design.ini"); + pos_size_type icon_dimensions = ao_app->get_element_dimensions(icon_identifier, "courtroom_design.ini"); f_pixmap = f_pixmap.scaled(icon_dimensions.width, icon_dimensions.height); QIcon f_icon(f_pixmap); - evidence_icon->setIcon(f_icon); - evidence_icon->setIconSize(f_pixmap.rect().size()); - evidence_icon->resize(f_pixmap.rect().size()); - evidence_icon->move(icon_dimensions.x, icon_dimensions.y); - evidence_movie->static_duration = 320; - evidence_movie->max_duration = 1000; - evidence_movie->set_play_once(true); - evidence_movie->load_image(gif_name, ""); - sfx_player->play(ao_app->get_court_sfx("evidence_present")); + ui_prompt_details->setIcon(f_icon); + ui_prompt_details->setIconSize(f_pixmap.rect().size()); + ui_prompt_details->resize(f_pixmap.rect().size()); + ui_prompt_details->move(icon_dimensions.x, icon_dimensions.y); + m_evidence_movie->static_duration = 320; + m_evidence_movie->max_duration = 1000; + m_evidence_movie->set_play_once(true); + m_evidence_movie->load_image(gif_name, ""); + m_sfx_player->play(ao_app->get_court_sfx("evidence_present")); } void AOEvidenceDisplay::reset() { - sfx_player->stop(); - evidence_movie->kill(); - evidence_icon->hide(); + m_sfx_player->stop(); + m_evidence_movie->kill(); + ui_prompt_details->hide(); this->clear(); } -void AOEvidenceDisplay::show_done() { evidence_icon->show(); } +void AOEvidenceDisplay::show_done() +{ + ui_prompt_details->show(); +} -void AOEvidenceDisplay::icon_clicked() { - if (last_evidence_index != -1) { - emit show_evidence_details(last_evidence_index - 1); // i dont know why i have to subtract 1 here +void AOEvidenceDisplay::icon_clicked() +{ + if (m_last_evidence_index != -1) + { + Q_EMIT show_evidence_details(m_last_evidence_index - 1); // i dont know why i have to subtract 1 here } } @@ -80,5 +84,5 @@ void AOEvidenceDisplay::combo_resize(int w, int h) { QSize f_size(w, h); this->resize(f_size); - evidence_movie->combo_resize(w, h); + m_evidence_movie->combo_resize(w, h); } diff --git a/src/aoevidencedisplay.h b/src/aoevidencedisplay.h new file mode 100644 index 00000000..b23bc0f7 --- /dev/null +++ b/src/aoevidencedisplay.h @@ -0,0 +1,37 @@ +#pragma once + +#include "aoapplication.h" +#include "aolayer.h" +#include "aosfxplayer.h" + +#include <QDebug> +#include <QLabel> +#include <QPushButton> + +class AOEvidenceDisplay : public QLabel +{ + Q_OBJECT + +public: + AOEvidenceDisplay(AOApplication *p_ao_app, QWidget *p_parent = nullptr); + + void show_evidence(int p_index, QString p_evidence_image, bool is_left_side, int p_volume); + void reset(); + void combo_resize(int w, int h); + +Q_SIGNALS: + void show_evidence_details(int index); + +private: + AOApplication *ao_app; + + int m_last_evidence_index = -1; + AOSfxPlayer *m_sfx_player; + + InterfaceLayer *m_evidence_movie; + QPushButton *ui_prompt_details; + +private Q_SLOTS: + void show_done(); + void icon_clicked(); +}; diff --git a/src/aoimage.cpp b/src/aoimage.cpp index e737ffb3..85f127ef 100644 --- a/src/aoimage.cpp +++ b/src/aoimage.cpp @@ -5,56 +5,33 @@ #include <QBitmap> -AOImage::AOImage(QWidget *parent, AOApplication *p_ao_app, bool make_static) : QLabel(parent) +AOImage::AOImage(AOApplication *p_ao_app, QWidget *parent) + : QLabel(parent) + , ao_app(p_ao_app) +{} + +AOImage::~AOImage() +{} + +QString AOImage::file_name() { - m_parent = parent; - ao_app = p_ao_app; - is_static = make_static; - if (!is_static) // Only create the QMovie if we're non-static - { - movie = new QMovie(this); - connect(movie, &QMovie::frameChanged, [this]{ - QPixmap f_pixmap = movie->currentPixmap(); - f_pixmap = - f_pixmap.scaled(this->size(), Qt::IgnoreAspectRatio); - this->setPixmap(f_pixmap); - if (masked) { - this->setMask(f_pixmap.mask()); - } - }); - } + return m_file_name; } -AOImage::~AOImage() {} - bool AOImage::set_image(QString p_image, QString p_misc) { - QString p_image_resolved = ao_app->get_image(p_image, Options::getInstance().theme(), Options::getInstance().subTheme(), - ao_app->default_theme, p_misc, "", "", - is_static || !Options::getInstance().animatedThemeEnabled()); + QString p_image_resolved = ao_app->get_image(p_image, Options::getInstance().theme(), Options::getInstance().subTheme(), ao_app->default_theme, p_misc, "", "", false); - if (!file_exists(p_image_resolved)) { + if (!file_exists(p_image_resolved)) + { qWarning() << "could not find image" << p_image; return false; } - path = p_image_resolved; - if (!is_static) { - movie->stop(); - movie->setFileName(path); - if (Options::getInstance().animatedThemeEnabled() && movie->frameCount() > 1) { - movie->start(); - } - } - if (is_static || !Options::getInstance().animatedThemeEnabled() || movie->frameCount() <= 1) { - QPixmap f_pixmap(path); - - f_pixmap = - f_pixmap.scaled(this->size(), Qt::IgnoreAspectRatio); - this->setPixmap(f_pixmap); - if (masked) { - this->setMask(f_pixmap.mask()); - } - } + m_file_name = p_image_resolved; + QPixmap f_pixmap(m_file_name); + f_pixmap = f_pixmap.scaled(size(), Qt::IgnoreAspectRatio); + setPixmap(f_pixmap); + return true; } diff --git a/src/aoimage.h b/src/aoimage.h new file mode 100644 index 00000000..5ab92e7b --- /dev/null +++ b/src/aoimage.h @@ -0,0 +1,27 @@ +// This class represents a static theme-dependent image + +#pragma once + +#include "aoapplication.h" + +#include <QDebug> +#include <QLabel> +#include <QMovie> + +class AOImage : public QLabel +{ + Q_OBJECT + +public: + AOImage(AOApplication *p_ao_app, QWidget *parent = nullptr); + AOImage(AOApplication *p_ao_app, bool make_static, QWidget *parent = nullptr); + ~AOImage(); + + QString file_name(); + bool set_image(QString p_image, QString p_misc = QString()); + +private: + AOApplication *ao_app; + + QString m_file_name; +}; diff --git a/src/aolayer.cpp b/src/aolayer.cpp index 4eaaf9f7..8284230e 100644 --- a/src/aolayer.cpp +++ b/src/aolayer.cpp @@ -2,12 +2,12 @@ #include "aoapplication.h" #include "file_functions.h" -#include "misc_functions.h" #include "options.h" static QThreadPool *thread_pool; -AOLayer::AOLayer(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_parent) +AOLayer::AOLayer(AOApplication *p_ao_app, QWidget *p_parent) + : QLabel(p_parent) { ao_app = p_ao_app; @@ -26,45 +26,47 @@ AOLayer::AOLayer(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_parent) preanim_timer->setSingleShot(true); connect(preanim_timer, &QTimer::timeout, this, &AOLayer::preanim_done); - if (!thread_pool) { + if (!thread_pool) + { thread_pool = new QThreadPool(p_ao_app); thread_pool->setMaxThreadCount(8); } } -BackgroundLayer::BackgroundLayer(QWidget *p_parent, AOApplication *p_ao_app) - : AOLayer(p_parent, p_ao_app) -{ -} -CharLayer::CharLayer(QWidget *p_parent, AOApplication *p_ao_app) - : AOLayer(p_parent, p_ao_app) -{ -} -EffectLayer::EffectLayer(QWidget *p_parent, AOApplication *p_ao_app) - : AOLayer(p_parent, p_ao_app) -{ -} -SplashLayer::SplashLayer(QWidget *p_parent, AOApplication *p_ao_app) - : AOLayer(p_parent, p_ao_app) -{ -} -InterfaceLayer::InterfaceLayer(QWidget *p_parent, AOApplication *p_ao_app) - : AOLayer(p_parent, p_ao_app) -{ -} -StickerLayer::StickerLayer(QWidget *p_parent, AOApplication *p_ao_app) - : AOLayer(p_parent, p_ao_app) -{ -} +BackgroundLayer::BackgroundLayer(AOApplication *p_ao_app, QWidget *p_parent) + : AOLayer(p_ao_app, p_parent) +{} + +CharLayer::CharLayer(AOApplication *p_ao_app, QWidget *p_parent) + : AOLayer(p_ao_app, p_parent) +{} + +EffectLayer::EffectLayer(AOApplication *p_ao_app, QWidget *p_parent) + : AOLayer(p_ao_app, p_parent) +{} + +SplashLayer::SplashLayer(AOApplication *p_ao_app, QWidget *p_parent) + : AOLayer(p_ao_app, p_parent) +{} + +InterfaceLayer::InterfaceLayer(AOApplication *p_ao_app, QWidget *p_parent) + : AOLayer(p_ao_app, p_parent) +{} + +StickerLayer::StickerLayer(AOApplication *p_ao_app, QWidget *p_parent) + : AOLayer(p_ao_app, p_parent) +{} QString AOLayer::find_image(QStringList p_list) { QString image_path; - for (const QString &path : p_list) { + for (const QString &path : p_list) + { #ifdef DEBUG_MOVIE qDebug() << "checking path " << path; #endif - if (file_exists(path)) { + if (file_exists(path)) + { image_path = path; #ifdef DEBUG_MOVIE qDebug() << "found path " << path; @@ -79,17 +81,28 @@ QPixmap AOLayer::get_pixmap(QImage image) { QPixmap f_pixmap; if (m_flipped) + { f_pixmap = QPixmap::fromImage(image.mirrored(true, false)); + } else + { f_pixmap = QPixmap::fromImage(image); + } // auto aspect_ratio = Qt::KeepAspectRatio; - if (!f_pixmap.isNull()) { + if (!f_pixmap.isNull()) + { if (f_pixmap.height() > f_h) // We are downscaling, use anti-aliasing. + { transform_mode = Qt::SmoothTransformation; + } if (stretch) + { f_pixmap = f_pixmap.scaled(f_w, f_h); + } else + { f_pixmap = f_pixmap.scaledToHeight(f_h, transform_mode); + } this->resize(f_pixmap.size()); } return f_pixmap; @@ -101,15 +114,16 @@ void AOLayer::set_frame(QPixmap f_pixmap) this->center_pixmap(f_pixmap); } -void AOLayer::center_pixmap(QPixmap f_pixmap) { - QLabel::move( - x + (f_w - f_pixmap.width()) / 2, - y + (f_h - f_pixmap.height())); // Always center horizontally, always put - // at the bottom vertically +void AOLayer::center_pixmap(QPixmap f_pixmap) +{ + QLabel::move(x + (f_w - f_pixmap.width()) / 2, + y + (f_h - f_pixmap.height())); // Always center horizontally, always put + // at the bottom vertically if (masked) - this->setMask( - QRegion((f_pixmap.width() - f_w) / 2, (f_pixmap.height() - f_h) / 2, f_w, - f_h)); // make sure we don't escape the area we've been given + { + this->setMask(QRegion((f_pixmap.width() - f_w) / 2, (f_pixmap.height() - f_h) / 2, f_w, + f_h)); // make sure we don't escape the area we've been given + } } void AOLayer::combo_resize(int w, int h) @@ -137,9 +151,13 @@ void AOLayer::move_and_center(int ax, int ay) x = ax; y = ay; if (movie_frames.isEmpty()) // safeguard - QLabel::move(x,y); + { + QLabel::move(x, y); + } else + { center_pixmap(movie_frames[0]); // just use the first frame since dimensions are all that matter + } } void BackgroundLayer::load_image(QString p_filename) @@ -147,15 +165,15 @@ void BackgroundLayer::load_image(QString p_filename) play_once = false; cull_image = false; VPath design_path = ao_app->get_background_path("design.ini"); - transform_mode = - ao_app->get_scaling(ao_app->read_design_ini("scaling", design_path)); + 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 QString final_path = ao_app->get_image_suffix(ao_app->get_background_path(p_filename)); - if (final_path == last_path) { + if (final_path == last_path) + { // Don't restart background if background is unchanged return; } @@ -164,24 +182,20 @@ void BackgroundLayer::load_image(QString p_filename) play(); } -void CharLayer::load_image(QString p_filename, QString p_charname, - int p_duration, bool p_is_preanim) +void CharLayer::load_image(QString p_filename, QString p_charname, int p_duration, bool p_is_preanim) { duration = p_duration; cull_image = false; force_continuous = false; - transform_mode = ao_app->get_scaling( - ao_app->get_emote_property(p_charname, p_filename, "scaling")); - stretch = ao_app->get_emote_property(p_charname, p_filename, "stretch") - .startsWith("true"); - if ((p_charname == last_char) && - ((p_filename == last_emote) || - (p_filename.mid(3, -1) == last_emote.mid(3, -1))) && - (!is_preanim) && (!was_preanim)) { + transform_mode = ao_app->get_scaling(ao_app->get_emote_property(p_charname, p_filename, "scaling")); + stretch = ao_app->get_emote_property(p_charname, p_filename, "stretch").startsWith("true"); + if ((p_charname == last_char) && ((p_filename == last_emote) || (p_filename.mid(3, -1) == last_emote.mid(3, -1))) && (!is_preanim) && (!was_preanim)) + { continuous = true; force_continuous = true; } - else { + else + { continuous = false; force_continuous = true; } @@ -194,12 +208,15 @@ 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)")) { // if we are playing an idle or talking animation + 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)")) { // else if we are playing a preanim or postanim - if (p_filename.left(3) == "(c)") { // if we are playing a postanim + 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); } @@ -209,29 +226,22 @@ void CharLayer::load_image(QString p_filename, QString p_charname, preanim_timer->start(duration); } #ifdef DEBUG_MOVIE - qDebug() << "[CharLayer] anim loaded: prefix " << prefix << " filename " - << current_emote << " from character: " << p_charname - << " continuous: " << continuous; + qDebug() << "[CharLayer] anim loaded: prefix " << prefix << " filename " << current_emote << " from character: " << p_charname << " continuous: " << continuous; #endif - QVector<VPath> pathlist { // cursed character path resolution vector - ao_app->get_character_path( - p_charname, prefix + current_emote), // Default path - ao_app->get_character_path( - p_charname, - prefix + "/" + current_emote), // Path check if it's categorized - // into a folder - ao_app->get_character_path( - p_charname, - current_emote), // Just use the non-prefixed image, animated or not - 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 + QVector<VPath> pathlist{ // cursed character path resolution vector + ao_app->get_character_path(p_charname, prefix + current_emote), // Default path + ao_app->get_character_path(p_charname, + prefix + "/" + current_emote), // Path check if it's categorized + // into a folder + ao_app->get_character_path(p_charname, + current_emote), // Just use the non-prefixed image, animated or not + 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 start_playback(ao_app->get_image_path(pathlist)); } -void SplashLayer::load_image(QString p_filename, QString p_charname, - QString p_miscname) +void SplashLayer::load_image(QString p_filename, QString p_charname, QString p_miscname) { transform_mode = ao_app->get_misc_scaling(p_miscname); QString final_image = ao_app->get_image(p_filename, Options::getInstance().theme(), Options::getInstance().subTheme(), ao_app->default_theme, p_miscname, p_charname, "placeholder"); @@ -242,9 +252,13 @@ void SplashLayer::load_image(QString p_filename, QString p_charname, void EffectLayer::load_image(QString p_filename, bool p_looping) { if (p_looping) + { play_once = false; + } else + { play_once = true; + } continuous = false; force_continuous = true; cull_image = false; @@ -266,7 +280,9 @@ void StickerLayer::load_image(QString p_charname) { QString p_miscname; if (Options::getInstance().customChatboxEnabled()) + { p_miscname = ao_app->get_chat(p_charname); + } transform_mode = ao_app->get_misc_scaling(p_miscname); QString final_image = ao_app->get_image("sticker/" + p_charname, Options::getInstance().theme(), Options::getInstance().subTheme(), ao_app->default_theme, p_miscname); start_playback(final_image); @@ -277,33 +293,43 @@ void CharLayer::start_playback(QString p_image) { movie_effects.clear(); AOLayer::start_playback(p_image); - if (network_strings.size() > 0) // our FX overwritten by networked ones + if (m_network_strings.size() > 0) // our FX overwritten by networked ones + { load_network_effects(); + } else // Use default ini FX + { load_effects(); + } play(); } void AOLayer::start_playback(QString p_image) { - if (p_image == "") {// image wasn't found by the path resolution function + if (p_image == "") + { // image wasn't found by the path resolution function this->kill(); return; } if (frame_loader.isRunning()) + { exit_loop = true; // tell the loader to stop, we have a new image to load + } QMutexLocker locker(&mutex); this->show(); - if (!Options::getInstance().continuousPlaybackEnabled()) { + if (!Options::getInstance().continuousPlaybackEnabled()) + { continuous = false; force_continuous = true; } if (((last_path == p_image) && (!force_continuous)) || p_image == "") + { return; + } #ifdef DEBUG_MOVIE actual_time.restart(); @@ -312,14 +338,16 @@ void AOLayer::start_playback(QString p_image) this->freeze(); movie_frames.clear(); movie_delays.clear(); - QString scaling_override = - ao_app->read_design_ini("scaling", p_image + ".ini"); + QString scaling_override = ao_app->read_design_ini("scaling", p_image + ".ini"); if (scaling_override != "") + { transform_mode = ao_app->get_scaling(scaling_override); - QString stretch_override = - ao_app->read_design_ini("stretch", p_image + ".ini"); + } + QString stretch_override = ao_app->read_design_ini("stretch", p_image + ".ini"); if (stretch_override != "") + { stretch = stretch_override.startsWith("true"); + } #ifdef DEBUG_MOVIE qDebug() << "[AOLayer::start_playback] Stretch:" << stretch << "Filename:" << p_image; @@ -328,35 +356,39 @@ void AOLayer::start_playback(QString p_image) last_max_frames = max_frames; max_frames = m_reader.imageCount(); if (m_reader.loopCount() == 0 && max_frames > 1) + { play_once = true; - if (!continuous - || ((continuous) && (max_frames != last_max_frames)) - || max_frames == 0 - || frame >= max_frames) { + } + if (!continuous || ((continuous) && (max_frames != last_max_frames)) || max_frames == 0 || frame >= max_frames) + { frame = 0; continuous = false; } - #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) frame_loader = QtConcurrent::run(thread_pool, this, &AOLayer::populate_vectors); - #else +#else frame_loader = QtConcurrent::run(thread_pool, &AOLayer::populate_vectors, this); - #endif +#endif last_path = p_image; 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]); - if (max_frames <= 1) { + if (max_frames <= 1) + { duration = static_duration; #ifdef DEBUG_MOVIE 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() << "[AOLayer::start_playback] Max frames:" << max_frames << "Setting image to " << p_image - << "Time taken to process image:" << actual_time.elapsed(); + qDebug() << "[AOLayer::start_playback] Max frames:" << max_frames << "Setting image to " << p_image << "Time taken to process image:" << actual_time.elapsed(); actual_time.restart(); #endif @@ -364,8 +396,10 @@ void AOLayer::start_playback(QString p_image) void CharLayer::play() { - if (max_frames <= 1) { - if (play_once) { + if (max_frames <= 1) + { + if (play_once) + { preanim_timer->start(qMax(0, duration)); } return; @@ -376,26 +410,42 @@ void CharLayer::play() void AOLayer::play() { - if (max_frames <= 1) { - if (play_once) { + if (max_frames <= 1) + { + if (play_once) + { if (duration > 0) + { ticker->start(duration); + } else + { preanim_done(); + } } else + { this->freeze(); + } } - else { - while (movie_delays.size() <= frame) { - frameAdded.wait(&mutex); + 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; } -void AOLayer::set_cull_image(bool p_cull_image) { cull_image = p_cull_image; } +void AOLayer::set_play_once(bool p_play_once) +{ + play_once = p_play_once; +} +void AOLayer::set_cull_image(bool p_cull_image) +{ + cull_image = p_cull_image; +} void AOLayer::set_static_duration(int p_static_duration) { static_duration = p_static_duration; @@ -409,21 +459,27 @@ void CharLayer::load_effects() { movie_effects.clear(); if (max_frames <= 1) + { return; + } movie_effects.resize(max_frames); - for (int e_frame = 0; e_frame < max_frames; ++e_frame) { + for (int e_frame = 0; e_frame < max_frames; ++e_frame) + { QString effect = ao_app->get_screenshake_frame(m_char, m_emote, e_frame); - if (effect != "") { + if (effect != "") + { movie_effects[e_frame].append("shake"); } effect = ao_app->get_flash_frame(m_char, m_emote, e_frame); - if (effect != "") { + if (effect != "") + { movie_effects[e_frame].append("flash"); } effect = ao_app->get_sfx_frame(m_char, m_emote, e_frame); - if (effect != "") { + if (effect != "") + { movie_effects[e_frame].append("sfx^" + effect); } } @@ -433,44 +489,54 @@ void CharLayer::load_network_effects() { movie_effects.clear(); if (max_frames <= 1) + { return; + } movie_effects.resize(max_frames); // Order is important!!! QStringList effects_list = {"shake", "flash", "sfx^"}; - // Determines which list is smaller - effects_list or network_strings - and - // uses it as basis for the loop. This way, incomplete network_strings would + // Determines which list is smaller - effects_list or m_network_strings - and + // uses it as basis for the loop. This way, incomplete m_network_strings would // still be parsed, and excess/unaccounted for networked information is // omitted. - int effects_size = qMin(effects_list.size(), network_strings.size()); + int effects_size = qMin(effects_list.size(), m_network_strings.size()); - for (int i = 0; i < effects_size; ++i) { - QString netstring = network_strings.at(i); + for (int i = 0; i < effects_size; ++i) + { + QString netstring = m_network_strings.at(i); QStringList emote_splits = netstring.split("^"); - for (const QString &emote : emote_splits) { + for (const QString &emote : emote_splits) + { QStringList parsed = emote.split("|"); if (parsed.size() <= 0 || parsed.at(0) != m_emote) + { continue; - foreach (QString frame_data, parsed) { + } + foreach (QString frame_data, parsed) + { QStringList frame_split = frame_data.split("="); - if (frame_split.size() <= - 1) // We might still be hanging at the emote itself (entry 0). + if (frame_split.size() <= 1) // We might still be hanging at the emote itself (entry 0). + { continue; + } int f_frame = frame_split.at(0).toInt(); - if (f_frame >= max_frames || f_frame < 0) { - qWarning() << "out of bounds" << effects_list[i] << "frame" - << f_frame << "out of" << max_frames << "for" << m_emote; + if (f_frame >= max_frames || f_frame < 0) + { + qWarning() << "out of bounds" << effects_list[i] << "frame" << f_frame << "out of" << max_frames << "for" << m_emote; continue; } QString f_data = frame_split.at(1); - if (f_data != "") { + if (f_data != "") + { QString effect = effects_list[i]; if (effect == "sfx^") // Currently the only frame result that feeds us // data, let's yank it in. + { effect += f_data; + } #ifdef DEBUG_MOVIE - qDebug() << "[CharLayer::load_network_effects]" << effect << f_data << "frame" << f_frame << "for" - << m_emote; + qDebug() << "[CharLayer::load_network_effects]" << effect << f_data << "frame" << f_frame << "for" << m_emote; #endif movie_effects[f_frame].append(effect); } @@ -481,29 +547,35 @@ void CharLayer::load_network_effects() void CharLayer::play_frame_effect(int p_frame) { - if (p_frame >= movie_effects.size()) { + if (p_frame >= movie_effects.size()) + { qWarning() << "Attempted to play a frame effect bigger than the size of movie_effects"; return; } - if (p_frame < max_frames) { - foreach (QString effect, movie_effects[p_frame]) { - if (effect == "shake") { - emit shake(); + if (p_frame < max_frames) + { + foreach (QString effect, movie_effects[p_frame]) + { + if (effect == "shake") + { + Q_EMIT shake(); #ifdef DEBUG_MOVIE qDebug() << "[CharLayer::play_frame_effect] Attempting to play shake on frame" << frame; #endif } - if (effect == "flash") { - emit flash(); + if (effect == "flash") + { + Q_EMIT flash(); #ifdef DEBUG_MOVIE qDebug() << "[CharLayer::play_frame_effect] Attempting to play flash on frame" << frame; #endif } - if (effect.startsWith("sfx^")) { + if (effect.startsWith("sfx^")) + { QString sfx = effect.section("^", 1); - emit play_sfx(sfx); + Q_EMIT play_sfx(sfx); #ifdef DEBUG_MOVIE qDebug() << "[CharLayer::play_frame_effect] Attempting to play sfx" << sfx << "on frame" << frame; #endif @@ -549,36 +621,47 @@ void CharLayer::movie_ticker() void AOLayer::movie_ticker() { ++frame; - if (frame >= max_frames) { - if (play_once) { + if (frame >= max_frames) + { + if (play_once) + { if (cull_image) + { this->stop(); + } else + { this->freeze(); + } preanim_done(); return; } else + { frame = 0; + } } { QMutexLocker locker(&mutex); 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 + } } #ifdef DEBUG_MOVIE - qDebug() << "[AOLayer::movie_ticker] Frame:" << frame << "Delay:" << 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() { +void AOLayer::populate_vectors() +{ #ifdef DEBUG_MOVIE qDebug() << "[AOLayer::populate_vectors] Started thread"; #endif - while (!exit_loop && movie_frames.size() < max_frames) { + while (!exit_loop && movie_frames.size() < max_frames) + { load_next_frame(); #ifdef DEBUG_MOVIE qDebug() << "[AOLayer::populate_vectors] Loaded frame" << movie_frames.size(); @@ -586,12 +669,15 @@ void AOLayer::populate_vectors() { } #ifdef DEBUG_MOVIE if (exit_loop) + { qDebug() << "[AOLayer::populate_vectors] Exit requested"; + } #endif exit_loop = false; } -void AOLayer::load_next_frame() { +void AOLayer::load_next_frame() +{ { QMutexLocker locker(&mutex); movie_frames.append(this->get_pixmap(m_reader.read())); @@ -603,16 +689,20 @@ void AOLayer::load_next_frame() { void CharLayer::preanim_done() { if (is_preanim) + { AOLayer::preanim_done(); + } else + { return; + } } void AOLayer::preanim_done() { ticker->stop(); preanim_timer->stop(); - emit done(); + Q_EMIT done(); } void AOLayer::shfx_timer_done() @@ -622,5 +712,5 @@ void AOLayer::shfx_timer_done() qDebug() << "shfx timer signaled done"; #endif // signal connected to courtroom object, let it figure out what to do - emit done(); + Q_EMIT done(); } diff --git a/src/aolayer.h b/src/aolayer.h new file mode 100644 index 00000000..0a44d8f5 --- /dev/null +++ b/src/aolayer.h @@ -0,0 +1,267 @@ +#pragma once + +#include <QBitmap> +#include <QDebug> +#include <QElapsedTimer> +#include <QImageReader> +#include <QLabel> +#include <QMutex> +#include <QTimer> +#include <QWaitCondition> +#include <QtConcurrent/QtConcurrentRun> + +class AOApplication; +class VPath; + +// "Brief" explanation of what the hell this is: +// +// AOLayer handles all animations both inside and outside +// the viewport. It was originally devised as a layering +// system, but turned into a full refactor of the existing +// animation code. +// +// AOLayer has six subclasses, all of which differ mainly in +// how they handle path resolution. +// +// - BackgroundLayer: self-explanatory, handles files found in base/background +// - CharLayer: handles all the "wonderful" quirks of character path resolution +// - SplashLayer: handles elements that can either be provided by a misc/ directory +// or by the theme - speedlines, shouts, WT/CE, et cetera +// - EffectLayer: this is basically a dummy layer since effects do their own wonky +// path resolution in a different file +// - InterfaceLayer: handles UI elements like the chat arrow and the music display +// - StickerLayer: Crystalwarrior really wanted this. Handles "stickers," whatever those are. +// +// For questions comments or concerns, bother someone else + +class AOLayer : public QLabel +{ + Q_OBJECT + +public: + AOLayer(AOApplication *p_ao_app, QWidget *p_parent = nullptr); + + QString filename; // file name without extension, i.e. "witnesstestimony" + int static_duration; // time in ms for static images to be displayed, if + // applicable. set to 0 for infinite + int max_duration; // maximum duration in ms, image will be culled if it is + // exceeded. set this to 0 for infinite duration + bool play_once = false; // Whether to loop this animation or not + bool cull_image = true; // if we're done playing this animation, should we + // hide it? also controls durational culling + // Are we loading this from the same frame we left off on? + bool continuous = false; + // Whether or not to forcibly bypass the simple check done by start_playback + // and use the existent value of continuous instead + bool force_continuous = false; + Qt::TransformationMode transform_mode = Qt::FastTransformation; // transformation mode to use for this image + bool stretch = false; // Should we stretch/squash this image to fill the screen? + bool masked = true; // Set a mask to the dimensions of the widget? + + // Set the movie's image to provided paths, preparing for playback. + void start_playback(QString p_image); + + void set_play_once(bool p_play_once); + void set_cull_image(bool p_cull_image); + void set_static_duration(int p_static_duration); + void set_max_duration(int p_max_duration); + + // Stop the movie, clearing the image + void stop(); + + // Stop the movie and clear all vectors + void kill(); + + // Set the m_flipped variable to true/false + void set_flipped(bool p_flipped) { m_flipped = p_flipped; } + + // Move the label itself around + void move(int ax, int ay); + + // Move the label and center it + void move_and_center(int ax, int ay); + + // This is somewhat pointless now as there's no "QMovie" object to resize, aka + // no "combo" to speak of + void combo_resize(int w, int h); + + // Return the frame delay adjusted for speed + int get_frame_delay(int delay); + + // iterate through a list of paths and return the first entry that exists. if + // none exist, return NULL (safe because we check again for existence later) + QString find_image(QStringList p_list); + +protected: + AOApplication *ao_app; + QVector<QPixmap> movie_frames; + QVector<int> movie_delays; + + QTimer *preanim_timer; + QTimer *shfx_timer; + QTimer *ticker; + QString last_path; + QImageReader m_reader; + + QElapsedTimer actual_time; + + // These are the X and Y values before they are fixed based on the sprite's + // width. + int x = 0; + int y = 0; + // These are the width and height values before they are fixed based on the + // sprite's width. + int f_w = 0; + int f_h = 0; + + int frame = 0; + int max_frames = 0; + int last_max_frames = 0; + + int speed = 100; + + bool m_flipped = false; + + int duration = 0; + + // Start playback of the movie (if animated). + void play(); + + // Freeze the movie at the current frame. + void freeze(); + + // Retreive a pixmap adjused for mirroring/aspect ratio shenanigans from a + // provided QImage + QPixmap get_pixmap(QImage image); + + // Set the movie's frame to provided pixmap + void set_frame(QPixmap f_pixmap); + // 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(); + std::atomic_bool exit_loop{false}; // awful solution but i'm not fucking using QThread + QFuture<void> frame_loader; + QMutex mutex; + QWaitCondition frameAdded; + +Q_SIGNALS: + void done(); + +protected Q_SLOTS: + virtual void preanim_done(); + void shfx_timer_done(); + virtual void movie_ticker(); +}; + +class BackgroundLayer : public AOLayer +{ + Q_OBJECT +public: + BackgroundLayer(AOApplication *p_ao_app, QWidget *p_parent); + void load_image(QString p_filename); +}; + +class CharLayer : public AOLayer +{ + Q_OBJECT + +public: + CharLayer(AOApplication *p_ao_app, QWidget *p_parent = nullptr); + + QStringList &network_strings2() { return m_network_strings; } + void set_network_string(QStringList list) { m_network_strings = list; } + + void load_image(QString p_filename, QString p_charname, int p_duration, bool p_is_preanim); + + void play(); // overloaded so we can play effects + +private: + QString current_emote; // name of the emote we're using + bool is_preanim; // equivalent to the old play_once, if true we don't want + // to loop this + QString prefix; // prefix, left blank if it's a preanim + QStringList m_network_strings; + + QString last_char; // name of the last character we used + QString last_emote; // name of the last animation we used + QString last_prefix; // prefix of the last animation we played + bool was_preanim = false; // whether is_preanim was true last time + + // Effects such as sfx, screenshakes and realization flashes are stored in + // here. QString entry format: "sfx^[sfx_name]", "shake", "flash". The program + // uses the QVector index as reference. + QVector<QVector<QString>> movie_effects; + + // used for effect loading + QString m_char; + QString m_emote; + + // overloaded for effects reasons + void start_playback(QString p_image); + + // Initialize the frame-specific effects from the char.ini + void load_effects(); + + // Initialize the frame-specific effects from the provided network_strings, + // this is only initialized if network_strings has size more than 0. + void load_network_effects(); + + // Play a frame-specific effect, if there's any defined for that specific + // frame. + void play_frame_effect(int p_frame); + +private Q_SLOTS: + void preanim_done() override; // overridden so we don't accidentally cull characters + void movie_ticker() override; // overridden so we can play effects + +Q_SIGNALS: + void shake(); + void flash(); + void play_sfx(QString sfx); +}; + +class SplashLayer : public AOLayer +{ + Q_OBJECT + +public: + SplashLayer(AOApplication *p_ao_app, QWidget *p_parent = nullptr); + + void load_image(QString p_filename, QString p_charname, QString p_miscname); +}; + +class EffectLayer : public AOLayer +{ + Q_OBJECT + +public: + EffectLayer(AOApplication *p_ao_app, QWidget *p_parent = nullptr); + + void load_image(QString p_filename, bool p_looping); +}; + +class InterfaceLayer : public AOLayer +{ + Q_OBJECT + +public: + InterfaceLayer(AOApplication *p_ao_app, QWidget *p_parent = nullptr); + + void load_image(QString p_filename, QString p_miscname); +}; + +class StickerLayer : public AOLayer +{ + Q_OBJECT + +public: + StickerLayer(AOApplication *p_ao_app, QWidget *p_parent = nullptr); + + void load_image(QString p_charname); +}; diff --git a/src/aomusicplayer.cpp b/src/aomusicplayer.cpp index 3f7c43ee..b9e6ab98 100644 --- a/src/aomusicplayer.cpp +++ b/src/aomusicplayer.cpp @@ -1,74 +1,92 @@ #include "aomusicplayer.h" -#include "options.h" -#include "bass.h" #include "file_functions.h" +#include "options.h" -AOMusicPlayer::AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app) -{ - m_parent = parent; - ao_app = p_ao_app; -} +#include <bass.h> + +#include <QDebug> +#include <QFuture> +#include <QWidget> + +AOMusicPlayer::AOMusicPlayer(AOApplication *p_ao_app) + : ao_app(p_ao_app) +{} AOMusicPlayer::~AOMusicPlayer() { - for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) { + for (int n_stream = 0; n_stream < CHANNEL_COUNT; ++n_stream) + { BASS_ChannelStop(m_stream_list[n_stream]); } } -QString AOMusicPlayer::play(QString p_song, int channel, bool loop, - int effect_flags) +QString AOMusicPlayer::play(QString p_song, int channel, bool loop, int effect_flags) { - channel = channel % m_channelmax; + channel = channel % CHANNEL_COUNT; if (channel < 0) // wtf? + { return "[ERROR] Invalid Channel"; - unsigned int flags = BASS_STREAM_PRESCAN | BASS_STREAM_AUTOFREE | - BASS_UNICODE | BASS_ASYNCFILE; + } + unsigned int flags = BASS_STREAM_PRESCAN | BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE; unsigned int streaming_flags = BASS_STREAM_AUTOFREE; - if (loop) { + if (loop) + { flags |= BASS_SAMPLE_LOOP; streaming_flags |= BASS_SAMPLE_LOOP; } QString f_path = p_song; DWORD newstream; - if (f_path.startsWith("http")) { - - if (!Options::getInstance().streamingEnabled()) { - BASS_ChannelStop(m_stream_list[channel]); - return QObject::tr("[MISSING] Streaming disabled."); + if (f_path.startsWith("http")) + { + if (!Options::getInstance().streamingEnabled()) + { + BASS_ChannelStop(m_stream_list[channel]); + return QObject::tr("[MISSING] Streaming disabled."); } QUrl l_url = QUrl(f_path); newstream = BASS_StreamCreateURL(l_url.toEncoded().toStdString().c_str(), 0, streaming_flags, nullptr, 0); } - else { + else + { f_path = ao_app->get_real_path(ao_app->get_music_path(p_song)); - if (f_path.endsWith(".mo3") || f_path.endsWith(".xm") || f_path.endsWith(".mod") || f_path.endsWith(".s3m") || f_path.endsWith(".it") || f_path.endsWith(".mtm") || f_path.endsWith(".umx") ) - newstream = BASS_MusicLoad(FALSE,f_path.utf16(), 0, 0, flags, 1); + if (f_path.endsWith(".mo3") || f_path.endsWith(".xm") || f_path.endsWith(".mod") || f_path.endsWith(".s3m") || f_path.endsWith(".it") || f_path.endsWith(".mtm") || f_path.endsWith(".umx")) + { + newstream = BASS_MusicLoad(FALSE, f_path.utf16(), 0, 0, flags, 1); + } else + { newstream = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, flags); + } } int error_code = BASS_ErrorGetCode(); if (Options::getInstance().audioOutputDevice() != "default") + { BASS_ChannelSetDevice(m_stream_list[channel], BASS_GetDevice()); + } QString d_path = f_path + ".txt"; - loop_start[channel] = 0; - loop_end[channel] = 0; + m_loop_start[channel] = 0; + m_loop_end[channel] = 0; if (loop && file_exists(d_path)) // Contains loop/etc. information file { QStringList lines = ao_app->read_file(d_path).split("\n"); bool seconds_mode = false; - foreach (QString line, lines) { + foreach (QString line, lines) + { QStringList args = line.split("="); if (args.size() < 2) + { continue; + } QString arg = args[0].trimmed(); - if (arg == "seconds") { - if (args[1].trimmed() == "true") { + if (arg == "seconds") + { + if (args[1].trimmed() == "true") + { seconds_mode = true; // Use new epic behavior continue; } @@ -86,64 +104,71 @@ QString AOMusicPlayer::play(QString p_song, int channel, bool loop, // Calculate the bytes for loop_start/loop_end to use with the sync proc QWORD bytes; - if (seconds_mode) { - bytes = - BASS_ChannelSeconds2Bytes(newstream, args[1].trimmed().toDouble()); + if (seconds_mode) + { + bytes = BASS_ChannelSeconds2Bytes(newstream, args[1].trimmed().toDouble()); } - else { - bytes = static_cast<QWORD>(args[1].trimmed().toUInt() * sample_size * - num_channels); + else + { + bytes = static_cast<QWORD>(args[1].trimmed().toUInt() * sample_size * num_channels); } if (arg == "loop_start") - loop_start[channel] = bytes; + { + m_loop_start[channel] = bytes; + } else if (arg == "loop_length") - loop_end[channel] = loop_start[channel] + bytes; + { + m_loop_end[channel] = m_loop_start[channel] + bytes; + } else if (arg == "loop_end") - loop_end[channel] = bytes; + { + m_loop_end[channel] = bytes; + } } - qDebug() << "Found data file for song" << p_song << "length" - << BASS_ChannelGetLength(newstream, BASS_POS_BYTE) << "loop start" - << loop_start[channel] << "loop end" << loop_end[channel]; + qDebug() << "Found data file for song" << p_song << "length" << BASS_ChannelGetLength(newstream, BASS_POS_BYTE) << "loop start" << m_loop_start[channel] << "loop end" << m_loop_end[channel]; } - if (BASS_ChannelIsActive(m_stream_list[channel]) == BASS_ACTIVE_PLAYING) { + if (BASS_ChannelIsActive(m_stream_list[channel]) == BASS_ACTIVE_PLAYING) + { DWORD oldstream = m_stream_list[channel]; - if (effect_flags & SYNC_POS) { + if (effect_flags & SYNC_POS) + { BASS_ChannelLock(oldstream, true); // Sync it with the new sample - BASS_ChannelSetPosition(newstream, - BASS_ChannelGetPosition(oldstream, BASS_POS_BYTE), - BASS_POS_BYTE); + BASS_ChannelSetPosition(newstream, BASS_ChannelGetPosition(oldstream, BASS_POS_BYTE), BASS_POS_BYTE); BASS_ChannelLock(oldstream, false); } - if ((effect_flags & FADE_OUT) && m_volume[channel] > 0) { + if ((effect_flags & FADE_OUT) && m_volume[channel] > 0) + { // Fade out the other sample and stop it (due to -1) - BASS_ChannelSlideAttribute(oldstream, BASS_ATTRIB_VOL | BASS_SLIDE_LOG, - -1, 4000); + BASS_ChannelSlideAttribute(oldstream, BASS_ATTRIB_VOL | BASS_SLIDE_LOG, -1, 4000); } else - BASS_ChannelStop( - oldstream); // Stop the sample since we don't need it anymore + { + BASS_ChannelStop(oldstream); // Stop the sample since we don't need it anymore + } } else + { BASS_ChannelStop(m_stream_list[channel]); + } m_stream_list[channel] = newstream; BASS_ChannelPlay(newstream, false); - if (effect_flags & FADE_IN) { + if (effect_flags & FADE_IN) + { // Fade in our sample BASS_ChannelSetAttribute(newstream, BASS_ATTRIB_VOL, 0); - BASS_ChannelSlideAttribute(newstream, BASS_ATTRIB_VOL, - static_cast<float>(m_volume[channel] / 100.0f), - 1000); + BASS_ChannelSlideAttribute(newstream, BASS_ATTRIB_VOL, static_cast<float>(m_volume[channel] / 100.0f), 1000); } else + { this->set_volume(m_volume[channel], channel); + } - BASS_ChannelSetSync(newstream, BASS_SYNC_DEV_FAIL, 0, - ao_app->BASSreset, 0); + BASS_ChannelSetSync(newstream, BASS_SYNC_DEV_FAIL, 0, ao_app->BASSreset, 0); this->set_looping(loop, channel); // Have to do this here due to any // crossfading-related changes, etc. @@ -152,20 +177,25 @@ QString AOMusicPlayer::play(QString p_song, int channel, bool loop, QString p_song_clear = QUrl(p_song).fileName(); p_song_clear = p_song_clear.left(p_song_clear.lastIndexOf('.')); - if (is_stop && channel == 0) { // don't send text on channels besides 0 + if (is_stop && channel == 0) + { // don't send text on channels besides 0 return QObject::tr("None"); } - if (error_code == BASS_ERROR_HANDLE) { // Cheap hack to see if file missing + if (error_code == BASS_ERROR_HANDLE) + { // Cheap hack to see if file missing return QObject::tr("[MISSING] %1").arg(p_song_clear); } - if (p_song.startsWith("http") && channel == 0) { + if (p_song.startsWith("http") && channel == 0) + { return QObject::tr("[STREAM] %1").arg(p_song_clear); } if (channel == 0) + { return p_song_clear; + } return ""; } @@ -179,7 +209,8 @@ void AOMusicPlayer::set_muted(bool toggle) { m_muted = toggle; // Update all volume based on the mute setting - for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) { + for (int n_stream = 0; n_stream < CHANNEL_COUNT; ++n_stream) + { set_volume(m_volume[n_stream], n_stream); } } @@ -189,13 +220,15 @@ void AOMusicPlayer::set_volume(int p_value, int channel) m_volume[channel] = p_value; // If muted, volume will always be 0 float volume = (m_volume[channel] / 100.0f) * !m_muted; - if (channel < 0) { - for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) { - BASS_ChannelSetAttribute(m_stream_list[n_stream], BASS_ATTRIB_VOL, - volume); + if (channel < 0) + { + for (int n_stream = 0; n_stream < CHANNEL_COUNT; ++n_stream) + { + BASS_ChannelSetAttribute(m_stream_list[n_stream], BASS_ATTRIB_VOL, volume); } } - else { + else + { BASS_ChannelSetAttribute(m_stream_list[channel], BASS_ATTRIB_VOL, volume); } } @@ -212,35 +245,35 @@ void CALLBACK loopProc(HSYNC handle, DWORD channel, DWORD data, void *user) void AOMusicPlayer::set_looping(bool loop_song, int channel) { - if (!loop_song) { + if (!loop_song) + { if (BASS_ChannelFlags(m_stream_list[channel], 0, 0) & BASS_SAMPLE_LOOP) + { BASS_ChannelFlags(m_stream_list[channel], 0, BASS_SAMPLE_LOOP); // remove the LOOP flag - BASS_ChannelRemoveSync(m_stream_list[channel], loop_sync[channel]); - loop_sync[channel] = 0; + } + BASS_ChannelRemoveSync(m_stream_list[channel], m_loop_sync[channel]); + m_loop_sync[channel] = 0; return; } BASS_ChannelFlags(m_stream_list[channel], BASS_SAMPLE_LOOP, BASS_SAMPLE_LOOP); // set the LOOP flag - if (loop_sync[channel] != 0) { + if (m_loop_sync[channel] != 0) + { BASS_ChannelRemoveSync(m_stream_list[channel], - loop_sync[channel]); // remove the sync - loop_sync[channel] = 0; + m_loop_sync[channel]); // remove the sync + m_loop_sync[channel] = 0; } - if (loop_start[channel] < loop_end[channel]) + if (m_loop_start[channel] < m_loop_end[channel]) { - //Loop when the endpoint is reached. - loop_sync[channel] = BASS_ChannelSetSync( - m_stream_list[channel], BASS_SYNC_POS | BASS_SYNC_MIXTIME, - loop_end[channel], loopProc, &loop_start[channel]); + // Loop when the endpoint is reached. + m_loop_sync[channel] = BASS_ChannelSetSync(m_stream_list[channel], BASS_SYNC_POS | BASS_SYNC_MIXTIME, m_loop_end[channel], loopProc, &m_loop_start[channel]); } else { - //Loop when the end of the file is reached. - loop_sync[channel] = BASS_ChannelSetSync( - m_stream_list[channel], BASS_SYNC_END | BASS_SYNC_MIXTIME, - 0, loopProc, &loop_start[channel]); + // Loop when the end of the file is reached. + m_loop_sync[channel] = BASS_ChannelSetSync(m_stream_list[channel], BASS_SYNC_END | BASS_SYNC_MIXTIME, 0, loopProc, &m_loop_start[channel]); } } diff --git a/src/aomusicplayer.h b/src/aomusicplayer.h new file mode 100644 index 00000000..248a45e3 --- /dev/null +++ b/src/aomusicplayer.h @@ -0,0 +1,44 @@ +#pragma once + +#include "aoapplication.h" + +#include <QFutureWatcher> + +class AOMusicPlayer +{ +public: + // Channel 0 = music + // Channel 1 = ambience + static constexpr int CHANNEL_COUNT = 2; + + AOMusicPlayer(AOApplication *p_ao_app); + virtual ~AOMusicPlayer(); + + void set_volume(int p_value, int channel = -1); + void set_looping(bool loop_song, int channel = 0); + void set_muted(bool toggle); + + QFutureWatcher<QString> music_watcher; + +public Q_SLOTS: + QString play(QString p_song, int channel = 0, bool loop = false, int effect_flags = 0); + void stop(int channel = 0); + +private: + AOApplication *ao_app; + + bool m_muted = false; + int m_volume[CHANNEL_COUNT] = {0, 0}; + HSTREAM m_stream_list[CHANNEL_COUNT]; + HSYNC m_loop_sync[CHANNEL_COUNT]; + + /** + * @brief The starting sample of the AB-Loop. + */ + unsigned int m_loop_start[CHANNEL_COUNT] = {0, 0}; + + /** + * @brief The end sample of the AB-Loop. + */ + unsigned int m_loop_end[CHANNEL_COUNT] = {0, 0}; +}; diff --git a/src/aopacket.cpp b/src/aopacket.cpp index 4a89e980..663edc52 100644 --- a/src/aopacket.cpp +++ b/src/aopacket.cpp @@ -1,42 +1,48 @@ #include "aopacket.h" -QString AOPacket::to_string(bool encoded) +QString AOPacket::encode(QString data) { - QStringList contents = m_contents; - if (encoded) { - escape(contents); - } - // Our packet is just the header by itself - if (contents.isEmpty()) { - return m_header + "#%"; - } - return m_header + "#" + contents.join("#") + "#%"; + return data.replace("#", "<num>").replace("%", "<percent>").replace("$", "<dollar>").replace("&", "<and>"); } -void AOPacket::net_encode() +QString AOPacket::decode(QString data) { - escape(m_contents); + return data.replace("<num>", "#").replace("<percent>", "%").replace("<dollar>", "$").replace("<and>", "&"); } -void AOPacket::net_decode() +AOPacket::AOPacket(QString header) + : m_header(header) +{} + +AOPacket::AOPacket(QString header, QStringList content) + : m_header(header) + , m_content(content) +{} + +QString AOPacket::get_header() { - unescape(m_contents); + return m_header; } -void AOPacket::escape(QStringList &contents) +QStringList &AOPacket::get_content() { - contents.replaceInStrings("#", "<num>") - .replaceInStrings("%", "<percent>") - .replaceInStrings("$", "<dollar>") - .replaceInStrings("&", "<and>"); - + return m_content; } -void AOPacket::unescape(QStringList &contents) +QString AOPacket::to_string(bool ensureEncoded) { - contents.replaceInStrings("<num>", "#") - .replaceInStrings("<percent>", "%") - .replaceInStrings("<dollar>", "$") - .replaceInStrings("<and>", "&"); + QString message = m_header; + if (!m_content.isEmpty()) + { + for (QString item : qAsConst(m_content)) + { + if (ensureEncoded) + { + item = encode(item); + } + message += "#" + item; + } + } + return message + "#%"; } diff --git a/src/aopacket.h b/src/aopacket.h new file mode 100644 index 00000000..df7f09c2 --- /dev/null +++ b/src/aopacket.h @@ -0,0 +1,22 @@ +#pragma once + +#include <QString> +#include <QStringList> + +class AOPacket +{ +public: + static QString encode(QString data); + static QString decode(QString data); + + AOPacket(QString header); + AOPacket(QString header, QStringList content); + + QString get_header(); + QStringList &get_content(); + QString to_string(bool ensureEncoded = false); + +private: + QString m_header; + QStringList m_content; +}; diff --git a/src/aosfxplayer.cpp b/src/aosfxplayer.cpp index 8d88667c..1b9be002 100644 --- a/src/aosfxplayer.cpp +++ b/src/aosfxplayer.cpp @@ -1,15 +1,15 @@ #include "aosfxplayer.h" + #include "file_functions.h" -AOSfxPlayer::AOSfxPlayer(QWidget *parent, AOApplication *p_ao_app) -{ - m_parent = parent; - ao_app = p_ao_app; -} +AOSfxPlayer::AOSfxPlayer(AOApplication *p_ao_app) + : ao_app(p_ao_app) +{} void AOSfxPlayer::clear() { - for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) { + for (int n_stream = 0; n_stream < CHANNEL_COUNT; ++n_stream) + { BASS_ChannelStop(m_stream_list[n_stream]); } set_volume_internal(m_volume); @@ -17,44 +17,51 @@ void AOSfxPlayer::clear() void AOSfxPlayer::loop_clear() { - for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) { + for (int n_stream = 0; n_stream < CHANNEL_COUNT; ++n_stream) + { if ((BASS_ChannelFlags(m_stream_list[n_stream], 0, 0) & BASS_SAMPLE_LOOP)) + { BASS_ChannelStop(m_stream_list[n_stream]); + } } set_volume_internal(m_volume); } void AOSfxPlayer::play(QString p_sfx, QString p_character, QString p_misc) { - for (int i = 0; i < m_channelmax; ++i) { + for (int i = 0; i < CHANNEL_COUNT; ++i) + { if (BASS_ChannelIsActive(m_stream_list[i]) == BASS_ACTIVE_PLAYING) - m_channel = (i + 1) % m_channelmax; - else { + { + m_channel = (i + 1) % CHANNEL_COUNT; + } + else + { m_channel = i; break; } } QString path = ao_app->get_sfx(p_sfx, p_misc, p_character); if (path.endsWith(".opus")) - m_stream_list[m_channel] = BASS_OPUS_StreamCreateFile( - FALSE, path.utf16(), 0, 0, - BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE); + { + m_stream_list[m_channel] = BASS_OPUS_StreamCreateFile(FALSE, path.utf16(), 0, 0, BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE); + } else - m_stream_list[m_channel] = BASS_StreamCreateFile( - FALSE, path.utf16(), 0, 0, - BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE); + { + m_stream_list[m_channel] = BASS_StreamCreateFile(FALSE, path.utf16(), 0, 0, BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE); + } set_volume_internal(m_volume); 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); + BASS_ChannelSetSync(m_stream_list[m_channel], BASS_SYNC_DEV_FAIL, 0, ao_app->BASSreset, 0); } void AOSfxPlayer::stop(int channel) { - if (channel == -1) { + if (channel == -1) + { channel = m_channel; } BASS_ChannelStop(m_stream_list[channel]); @@ -67,6 +74,11 @@ void AOSfxPlayer::set_muted(bool toggle) set_volume_internal(m_volume); } +int AOSfxPlayer::get_volume() +{ + return m_volume * 100; +} + void AOSfxPlayer::set_volume(qreal p_value) { m_volume = p_value * 0.01; @@ -77,25 +89,33 @@ void AOSfxPlayer::set_volume_internal(qreal p_value) { // If muted, volume will always be 0 float volume = static_cast<float>(p_value) * !m_muted; - for (int n_stream = 0; n_stream < m_channelmax; ++n_stream) { + for (int n_stream = 0; n_stream < CHANNEL_COUNT; ++n_stream) + { BASS_ChannelSetAttribute(m_stream_list[n_stream], BASS_ATTRIB_VOL, volume); } } void AOSfxPlayer::set_looping(bool toggle, int channel) { - if (channel == -1) { + if (channel == -1) + { channel = m_channel; } m_looping = toggle; - if (BASS_ChannelFlags(m_stream_list[channel], 0, 0) & BASS_SAMPLE_LOOP) { + if (BASS_ChannelFlags(m_stream_list[channel], 0, 0) & BASS_SAMPLE_LOOP) + { if (m_looping == false) + { BASS_ChannelFlags(m_stream_list[channel], 0, BASS_SAMPLE_LOOP); // remove the LOOP flag + } } - else { + else + { if (m_looping == true) + { BASS_ChannelFlags(m_stream_list[channel], BASS_SAMPLE_LOOP, BASS_SAMPLE_LOOP); // set the LOOP flag + } } } diff --git a/src/aosfxplayer.h b/src/aosfxplayer.h new file mode 100644 index 00000000..6a71a71c --- /dev/null +++ b/src/aosfxplayer.h @@ -0,0 +1,38 @@ +#pragma once + +#include "bass.h" +#include "bassopus.h" + +#include "aoapplication.h" + +#include <QDebug> +#include <QWidget> + +class AOSfxPlayer +{ +public: + static constexpr int CHANNEL_COUNT = 5; + + AOSfxPlayer(AOApplication *p_ao_app); + + int get_volume(); + + void clear(); + void loop_clear(); + void play(QString p_sfx, QString p_char = QString(), QString shout = QString()); + void stop(int channel = -1); + void set_volume(qreal p_volume); + void set_looping(bool toggle, int channel = -1); + void set_muted(bool toggle); + +private: + AOApplication *ao_app; + + qreal m_volume = 0.0; + bool m_looping = true; + bool m_muted = false; + int m_channel = 0; + HSTREAM m_stream_list[CHANNEL_COUNT]{}; + + void set_volume_internal(qreal p_volume); +}; diff --git a/src/aotextarea.cpp b/src/aotextarea.cpp index a4259039..cf651244 100644 --- a/src/aotextarea.cpp +++ b/src/aotextarea.cpp @@ -1,42 +1,36 @@ #include "aotextarea.h" -AOTextArea::AOTextArea(QWidget *p_parent, int p_log_length) : QTextBrowser(p_parent) -{ - this->document()->setMaximumBlockCount(p_log_length); -} +AOTextArea::AOTextArea(QWidget *p_parent) + : AOTextArea(5000, p_parent) +{} -void AOTextArea::append_linked(QString p_message) +AOTextArea::AOTextArea(int p_log_length, QWidget *p_parent) + : QTextBrowser(p_parent) { - QString result = p_message.toHtmlEscaped() - .replace("\n", "<br>") - .replace(url_parser_regex, "<a href='\\1'>\\1</a>"); - this->insertHtml(result); + this->document()->setMaximumBlockCount(p_log_length); } -void AOTextArea::append_chatmessage(QString p_name, QString p_message, - QString p_name_colour, QString p_color) +void AOTextArea::append_chatmessage(QString p_name, QString p_message, QString p_name_colour, QString p_color) { const QTextCursor old_cursor = this->textCursor(); const int old_scrollbar_value = this->verticalScrollBar()->value(); - const bool is_scrolled_down = - old_scrollbar_value == this->verticalScrollBar()->maximum(); + const bool is_scrolled_down = old_scrollbar_value == this->verticalScrollBar()->maximum(); this->moveCursor(QTextCursor::End); this->append(""); - if (!p_name.isEmpty()) { - this->insertHtml("<b><font color=" + p_name_colour + ">" + p_name.toHtmlEscaped() + - "</font></b>: "); + if (!p_name.isEmpty()) + { + this->insertHtml("<b><font color=" + p_name_colour + ">" + p_name.toHtmlEscaped() + "</font></b>: "); // cheap workarounds ahoy p_message += " "; } - QString result = p_message.toHtmlEscaped() - .replace("\n", "<br>") - .replace(url_parser_regex, "<a href='\\1'>\\1</a>"); + QString result = p_message.toHtmlEscaped().replace("\n", "<br>").replace(url_parser_regex, "<a href='\\1'>\\1</a>"); - if (!p_color.isEmpty()) { + if (!p_color.isEmpty()) + { result = "<font color=" + p_color + ">" + result + "</font>"; } @@ -45,36 +39,17 @@ void AOTextArea::append_chatmessage(QString p_name, QString p_message, this->auto_scroll(old_cursor, old_scrollbar_value, is_scrolled_down); } -void AOTextArea::append_error(QString p_message) -{ - const QTextCursor old_cursor = this->textCursor(); - const int old_scrollbar_value = this->verticalScrollBar()->value(); - const bool is_scrolled_down = - old_scrollbar_value == this->verticalScrollBar()->maximum(); - - this->moveCursor(QTextCursor::End); - - this->append(""); - - p_message += " "; - QString result = p_message.replace("\n", "<br>") - .replace(url_parser_regex, "<a href='\\1'>\\1</a>"); - - this->insertHtml("<font color='red'>" + result + "</font>"); - - this->auto_scroll(old_cursor, old_scrollbar_value, is_scrolled_down); -} - -void AOTextArea::auto_scroll(QTextCursor old_cursor, int old_scrollbar_value, - bool is_scrolled_down) +void AOTextArea::auto_scroll(QTextCursor old_cursor, int old_scrollbar_value, bool is_scrolled_down) { - if (old_cursor.hasSelection() || !is_scrolled_down) { + if (old_cursor.hasSelection() || !is_scrolled_down) + { // The user has selected text or scrolled away from the bottom: maintain // position. this->setTextCursor(old_cursor); this->verticalScrollBar()->setValue(old_scrollbar_value); } - else { + else + { // The user hasn't selected any text and the scrollbar is at the bottom: // scroll to the bottom. this->moveCursor(QTextCursor::End); diff --git a/src/aotextarea.h b/src/aotextarea.h new file mode 100644 index 00000000..b6f6ec6a --- /dev/null +++ b/src/aotextarea.h @@ -0,0 +1,23 @@ +#pragma once + +#include <QDebug> +#include <QRegularExpression> +#include <QScrollBar> +#include <QTextBrowser> +#include <QTextCursor> + +class AOTextArea : public QTextBrowser +{ + Q_OBJECT + +public: + AOTextArea(QWidget *p_parent = nullptr); + AOTextArea(int p_log_length, QWidget *p_parent = nullptr); + + void append_chatmessage(QString p_name, QString p_message, QString p_name_colour, QString p_color = QString()); + +private: + const QRegularExpression url_parser_regex = QRegularExpression("\\b(https?://\\S+\\.\\S+)\\b"); + + void auto_scroll(QTextCursor old_cursor, int scrollbar_value, bool is_scrolled_down); +}; diff --git a/src/aotextboxwidgets.cpp b/src/aotextboxwidgets.cpp index 1a16e8fe..a6999beb 100644 --- a/src/aotextboxwidgets.cpp +++ b/src/aotextboxwidgets.cpp @@ -1,21 +1,44 @@ #include "aotextboxwidgets.h" -AOChatboxLabel::AOChatboxLabel(QWidget *parent) : QLabel(parent) {} +AOChatboxLabel::AOChatboxLabel(QWidget *parent) + : QLabel(parent) +{} + +void AOChatboxLabel::setOutlineColor(QColor color) +{ + m_outline_color = color; +} + +void AOChatboxLabel::setOutlineWidth(int width) +{ + m_outline_width = width; +} + +void AOChatboxLabel::setIsOutlined(bool outlined) +{ + m_outline = outlined; +} + +void AOChatboxLabel::setTextColor(QColor color) +{ + m_text_color = color; +} void AOChatboxLabel::paintEvent(QPaintEvent *event) { - if (is_outlined) { + if (m_outline) + { QBrush brush; QPen pen; - QPointF baseline(outline_width, fontMetrics().height()); + QPointF baseline(m_outline_width, fontMetrics().height()); // Set up brush (base text) - brush.setColor(text_color); + brush.setColor(m_text_color); brush.setStyle(Qt::SolidPattern); // Set up outline - pen.setColor(outline_color); - pen.setWidthF(outline_width); + pen.setColor(m_outline_color); + pen.setWidthF(m_outline_width); QPainterPath path; path.addText(baseline, font(), text()); @@ -30,7 +53,8 @@ void AOChatboxLabel::paintEvent(QPaintEvent *event) painter.setBrush(brush); painter.drawPath(path); } - else { + else + { // Use the default renderer QLabel::paintEvent(event); } diff --git a/src/aotextboxwidgets.h b/src/aotextboxwidgets.h new file mode 100644 index 00000000..fa7288f8 --- /dev/null +++ b/src/aotextboxwidgets.h @@ -0,0 +1,32 @@ +#pragma once + +#include <QAbstractTextDocumentLayout> +#include <QDebug> +#include <QLabel> +#include <QPaintEvent> +#include <QPainter> +#include <QPainterPath> +#include <QTextEdit> + +class AOChatboxLabel : public QLabel +{ + Q_OBJECT + +public: + AOChatboxLabel(QWidget *parent); + + void setIsOutlined(bool outlined); + void setOutlineColor(QColor color); + void setOutlineWidth(int width); + + void setTextColor(QColor color); + +protected: + void paintEvent(QPaintEvent *event); + +private: + bool m_outline = false; + QColor m_outline_color; + int m_outline_width = 1; + QColor m_text_color; +}; diff --git a/src/aoutils.cpp b/src/aoutils.cpp index ee2e90b3..dd88a0a2 100644 --- a/src/aoutils.cpp +++ b/src/aoutils.cpp @@ -28,15 +28,15 @@ void AOUtils::migrateEffects(QSettings &p_effects_ini) p_effects_ini.endGroup(); const QStringList l_property_list{ - "sound", - "scaling", - "stretch", - "ignore_offset", - "under_chatbox", + "sound", + "scaling", + "stretch", + "ignore_offset", + "under_chatbox", }; const QMap<QString, QPair<QString, QString>> l_property_replacement_list{ - {"under_chatbox", {"layer", "character"}}, + {"under_chatbox", {"layer", "character"}}, }; QStringList l_key_list; @@ -65,9 +65,10 @@ void AOUtils::migrateEffects(QSettings &p_effects_ini) p_effects_ini.setValue("cull", true); p_effects_ini.setValue("layer", "character"); - if (i_effect_key == "realization") { - p_effects_ini.setValue("stretch", true); - p_effects_ini.setValue("layer", "chat"); + if (i_effect_key == "realization") + { + p_effects_ini.setValue("stretch", true); + p_effects_ini.setValue("layer", "chat"); } for (const QString &i_property : l_property_list) diff --git a/src/aoutils.h b/src/aoutils.h new file mode 100644 index 00000000..1fe03fd5 --- /dev/null +++ b/src/aoutils.h @@ -0,0 +1,12 @@ +#pragma once + +#include <QSettings> + +namespace AOUtils +{ +/** + * @brief Migrates the effects from the old format to version 2. + * @param QSettings object reference of the old effects.ini + */ +void migrateEffects(QSettings &p_fileName); +}; // namespace AOUtils diff --git a/src/charselect.cpp b/src/charselect.cpp index 443c1f20..57b4e76b 100644 --- a/src/charselect.cpp +++ b/src/charselect.cpp @@ -7,9 +7,9 @@ void Courtroom::construct_char_select() { - this->setWindowFlags( (this->windowFlags() | Qt::CustomizeWindowHint) & ~Qt::WindowMaximizeButtonHint); + this->setWindowFlags((this->windowFlags() | Qt::CustomizeWindowHint) & ~Qt::WindowMaximizeButtonHint); - ui_char_select_background = new AOImage(this, ao_app); + ui_char_select_background = new AOImage(ao_app, this); ui_char_select_background->setObjectName("ui_char_select_background"); ui_char_list = new QTreeWidget(ui_char_select_background); @@ -24,19 +24,19 @@ void Courtroom::construct_char_select() ui_char_buttons = new QWidget(ui_char_select_background); ui_char_buttons->setObjectName("ui_char_buttons"); - ui_back_to_lobby = new AOButton(ui_char_select_background, ao_app); + ui_back_to_lobby = new AOButton(ao_app, ui_char_select_background); ui_back_to_lobby->setObjectName("ui_back_to_lobby"); ui_char_password = new QLineEdit(ui_char_select_background); ui_char_password->setPlaceholderText(tr("Password")); ui_char_password->setObjectName("ui_char_password"); - ui_char_select_left = new AOButton(ui_char_select_background, ao_app); + ui_char_select_left = new AOButton(ao_app, ui_char_select_background); ui_char_select_left->setObjectName("ui_char_select_left"); - ui_char_select_right = new AOButton(ui_char_select_background, ao_app); + ui_char_select_right = new AOButton(ao_app, ui_char_select_background); ui_char_select_right->setObjectName("ui_char_select_right"); - ui_spectator = new AOButton(ui_char_select_background, ao_app); + ui_spectator = new AOButton(ao_app, ui_char_select_background); ui_spectator->setText(tr("Spectator")); ui_spectator->setObjectName("ui_spectator"); @@ -52,42 +52,36 @@ void Courtroom::construct_char_select() ui_char_taken->setText(tr("Taken")); ui_char_taken->setObjectName("ui_char_taken"); - connect(ui_char_list, &QTreeWidget::itemDoubleClicked, - this, &Courtroom::on_char_list_double_clicked); + connect(ui_char_list, &QTreeWidget::itemDoubleClicked, this, &Courtroom::on_char_list_double_clicked); - connect(ui_back_to_lobby, &AOButton::clicked, this, - &Courtroom::on_back_to_lobby_clicked); + connect(ui_back_to_lobby, &AOButton::clicked, this, &Courtroom::on_back_to_lobby_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_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, &AOButton::clicked, this, &Courtroom::on_spectator_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); - + 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); } void Courtroom::set_char_select() { QString filename = "courtroom_design.ini"; - pos_size_type f_charselect = - ao_app->get_element_dimensions("char_select", filename); + pos_size_type f_charselect = ao_app->get_element_dimensions("char_select", filename); - if (f_charselect.width < 0 || f_charselect.height < 0) { + if (f_charselect.width < 0 || f_charselect.height < 0) + { qWarning() << "did not find char_select width or height in " - "courtroom_design.ini!"; + "courtroom_design.ini!"; this->setFixedSize(714, 668); } else + { this->setFixedSize(f_charselect.width, f_charselect.height); + } ui_char_select_background->resize(f_charselect.width, f_charselect.height); ui_char_select_background->set_image("charselect_background"); @@ -122,7 +116,8 @@ void Courtroom::set_char_select_page() ui_char_select_left->hide(); ui_char_select_right->hide(); - for (AOCharButton *i_button : qAsConst(ui_char_button_list)) { + for (AOCharButton *i_button : qAsConst(ui_char_button_list)) + { i_button->reset(); i_button->hide(); i_button->move(0, 0); @@ -131,34 +126,40 @@ void Courtroom::set_char_select_page() int total_pages = ui_char_button_list_filtered.size() / max_chars_on_page; int chars_on_page = 0; - if (ui_char_button_list_filtered.size() % max_chars_on_page != 0) { + if (ui_char_button_list_filtered.size() % max_chars_on_page != 0) + { ++total_pages; // i. e. not on the last page if (total_pages > current_char_page + 1) + { chars_on_page = max_chars_on_page; + } else + { chars_on_page = ui_char_button_list_filtered.size() % max_chars_on_page; + } } else + { chars_on_page = max_chars_on_page; + } if (total_pages > current_char_page + 1) + { ui_char_select_right->show(); + } if (current_char_page > 0) + { ui_char_select_left->show(); + } - QPoint f_spacing = - ao_app->get_button_spacing("char_button_spacing", "courtroom_design.ini"); + QPoint f_spacing = ao_app->get_button_spacing("char_button_spacing", "courtroom_design.ini"); int s_button_size = button_width * Options::getInstance().themeScalingFactor(); - char_columns = - ((ui_char_buttons->width() - s_button_size) / (f_spacing.x() + s_button_size)) + - 1; - char_rows = ((ui_char_buttons->height() - s_button_size) / - (f_spacing.y() + s_button_size)) + - 1; + char_columns = ((ui_char_buttons->width() - s_button_size) / (f_spacing.x() + s_button_size)) + 1; + char_rows = ((ui_char_buttons->height() - s_button_size) / (f_spacing.y() + s_button_size)) + 1; max_chars_on_page = char_columns * char_rows; @@ -169,11 +170,13 @@ void Courtroom::on_char_list_double_clicked(QTreeWidgetItem *p_item, int column) { Q_UNUSED(column); int cid = p_item->text(1).toInt(); - if (cid == -1 && !p_item->isExpanded()) { + if (cid == -1 && !p_item->isExpanded()) + { p_item->setExpanded(true); return; } - else if (cid == -1) { + else if (cid == -1) + { p_item->setExpanded(false); return; } @@ -185,10 +188,10 @@ void Courtroom::char_clicked(int n_char) if (n_char != -1) { QString char_name = char_list.at(n_char).name; - QString char_ini_path = ao_app->get_real_path( - ao_app->get_character_path(char_name, "char.ini")); + QString char_ini_path = ao_app->get_real_path(ao_app->get_character_path(char_name, "char.ini")); - if (!file_exists(char_ini_path)) { + if (!file_exists(char_ini_path)) + { call_error(tr("Could not find character (char.ini) for %1").arg(char_name)); return; } @@ -196,14 +199,13 @@ void Courtroom::char_clicked(int n_char) qDebug() << "Found char.ini for" << char_name << "at" << char_ini_path; } - if (n_char != m_cid || n_char == -1) { - ao_app->send_server_packet( - new AOPacket("PW", {ui_char_password->text()})); - ao_app->send_server_packet( - new AOPacket("CC", {QString::number(ao_app->client_id), - QString::number(n_char), get_hdid()})); + if (n_char != m_cid || n_char == -1) + { + ao_app->send_server_packet(AOPacket("PW", {ui_char_password->text()})); + ao_app->send_server_packet(AOPacket("CC", {QString::number(ao_app->client_id), QString::number(n_char), get_hdid()})); } - if (n_char == m_cid || n_char == -1) { + if (n_char == m_cid || n_char == -1) + { update_character(n_char); enter_courtroom(); set_courtroom_size(); @@ -212,7 +214,7 @@ void Courtroom::char_clicked(int n_char) void Courtroom::on_char_button_context_menu_requested(const QPoint &pos) { - AOCharButton* button = qobject_cast<AOCharButton*>(sender()); + AOCharButton *button = qobject_cast<AOCharButton *>(sender()); int n_char = ui_char_button_list.indexOf(button); if (n_char == -1) { @@ -220,45 +222,44 @@ void Courtroom::on_char_button_context_menu_requested(const QPoint &pos) } QString char_name = char_list.at(n_char).name; - QString char_ini_path = ao_app->get_real_path( - ao_app->get_character_path(char_name, "char.ini")); + QString char_ini_path = ao_app->get_real_path(ao_app->get_character_path(char_name, "char.ini")); - if (!file_exists(char_ini_path)) { + if (!file_exists(char_ini_path)) + { call_error(tr("Could not find character (char.ini) for %1").arg(char_name)); return; } QMenu *menu = new QMenu(this); - menu->addAction(QString("Edit " + char_name + "/char.ini"), this, - [=] { QDesktopServices::openUrl(QUrl::fromLocalFile(char_ini_path)); } - ); + menu->addAction(QString("Edit " + char_name + "/char.ini"), this, [=] { QDesktopServices::openUrl(QUrl::fromLocalFile(char_ini_path)); }); menu->addSeparator(); - menu->addAction(QString("Open character folder " + char_name), this, - [=] { + menu->addAction(QString("Open character folder " + char_name), this, [=] { QString p_path = ao_app->get_real_path(VPath("characters/" + char_name + "/")); - if (!dir_exists(p_path)) { + if (!dir_exists(p_path)) + { return; } QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); - } - ); + }); menu->popup(button->mapToGlobal(pos)); } void Courtroom::put_button_in_place(int starting, int chars_on_this_page) { if (ui_char_button_list_filtered.size() == 0) + { return; + } - QPoint f_spacing = - ao_app->get_button_spacing("char_button_spacing", "courtroom_design.ini"); + QPoint f_spacing = ao_app->get_button_spacing("char_button_spacing", "courtroom_design.ini"); int x_mod_count = 0; int y_mod_count = 0; int startout = starting; int size = button_width * Options::getInstance().themeScalingFactor(); - for (int n = starting; n < startout + chars_on_this_page; ++n) { + for (int n = starting; n < startout + chars_on_this_page; ++n) + { int x_pos = (size + f_spacing.x()) * x_mod_count; int y_pos = (size + f_spacing.y()) * y_mod_count; @@ -268,7 +269,8 @@ void Courtroom::put_button_in_place(int starting, int chars_on_this_page) ++x_mod_count; - if (x_mod_count == char_columns) { + if (x_mod_count == char_columns) + { ++y_mod_count; x_mod_count = 0; } @@ -279,8 +281,10 @@ void Courtroom::character_loading_finished() { // Zeroeth, we'll clear any leftover characters from previous server visits. ao_app->generated_chars = 0; - if (ui_char_button_list.size() > 0) { - foreach (AOCharButton *item, ui_char_button_list) { + if (ui_char_button_list.size() > 0) + { + foreach (AOCharButton *item, ui_char_button_list) + { delete item; } ui_char_button_list.clear(); @@ -290,9 +294,9 @@ void Courtroom::character_loading_finished() // First, we'll make all the character buttons in the very beginning. // We also hide them all, so they can't be accidentally clicked. // Later on, we'll be revealing buttons as we need them. - for (int n = 0; n < char_list.size(); n++) { - AOCharButton *char_button = - new AOCharButton(ui_char_buttons, ao_app, 0, 0, char_list.at(n).taken); + for (int n = 0; n < char_list.size(); n++) + { + AOCharButton *char_button = new AOCharButton(ao_app, 0, 0, char_list.at(n).taken, ui_char_buttons); char_button->setContextMenuPolicy(Qt::CustomContextMenu); char_button->reset(); char_button->hide(); @@ -300,24 +304,25 @@ void Courtroom::character_loading_finished() char_button->setToolTip(char_list.at(n).name); ui_char_button_list.append(char_button); QString char_category = ao_app->get_category(char_list.at(n).name); - QList<QTreeWidgetItem*> matching_list = ui_char_list->findItems(char_category, Qt::MatchFixedString, 0); + QList<QTreeWidgetItem *> matching_list = ui_char_list->findItems(char_category, Qt::MatchFixedString, 0); // create the character tree item QTreeWidgetItem *treeItem = new QTreeWidgetItem(); treeItem->setText(0, char_list.at(n).name); - treeItem->setIcon( - 0, QIcon(ao_app->get_image_suffix( - ao_app->get_character_path(char_list.at(n).name, "char_icon"), - true))); + treeItem->setIcon(0, QIcon(ao_app->get_image_suffix(ao_app->get_character_path(char_list.at(n).name, "char_icon"), true))); treeItem->setText(1, QString::number(n)); // category logic QTreeWidgetItem *category; if (char_category == "") // no category + { ui_char_list->addTopLevelItem(treeItem); - else if (!matching_list.isEmpty()) { // our category already exists + } + else if (!matching_list.isEmpty()) + { // our category already exists category = matching_list[0]; category->addChild(treeItem); } - else { // we need to make a new category + else + { // we need to make a new category category = new QTreeWidgetItem(); category->setText(0, char_category); category->setText(1, "-1"); @@ -327,14 +332,14 @@ void Courtroom::character_loading_finished() } ui_char_list->sortItems(0, Qt::AscendingOrder); - - connect(char_button, &AOCharButton::clicked, - [this, n]() { this->char_clicked(n); }); + + connect(char_button, &AOCharButton::clicked, this, [this, n]() { this->char_clicked(n); }); connect(char_button, &AOCharButton::customContextMenuRequested, this, &Courtroom::on_char_button_context_menu_requested); // This part here serves as a way of showing to the player that the game is // still running, it is just loading the pictures of the characters. - if (ao_app->lobby_constructed) { + if (ao_app->lobby_constructed) + { ao_app->generated_chars++; } } @@ -344,27 +349,27 @@ void Courtroom::character_loading_finished() void Courtroom::filter_character_list() { ui_char_button_list_filtered.clear(); - for (int i = 0; i < char_list.size(); i++) { + for (int i = 0; i < char_list.size(); i++) + { AOCharButton *current_char = ui_char_button_list.at(i); - QTreeWidgetItem* current_char_list_item = ui_char_list->findItems(QString::number(i), Qt::MatchExactly | Qt::MatchRecursive, 1)[0]; - - + QTreeWidgetItem *current_char_list_item = ui_char_list->findItems(QString::number(i), Qt::MatchExactly | Qt::MatchRecursive, 1)[0]; // It seems passwording characters is unimplemented yet? // Until then, this will stay here, I suppose. // if (ui_char_passworded->isChecked() && character_is_passworded??) // continue; - if (!ui_char_taken->isChecked() && char_list.at(i).taken) { + if (!ui_char_taken->isChecked() && char_list.at(i).taken) + { current_char_list_item->setHidden(true); continue; } - if (!char_list.at(i).name.contains(ui_char_search->text(), - Qt::CaseInsensitive)) { + if (!char_list.at(i).name.contains(ui_char_search->text(), Qt::CaseInsensitive)) + { current_char_list_item->setHidden(true); continue; - } + } // We only really need to update the fact that a character is taken // for the buttons that actually appear. @@ -376,7 +381,9 @@ void Courtroom::filter_character_list() // reset disabled current_char_list_item->setDisabled(false); if (char_list.at(i).taken) // woops, we are taken + { current_char_list_item->setDisabled(true); + } ui_char_button_list_filtered.append(current_char); } @@ -385,8 +392,17 @@ void Courtroom::filter_character_list() set_char_select_page(); } -void Courtroom::on_char_search_changed() { filter_character_list(); } +void Courtroom::on_char_search_changed() +{ + filter_character_list(); +} -void Courtroom::on_char_passworded_clicked() { filter_character_list(); } +void Courtroom::on_char_passworded_clicked() +{ + filter_character_list(); +} -void Courtroom::on_char_taken_clicked() { filter_character_list(); } +void Courtroom::on_char_taken_clicked() +{ + filter_character_list(); +} diff --git a/src/chatlogpiece.cpp b/src/chatlogpiece.cpp index 64ffefe8..662dc0d2 100644 --- a/src/chatlogpiece.cpp +++ b/src/chatlogpiece.cpp @@ -1,17 +1,15 @@ #include "chatlogpiece.h" -chatlogpiece::chatlogpiece() +ChatLogPiece::ChatLogPiece() { name = tr("UNKNOWN"); showname = tr("UNKNOWN"); message = tr("UNKNOWN"); color = 0; - action = ""; datetime = QDateTime::currentDateTimeUtc(); } -chatlogpiece::chatlogpiece(QString p_name, QString p_showname, - QString p_message, QString p_action, int p_color, bool p_selfname) +ChatLogPiece::ChatLogPiece(QString p_name, QString p_showname, QString p_message, QString p_action, int p_color, bool p_selfname) { name = p_name; showname = p_showname; @@ -22,9 +20,7 @@ chatlogpiece::chatlogpiece(QString p_name, QString p_showname, datetime = QDateTime::currentDateTimeUtc(); } -chatlogpiece::chatlogpiece(QString p_name, QString p_showname, - QString p_message, QString p_action, int p_color, bool p_selfname, - QDateTime p_datetime) +ChatLogPiece::ChatLogPiece(QString p_name, QString p_showname, QString p_message, QString p_action, int p_color, bool p_selfname, QDateTime p_datetime) { name = p_name; showname = p_showname; @@ -35,23 +31,30 @@ chatlogpiece::chatlogpiece(QString p_name, QString p_showname, datetime = p_datetime.toUTC(); } -QString chatlogpiece::get_full() +QString ChatLogPiece::get_datetime_as_string() +{ + return datetime.toString(); +} + +QString ChatLogPiece::get_full() { QString full = "["; full.append(get_datetime_as_string()); full.append("] "); - full.append(get_showname()); - if (get_showname() != get_name()) + full.append(showname); + if (showname != name) { full.append(" ("); - full.append(get_name()); + full.append(name); full.append(")"); } - if (!get_action().isEmpty()) - full.append(" " + get_action()); + if (!action.isEmpty()) + { + full.append(" " + action); + } full.append(": "); - full.append(get_message()); + full.append(message); return full; } diff --git a/src/chatlogpiece.h b/src/chatlogpiece.h new file mode 100644 index 00000000..3750ff91 --- /dev/null +++ b/src/chatlogpiece.h @@ -0,0 +1,26 @@ +#pragma once + +#include <QDateTime> +#include <QString> +#include <QtWidgets/QApplication> + +class ChatLogPiece +{ + Q_DECLARE_TR_FUNCTIONS(chatlogpiece) + +public: + ChatLogPiece(); + ChatLogPiece(QString p_name, QString p_showname, QString p_message, QString p_action, int color, bool selfname); + ChatLogPiece(QString p_name, QString p_showname, QString p_message, QString p_action, int color, bool selfname, QDateTime p_datetime); + + QString name; + QString showname; + QString message; + QString action; + bool selfname = false; + QDateTime datetime; + int color = 0; + + QString get_datetime_as_string(); + QString get_full(); +}; diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 3056fd92..326f2ad0 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1,12 +1,12 @@ #include "courtroom.h" #include "options.h" -Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() +Courtroom::Courtroom(AOApplication *p_ao_app) + : QMainWindow() { ao_app = p_ao_app; - this->setWindowFlags((this->windowFlags() | Qt::CustomizeWindowHint) & - ~Qt::WindowMaximizeButtonHint); + this->setWindowFlags((this->windowFlags() | Qt::CustomizeWindowHint) & ~Qt::WindowMaximizeButtonHint); ao_app->initBASS(); #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) // Needed for pre-5.10 RNG stuff @@ -27,54 +27,53 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() sfx_delay_timer = new QTimer(this); sfx_delay_timer->setSingleShot(true); - music_player = new AOMusicPlayer(this, ao_app); + music_player = new AOMusicPlayer(ao_app); music_player->set_muted(true); - connect(&music_player->music_watcher, &QFutureWatcher<QString>::finished, - this, &Courtroom::update_ui_music_name, Qt::QueuedConnection); + connect(&music_player->music_watcher, &QFutureWatcher<QString>::finished, this, &Courtroom::update_ui_music_name, Qt::QueuedConnection); - sfx_player = new AOSfxPlayer(this, ao_app); + sfx_player = new AOSfxPlayer(ao_app); sfx_player->set_muted(true); - objection_player = new AOSfxPlayer(this, ao_app); + objection_player = new AOSfxPlayer(ao_app); objection_player->set_muted(true); - blip_player = new AOBlipPlayer(this, ao_app); + blip_player = new AOBlipPlayer(ao_app); blip_player->set_muted(true); - modcall_player = new AOSfxPlayer(this, ao_app); + modcall_player = new AOSfxPlayer(ao_app); modcall_player->set_volume(50); - ui_background = new AOImage(this, ao_app); + ui_background = new AOImage(ao_app, this); ui_background->setObjectName("ui_background"); ui_viewport = new QWidget(this); ui_viewport->setObjectName("ui_viewport"); - ui_vp_background = new BackgroundLayer(ui_viewport, ao_app); + ui_vp_background = new BackgroundLayer(ao_app, ui_viewport); ui_vp_background->setObjectName("ui_vp_background"); - ui_vp_speedlines = new SplashLayer(ui_viewport, ao_app); + ui_vp_speedlines = new SplashLayer(ao_app, ui_viewport); ui_vp_speedlines->setObjectName("ui_vp_speedlines"); ui_vp_speedlines->stretch = true; - ui_vp_player_char = new CharLayer(ui_viewport, ao_app); + ui_vp_player_char = new CharLayer(ao_app, ui_viewport); ui_vp_player_char->setObjectName("ui_vp_player_char"); ui_vp_player_char->masked = false; - ui_vp_sideplayer_char = new CharLayer(ui_viewport, ao_app); + ui_vp_sideplayer_char = new CharLayer(ao_app, ui_viewport); ui_vp_sideplayer_char->setObjectName("ui_vp_sideplayer_char"); ui_vp_sideplayer_char->masked = false; ui_vp_sideplayer_char->hide(); - ui_vp_desk = new BackgroundLayer(ui_viewport, ao_app); + ui_vp_desk = new BackgroundLayer(ao_app, ui_viewport); ui_vp_desk->setObjectName("ui_vp_desk"); - ui_vp_effect = new EffectLayer(this, ao_app); + ui_vp_effect = new EffectLayer(ao_app, this); ui_vp_effect->setAttribute(Qt::WA_TransparentForMouseEvents); ui_vp_effect->setObjectName("ui_vp_effect"); - ui_vp_evidence_display = new AOEvidenceDisplay(ui_viewport, ao_app); + ui_vp_evidence_display = new AOEvidenceDisplay(ao_app, ui_viewport); ui_vp_evidence_display->setObjectName("ui_vp_evidence_display"); - ui_vp_chatbox = new AOImage(this, ao_app); + ui_vp_chatbox = new AOImage(ao_app, this); ui_vp_chatbox->setObjectName("ui_vp_chatbox"); - ui_vp_sticker = new StickerLayer(this, ao_app); + ui_vp_sticker = new StickerLayer(ao_app, this); ui_vp_sticker->set_play_once(false); ui_vp_sticker->set_cull_image(false); ui_vp_sticker->setAttribute(Qt::WA_TransparentForMouseEvents); @@ -83,7 +82,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_vp_showname = new AOChatboxLabel(ui_vp_chatbox); ui_vp_showname->setObjectName("ui_vp_showname"); ui_vp_showname->setAlignment(Qt::AlignLeft); - ui_vp_chat_arrow = new InterfaceLayer(this, ao_app); + ui_vp_chat_arrow = new InterfaceLayer(ao_app, this); ui_vp_chat_arrow->set_play_once(false); ui_vp_chat_arrow->set_cull_image(false); ui_vp_chat_arrow->setObjectName("ui_vp_chat_arrow"); @@ -95,17 +94,17 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_vp_message->setReadOnly(true); ui_vp_message->setObjectName("ui_vp_message"); - ui_vp_testimony = new SplashLayer(this, ao_app); + ui_vp_testimony = new SplashLayer(ao_app, this); ui_vp_testimony->set_play_once(false); ui_vp_testimony->setAttribute(Qt::WA_TransparentForMouseEvents); ui_vp_testimony->setObjectName("ui_vp_testimony"); - ui_vp_wtce = new SplashLayer(this, ao_app); + ui_vp_wtce = new SplashLayer(ao_app, this); ui_vp_wtce->set_play_once(true); ui_vp_wtce->continuous = false; ui_vp_wtce->force_continuous = true; ui_vp_wtce->setAttribute(Qt::WA_TransparentForMouseEvents); ui_vp_wtce->setObjectName("ui_vp_wtce"); - ui_vp_objection = new SplashLayer(this, ao_app); + ui_vp_objection = new SplashLayer(ao_app, this); ui_vp_objection->set_play_once(true); ui_vp_objection->continuous = false; ui_vp_objection->force_continuous = true; @@ -124,13 +123,12 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() log_timestamp = Options::getInstance().logTimestampEnabled(); log_timestamp_format = Options::getInstance().logTimestampFormat(); - ui_debug_log = new AOTextArea(this, Options::getInstance().maxLogSize()); + ui_debug_log = new AOTextArea(Options::getInstance().maxLogSize(), this); ui_debug_log->setReadOnly(true); ui_debug_log->setOpenExternalLinks(true); ui_debug_log->hide(); ui_debug_log->setObjectName("ui_debug_log"); - connect(ao_app, &AOApplication::qt_log_message, - this, &Courtroom::debug_message_handler); + connect(ao_app, &AOApplication::qt_log_message, this, &Courtroom::debug_message_handler); ui_server_chatlog = new AOTextArea(this); ui_server_chatlog->setReadOnly(true); @@ -156,7 +154,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_music_list->setUniformRowHeights(true); ui_music_list->setObjectName("ui_music_list"); - ui_music_display = new InterfaceLayer(this, ao_app); + ui_music_display = new InterfaceLayer(ao_app, this); ui_music_display->set_play_once(false); ui_music_display->set_cull_image(false); ui_music_display->transform_mode = Qt::SmoothTransformation; @@ -168,7 +166,8 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_music_name->setAttribute(Qt::WA_TransparentForMouseEvents); ui_music_name->setObjectName("ui_music_name"); - for (int i = 0; i < max_clocks; i++) { + for (int i = 0; i < max_clocks; i++) + { ui_clock[i] = new AOClockLabel(this); ui_clock[i]->setAttribute(Qt::WA_TransparentForMouseEvents); ui_clock[i]->hide(); @@ -189,7 +188,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_ic_chat_message->installEventFilter(ui_ic_chat_message_filter); ui_ic_chat_message->setObjectName("ui_ic_chat_message"); - ui_muted = new AOImage(ui_ic_chat_message, ao_app); + ui_muted = new AOImage(ao_app, ui_ic_chat_message); ui_muted->hide(); ui_muted->setObjectName("ui_muted"); @@ -217,7 +216,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_pos_dropdown->view()->setTextElideMode(Qt::ElideLeft); ui_pos_dropdown->setObjectName("ui_pos_dropdown"); - ui_pos_remove = new AOButton(this, ao_app); + ui_pos_remove = new AOButton(ao_app, this); ui_pos_remove->setObjectName("ui_pos_remove"); ui_iniswap_dropdown = new QComboBox(this); @@ -225,7 +224,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_iniswap_dropdown->view()->setTextElideMode(Qt::ElideLeft); ui_iniswap_dropdown->setObjectName("ui_iniswap_dropdown"); - ui_iniswap_remove = new AOButton(this, ao_app); + ui_iniswap_remove = new AOButton(ao_app, this); ui_iniswap_remove->setObjectName("ui_iniswap_remove"); ui_sfx_dropdown = new QComboBox(this); @@ -233,7 +232,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_sfx_dropdown->view()->setTextElideMode(Qt::ElideLeft); ui_sfx_dropdown->setObjectName("ui_sfx_dropdown"); - ui_sfx_remove = new AOButton(this, ao_app); + ui_sfx_remove = new AOButton(ao_app, this); ui_sfx_remove->setObjectName("ui_sfx_remove"); ui_effects_dropdown = new QComboBox(this); @@ -241,10 +240,10 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_effects_dropdown->setContextMenuPolicy(Qt::CustomContextMenu); ui_effects_dropdown->setObjectName("ui_effects_dropdown"); - ui_defense_bar = new AOImage(this, ao_app); + ui_defense_bar = new AOImage(ao_app, this); ui_defense_bar->setObjectName("ui_defense_bar"); - ui_prosecution_bar = new AOImage(this, ao_app); + ui_prosecution_bar = new AOImage(ao_app, this); ui_prosecution_bar->setObjectName("ui_prosecution_bar"); ui_music_label = new QLabel(this); @@ -256,43 +255,43 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_blip_label = new QLabel(this); ui_blip_label->setObjectName("ui_blip_label"); - ui_hold_it = new AOButton(this, ao_app); + ui_hold_it = new AOButton(ao_app, this); ui_hold_it->setObjectName("ui_hold_it"); - ui_objection = new AOButton(this, ao_app); + ui_objection = new AOButton(ao_app, this); ui_objection->setObjectName("ui_objection"); - ui_take_that = new AOButton(this, ao_app); + ui_take_that = new AOButton(ao_app, this); ui_take_that->setObjectName("ui_take_that"); - ui_ooc_toggle = new AOButton(this, ao_app); + ui_ooc_toggle = new AOButton(ao_app, this); ui_ooc_toggle->setObjectName("ui_ooc_toggle"); - ui_witness_testimony = new AOButton(this, ao_app); + ui_witness_testimony = new AOButton(ao_app, this); ui_witness_testimony->setObjectName("ui_witness_testimony"); - ui_cross_examination = new AOButton(this, ao_app); + ui_cross_examination = new AOButton(ao_app, this); ui_cross_examination->setObjectName("ui_cross_examination"); - ui_guilty = new AOButton(this, ao_app); + ui_guilty = new AOButton(ao_app, this); ui_guilty->setObjectName("ui_guilty"); - ui_not_guilty = new AOButton(this, ao_app); + ui_not_guilty = new AOButton(ao_app, this); ui_not_guilty->setObjectName("ui_not_guilty"); - ui_change_character = new AOButton(this, ao_app); + ui_change_character = new AOButton(ao_app, this); ui_change_character->setObjectName("ui_change_character"); - ui_reload_theme = new AOButton(this, ao_app); + ui_reload_theme = new AOButton(ao_app, this); ui_reload_theme->setObjectName("ui_reload_theme"); - ui_call_mod = new AOButton(this, ao_app); + ui_call_mod = new AOButton(ao_app, this); ui_call_mod->setObjectName("ui_call_mod"); - ui_settings = new AOButton(this, ao_app); + ui_settings = new AOButton(ao_app, this); ui_settings->setObjectName("ui_settings"); - ui_switch_area_music = new AOButton(this, ao_app); + ui_switch_area_music = new AOButton(ao_app, this); ui_switch_area_music->setObjectName("ui_switch_area_music"); ui_pre = new QCheckBox(this); @@ -324,32 +323,32 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_immediate->hide(); ui_immediate->setObjectName("ui_immediate"); - ui_custom_objection = new AOButton(this, ao_app); + ui_custom_objection = new AOButton(ao_app, this); ui_custom_objection->setContextMenuPolicy(Qt::CustomContextMenu); ui_custom_objection->setObjectName("ui_custom_objection"); custom_obj_menu = new QMenu(this); custom_obj_menu->setObjectName("ui_custom_obj_menu"); - ui_realization = new AOButton(this, ao_app); + ui_realization = new AOButton(ao_app, this); ui_realization->setObjectName("ui_realization"); - ui_screenshake = new AOButton(this, ao_app); + ui_screenshake = new AOButton(ao_app, this); ui_screenshake->setObjectName("ui_screenshake"); - ui_mute = new AOButton(this, ao_app); + ui_mute = new AOButton(ao_app, this); ui_mute->setObjectName("ui_mute"); - ui_defense_plus = new AOButton(this, ao_app); + ui_defense_plus = new AOButton(ao_app, this); ui_defense_plus->setObjectName("ui_defense_plus"); - ui_defense_minus = new AOButton(this, ao_app); + ui_defense_minus = new AOButton(ao_app, this); ui_defense_minus->setObjectName("ui_defense_minus"); - ui_prosecution_plus = new AOButton(this, ao_app); + ui_prosecution_plus = new AOButton(ao_app, this); ui_prosecution_plus->setObjectName("ui_prosecution_plus"); - ui_prosecution_minus = new AOButton(this, ao_app); + ui_prosecution_minus = new AOButton(ao_app, this); ui_prosecution_minus->setObjectName("ui_prosecution_minus"); ui_text_color = new QComboBox(this); @@ -392,10 +391,10 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_pair_order_dropdown->addItem(tr("To behind")); ui_pair_order_dropdown->setObjectName("ui_pair_order_dropdown"); - ui_pair_button = new AOButton(this, ao_app); + ui_pair_button = new AOButton(ao_app, this); ui_pair_button->setObjectName("ui_pair_button"); - ui_evidence_button = new AOButton(this, ao_app); + ui_evidence_button = new AOButton(ao_app, this); ui_evidence_button->setContextMenuPolicy(Qt::CustomContextMenu); ui_evidence_button->setObjectName("ui_evidence_button"); @@ -414,152 +413,100 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() 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(ui_vp_player_char, &CharLayer::play_sfx, this, &Courtroom::play_char_sfx); - connect(text_delay_timer, &QTimer::timeout, this, - &Courtroom::start_chat_ticking); + connect(text_delay_timer, &QTimer::timeout, this, &Courtroom::start_chat_ticking); - connect(text_queue_timer, &QTimer::timeout, this, - &Courtroom::chatmessage_dequeue); + connect(text_queue_timer, &QTimer::timeout, this, &Courtroom::chatmessage_dequeue); connect(sfx_delay_timer, &QTimer::timeout, this, &Courtroom::play_sfx); connect(chat_tick_timer, &QTimer::timeout, this, &Courtroom::chat_tick); - connect(ui_pos_dropdown, QOverload<int>::of(&QComboBox::currentIndexChanged), this, - QOverload<int>::of(&Courtroom::on_pos_dropdown_changed)); - connect(ui_pos_dropdown, &QComboBox::editTextChanged, this, - QOverload<QString>::of(&Courtroom::on_pos_dropdown_changed)); - connect(ui_pos_dropdown, &QComboBox::customContextMenuRequested, this, - &Courtroom::on_pos_dropdown_context_menu_requested); + connect(ui_pos_dropdown, QOverload<int>::of(&QComboBox::currentIndexChanged), this, QOverload<int>::of(&Courtroom::on_pos_dropdown_changed)); + connect(ui_pos_dropdown, &QComboBox::editTextChanged, this, QOverload<QString>::of(&Courtroom::on_pos_dropdown_changed)); + connect(ui_pos_dropdown, &QComboBox::customContextMenuRequested, this, &Courtroom::on_pos_dropdown_context_menu_requested); connect(ui_pos_remove, &AOButton::clicked, this, &Courtroom::on_pos_remove_clicked); - connect(ui_iniswap_dropdown, QOverload<int>::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, QOverload<int>::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, QOverload<int>::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, &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, &QLineEdit::returnPressed, this, - &Courtroom::on_chat_return_pressed); - - connect(ui_ooc_chat_message, &QLineEdit::returnPressed, this, - &Courtroom::on_ooc_return_pressed); - - 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, &QTreeWidget::itemDoubleClicked, this, - &Courtroom::on_area_list_double_clicked); + connect(ui_iniswap_dropdown, QOverload<int>::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, QOverload<int>::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, QOverload<int>::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, &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, &QLineEdit::returnPressed, this, &Courtroom::on_chat_return_pressed); + + connect(ui_ooc_chat_message, &QLineEdit::returnPressed, this, &Courtroom::on_ooc_return_pressed); + + 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, &QTreeWidget::itemDoubleClicked, this, &Courtroom::on_area_list_double_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, - &AOButton::customContextMenuRequested, this, - &Courtroom::show_custom_objection_menu); + connect(ui_custom_objection, &AOButton::clicked, this, &Courtroom::on_custom_objection_clicked); + connect(ui_custom_objection, &AOButton::customContextMenuRequested, this, &Courtroom::show_custom_objection_menu); - connect(ui_realization, &AOButton::clicked, this, - &Courtroom::on_realization_clicked); - connect(ui_screenshake, &AOButton::clicked, this, - &Courtroom::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, &AOButton::clicked, this, &Courtroom::on_mute_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, QOverload<int>::of(&QComboBox::currentIndexChanged), this, - &Courtroom::on_text_color_changed); - connect(ui_text_color, &QComboBox::customContextMenuRequested, this, - &Courtroom::on_text_color_context_menu_requested); - - 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, &AOButton::clicked, this, - &Courtroom::on_ooc_toggle_clicked); - - connect(ui_music_search, &QLineEdit::textChanged, this, - &Courtroom::on_music_search_edited); - - 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_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, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &Courtroom::on_text_color_changed); + connect(ui_text_color, &QComboBox::customContextMenuRequested, this, &Courtroom::on_text_color_context_menu_requested); + + 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, &AOButton::clicked, this, &Courtroom::on_ooc_toggle_clicked); + + connect(ui_music_search, &QLineEdit::textChanged, this, &Courtroom::on_music_search_edited); + + 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_not_guilty, &AOButton::clicked, this, &Courtroom::on_not_guilty_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_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_switch_area_music, &AOButton::clicked, this, - &Courtroom::on_switch_area_music_clicked); + connect(ui_switch_area_music, &AOButton::clicked, this, &Courtroom::on_switch_area_music_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_showname_enable, &AOButton::clicked, this, - &Courtroom::on_showname_enable_clicked); + connect(ui_showname_enable, &AOButton::clicked, this, &Courtroom::on_showname_enable_clicked); 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<int>::of(&QSpinBox::valueChanged), this, - &Courtroom::on_pair_offset_changed); - connect(ui_pair_vert_offset_spinbox, QOverload<int>::of(&QSpinBox::valueChanged), this, - &Courtroom::on_pair_vert_offset_changed); - connect(ui_pair_order_dropdown, QOverload<int>::of(&QComboBox::currentIndexChanged), this, - &Courtroom::on_pair_order_dropdown_changed); - - connect(ui_evidence_button, &AOButton::clicked, this, - &Courtroom::on_evidence_button_clicked); - connect(ui_evidence_button, &QComboBox::customContextMenuRequested, this, - &Courtroom::on_evidence_context_menu_requested); - - connect(qApp, QOverload<Qt::ApplicationState>::of(&QApplication::applicationStateChanged), this, - &Courtroom::on_application_state_changed); + connect(ui_pair_list, &QListWidget::clicked, this, &Courtroom::on_pair_list_clicked); + connect(ui_pair_offset_spinbox, QOverload<int>::of(&QSpinBox::valueChanged), this, &Courtroom::on_pair_offset_changed); + connect(ui_pair_vert_offset_spinbox, QOverload<int>::of(&QSpinBox::valueChanged), this, &Courtroom::on_pair_vert_offset_changed); + connect(ui_pair_order_dropdown, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &Courtroom::on_pair_order_dropdown_changed); + + connect(ui_evidence_button, &AOButton::clicked, this, &Courtroom::on_evidence_button_clicked); + connect(ui_evidence_button, &QComboBox::customContextMenuRequested, this, &Courtroom::on_evidence_context_menu_requested); + + connect(qApp, QOverload<Qt::ApplicationState>::of(&QApplication::applicationStateChanged), this, &Courtroom::on_application_state_changed); connect(ui_vp_evidence_display, &AOEvidenceDisplay::show_evidence_details, this, &Courtroom::show_evidence); @@ -568,11 +515,25 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() set_char_select(); } +Courtroom::~Courtroom() +{ + // save sound settings + Options::getInstance().setMusicVolume(ui_music_slider->value()); + Options::getInstance().setSfxVolume(ui_sfx_slider->value()); + Options::getInstance().setBlipVolume(ui_blip_slider->value()); + + delete music_player; + delete sfx_player; + delete objection_player; + delete blip_player; +} + void Courtroom::on_application_state_changed(Qt::ApplicationState state) { // Unsuppressed suppress_audio = 0; - if (state != Qt::ApplicationActive) { + if (state != Qt::ApplicationActive) + { // Suppressed audio setting suppress_audio = Options::getInstance().defaultSuppressAudio(); } @@ -583,13 +544,18 @@ void Courtroom::update_audio_volume() { float remaining_percent = 1.0f - static_cast<float>(suppress_audio / 100.0f); if (remaining_percent > 1) + { remaining_percent = 1; + } if (remaining_percent < 0) + { remaining_percent = 0; + } music_player->set_volume(ui_music_slider->value() * remaining_percent, 0); // set music // Set the ambience and other misc. music layers - for (int i = 1; i < music_player->m_channelmax; ++i) { + for (int i = 1; i < music_player->CHANNEL_COUNT; ++i) + { music_player->set_volume(ui_sfx_slider->value() * remaining_percent, i); } sfx_player->set_volume(ui_sfx_slider->value() * remaining_percent); @@ -597,18 +563,107 @@ void Courtroom::update_audio_volume() blip_player->set_volume(ui_blip_slider->value() * remaining_percent); } +void Courtroom::append_char(char_type p_char) +{ + char_list.append(p_char); +} + +void Courtroom::append_music(QString f_music) +{ + music_list.append(f_music); +} + +void Courtroom::append_area(QString f_area) +{ + area_list.append(f_area); +} + +void Courtroom::clear_chars() +{ + char_list.clear(); +} + +void Courtroom::clear_music() +{ + music_list.clear(); +} + +void Courtroom::clear_areas() +{ + area_list.clear(); +} + +void Courtroom::fix_last_area() +{ + if (area_list.size() > 0) + { + QString malplaced = area_list.last(); + area_list.removeLast(); + append_music(malplaced); + } +} + +void Courtroom::arup_append(int players, QString status, QString cm, QString locked) +{ + arup_players.append(players); + arup_statuses.append(status); + arup_cms.append(cm); + arup_locks.append(locked); +} + +void Courtroom::arup_clear() +{ + arup_players.clear(); + arup_statuses.clear(); + arup_cms.clear(); + arup_locks.clear(); +} + +void Courtroom::arup_modify(int type, int place, QString value) +{ + if (type == 0) + { + if (arup_players.size() > place) + { + arup_players[place] = value.toInt(); + } + } + else if (type == 1) + { + if (arup_statuses.size() > place) + { + arup_statuses[place] = value; + } + } + else if (type == 2) + { + if (arup_cms.size() > place) + { + arup_cms[place] = value; + } + } + else if (type == 3) + { + if (arup_locks.size() > place) + { + arup_locks[place] = value; + } + } +} + void Courtroom::set_courtroom_size() { QString filename = "courtroom_design.ini"; - pos_size_type f_courtroom = - ao_app->get_element_dimensions("courtroom", filename); + pos_size_type f_courtroom = ao_app->get_element_dimensions("courtroom", filename); - if (f_courtroom.width < 0 || f_courtroom.height < 0) { + if (f_courtroom.width < 0 || f_courtroom.height < 0) + { qWarning() << "did not find courtroom width or height in " << filename; this->setFixedSize(714, 668); } - else { + else + { m_courtroom_width = f_courtroom.width; m_courtroom_height = f_courtroom.height; @@ -624,18 +679,22 @@ void Courtroom::set_mute_list() mute_map.clear(); // maps which characters are muted based on cid, none are muted by default - for (int n_cid = 0; n_cid < char_list.size(); n_cid++) { + for (int n_cid = 0; n_cid < char_list.size(); n_cid++) + { mute_map.insert(n_cid, false); } QStringList sorted_mute_list; for (const char_type &i_char : qAsConst(char_list)) + { sorted_mute_list.append(i_char.name); + } sorted_mute_list.sort(); - for (const 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); } @@ -646,11 +705,14 @@ void Courtroom::set_pair_list() QStringList sorted_pair_list; for (const char_type &i_char : qAsConst(char_list)) + { sorted_pair_list.append(i_char.name); + } sorted_pair_list.sort(); - for (const QString &i_name : sorted_pair_list) { + for (const QString &i_name : sorted_pair_list) + { ui_pair_list->addItem(i_name); } } @@ -665,14 +727,16 @@ void Courtroom::set_widgets() // If there is a point to it, show all CCCC features. // We also do this this soon so that set_size_and_pos can hide them all later, // if needed. - if (ao_app->cccc_ic_supported) { + if (ao_app->cccc_ic_supported) + { ui_pair_button->show(); ui_immediate->show(); ui_showname_enable->show(); ui_ic_chat_name->show(); ui_ic_chat_name->setEnabled(true); } - else { + else + { ui_pair_button->hide(); ui_immediate->hide(); ui_showname_enable->hide(); @@ -699,16 +763,14 @@ void Courtroom::set_widgets() ui_vp_player_char->combo_resize(ui_viewport->width(), ui_viewport->height()); ui_vp_sideplayer_char->move_and_center(0, 0); - ui_vp_sideplayer_char->combo_resize(ui_viewport->width(), - ui_viewport->height()); + ui_vp_sideplayer_char->combo_resize(ui_viewport->width(), ui_viewport->height()); // the AO2 desk element ui_vp_desk->move_and_center(0, 0); ui_vp_desk->combo_resize(ui_viewport->width(), ui_viewport->height()); ui_vp_evidence_display->move(0, 0); - ui_vp_evidence_display->combo_resize(ui_viewport->width(), - ui_viewport->height()); + ui_vp_evidence_display->combo_resize(ui_viewport->width(), ui_viewport->height()); // layering shenanigans with ui_vp_chatbox prevent us from doing the sensible // thing, which is to parent these to ui_viewport. instead, AOLayer handles @@ -728,26 +790,21 @@ void Courtroom::set_widgets() log_maximum_blocks = Options::getInstance().maxLogSize(); - bool regenerate = log_goes_downwards != Options::getInstance().logDirectionDownwards() || - log_colors != Options::getInstance().colorLogEnabled() || - log_newline != Options::getInstance().logNewline() || - log_margin != Options::getInstance().logMargin() || - log_timestamp != Options::getInstance().logTimestampEnabled() || - log_timestamp_format != Options::getInstance().logTimestampFormat(); + bool regenerate = log_goes_downwards != Options::getInstance().logDirectionDownwards() || log_colors != Options::getInstance().colorLogEnabled() || log_newline != Options::getInstance().logNewline() || log_margin != Options::getInstance().logMargin() || log_timestamp != Options::getInstance().logTimestampEnabled() || log_timestamp_format != Options::getInstance().logTimestampFormat(); log_goes_downwards = Options::getInstance().logDirectionDownwards(); log_colors = Options::getInstance().colorLogEnabled(); log_newline = Options::getInstance().logNewline(); log_margin = Options::getInstance().logMargin(); log_timestamp = Options::getInstance().logTimestampEnabled(); log_timestamp_format = Options::getInstance().logTimestampFormat(); - if (regenerate) { + if (regenerate) + { regenerate_ic_chatlog(); } set_size_and_pos(ui_ic_chatlog, "ic_chatlog"); ui_ic_chatlog->setFrameShape(QFrame::NoFrame); - ui_ic_chatlog->setPlaceholderText(log_goes_downwards ? "▼ " + tr("Log goes down") + " ▼" - : "▲ " + tr("Log goes up") + " ▲"); + ui_ic_chatlog->setPlaceholderText(log_goes_downwards ? "▼ " + tr("Log goes down") + " ▼" : "▲ " + tr("Log goes up") + " ▲"); set_size_and_pos(ui_debug_log, "ms_chatlog"); // Old name, still use it to not break compatibility ui_debug_log->setFrameShape(QFrame::NoFrame); @@ -764,27 +821,23 @@ void Courtroom::set_widgets() set_size_and_pos(ui_pair_offset_spinbox, "pair_offset_spinbox"); ui_pair_offset_spinbox->hide(); - ui_pair_offset_spinbox->setToolTip( - tr("Change the horizontal percentage offset of your character's position " - "from the " - "center of the screen.")); + ui_pair_offset_spinbox->setToolTip(tr("Change the horizontal percentage offset of your character's position " + "from the " + "center of the screen.")); set_size_and_pos(ui_pair_vert_offset_spinbox, "pair_vert_offset_spinbox"); ui_pair_vert_offset_spinbox->hide(); - ui_pair_vert_offset_spinbox->setToolTip( - tr("Change the vertical percentage offset of your character's position " - "from the " - "center of the screen.")); + ui_pair_vert_offset_spinbox->setToolTip(tr("Change the vertical percentage offset of your character's position " + "from the " + "center of the screen.")); ui_pair_order_dropdown->hide(); set_size_and_pos(ui_pair_order_dropdown, "pair_order_dropdown"); - ui_pair_order_dropdown->setToolTip( - tr("Change the order of appearance for your character.")); + ui_pair_order_dropdown->setToolTip(tr("Change the order of appearance for your character.")); set_size_and_pos(ui_pair_button, "pair_button"); ui_pair_button->set_image("pair_button"); - ui_pair_button->setToolTip( - tr("Display the list of characters to pair with.")); + ui_pair_button->setToolTip(tr("Display the list of characters to pair with.")); set_size_and_pos(ui_area_list, "music_list"); ui_area_list->header()->setMinimumSectionSize(ui_area_list->width()); @@ -793,9 +846,13 @@ void Courtroom::set_widgets() ui_music_list->header()->setMinimumSectionSize(ui_music_list->width()); QString music_list_indentation = ao_app->get_design_element("music_list_indent", "courtroom_design.ini"); if (music_list_indentation == "") + { ui_music_list->resetIndentation(); + } else + { ui_music_list->setIndentation(music_list_indentation.toInt()); + } QString music_list_animated = ao_app->get_design_element("music_list_animated", "courtroom_design.ini"); ui_music_list->setAnimated(music_list_animated == "1" || music_list_animated.startsWith("true")); @@ -803,22 +860,22 @@ void Courtroom::set_widgets() set_size_and_pos(ui_music_name, "music_name"); ui_music_display->move(0, 0); - pos_size_type design_ini_result = - ao_app->get_element_dimensions("music_display", "courtroom_design.ini"); + pos_size_type design_ini_result = ao_app->get_element_dimensions("music_display", "courtroom_design.ini"); - if (design_ini_result.width < 0 || design_ini_result.height < 0) { + if (design_ini_result.width < 0 || design_ini_result.height < 0) + { qWarning() << "could not find \"music_display\" in courtroom_design.ini"; ui_music_display->hide(); } - else { + else + { ui_music_display->move(design_ini_result.x, design_ini_result.y); - ui_music_display->combo_resize(design_ini_result.width, - design_ini_result.height); + ui_music_display->combo_resize(design_ini_result.width, design_ini_result.height); } ui_music_display->load_image("music_display", ""); - - for (int i = 0; i < max_clocks; i++) { + for (int i = 0; i < max_clocks; i++) + { set_size_and_pos(ui_clock[i], "clock_" + QString::number(i)); } set_size_and_pos(ui_ic_chat_message, "ao2_ic_chat_message"); @@ -827,14 +884,13 @@ void Courtroom::set_widgets() initialize_chatbox(); ui_vp_sticker->move(ui_viewport->x(), ui_viewport->y()); - ui_vp_sticker->combo_resize(ui_viewport->width(), - ui_viewport->height()); + ui_vp_sticker->combo_resize(ui_viewport->width(), ui_viewport->height()); ui_muted->resize(ui_ic_chat_message->width(), ui_ic_chat_message->height()); ui_muted->set_image("muted"); ui_muted->setToolTip(tr("Oops, you're muted!")); - set_size_and_pos(ui_ooc_chat_message, "ooc_chat_message");; + set_size_and_pos(ui_ooc_chat_message, "ooc_chat_message"); set_size_and_pos(ui_ooc_chat_name, "ooc_chat_name"); @@ -842,49 +898,48 @@ void Courtroom::set_widgets() set_size_and_pos(ui_music_search, "music_search"); set_size_and_pos(ui_emote_dropdown, "emote_dropdown"); - ui_emote_dropdown->setToolTip( - tr("Set your character's emote to play on your next message.")); + ui_emote_dropdown->setToolTip(tr("Set your character's emote to play on your next message.")); set_size_and_pos(ui_pos_dropdown, "pos_dropdown"); ui_pos_dropdown->setEditable(true); ui_pos_dropdown->setInsertPolicy(QComboBox::NoInsert); - ui_pos_dropdown->setToolTip( - tr("Set your character's supplementary background.")); + ui_pos_dropdown->setToolTip(tr("Set your character's supplementary background.")); set_size_and_pos(ui_pos_remove, "pos_remove"); ui_pos_remove->setText("X"); ui_pos_remove->set_image("evidencex"); ui_pos_remove->setToolTip(tr("Reset your character's supplementary background to its default.")); if (current_side == "") + { ui_pos_remove->hide(); + } else + { ui_pos_remove->show(); + } set_size_and_pos(ui_iniswap_dropdown, "iniswap_dropdown"); ui_iniswap_dropdown->setEditable(true); ui_iniswap_dropdown->setInsertPolicy(QComboBox::InsertAtBottom); - ui_iniswap_dropdown->setToolTip( - tr("Set an 'iniswap', or an alternative character folder to refer to " - "from your current character.\n" - "Edit by typing and pressing Enter, [X] to remove. This saves to your " - "base/iniswaps.ini")); + ui_iniswap_dropdown->setToolTip(tr("Set an 'iniswap', or an alternative character folder to refer to " + "from your current character.\n" + "Edit by typing and pressing Enter, [X] to remove. This saves to your " + "base/iniswaps.ini")); set_size_and_pos(ui_iniswap_remove, "iniswap_remove"); ui_iniswap_remove->setText("X"); ui_iniswap_remove->set_image("evidencex"); - ui_iniswap_remove->setToolTip( - tr("Remove the currently selected iniswap from the list and return to " - "the original character folder.")); + ui_iniswap_remove->setToolTip(tr("Remove the currently selected iniswap from the list and return to " + "the original character folder.")); ui_iniswap_remove->hide(); set_size_and_pos(ui_sfx_dropdown, "sfx_dropdown"); ui_sfx_dropdown->setEditable(true); ui_sfx_dropdown->setInsertPolicy(QComboBox::NoInsert); - ui_sfx_dropdown->setToolTip( - tr("Set a sound effect to play on your next 'Preanim'. Leaving it on " - "Default will use the emote-defined sound (if any).\n" - "Edit by typing and pressing Enter, [X] to remove. This saves to your " - "base/characters/<charname>/soundlist.ini")); + ui_sfx_dropdown->setToolTip(tr("Set a sound effect to play on your next 'Preanim'. Leaving it on " + "Default will use the emote-defined sound (if any).\n" + "Edit by typing and pressing Enter, [X] to remove. This saves to your " + "base/characters/<charname>/soundlist.ini")); set_size_and_pos(ui_sfx_remove, "sfx_remove"); ui_sfx_remove->setText("X"); @@ -896,12 +951,11 @@ void Courtroom::set_widgets() set_size_and_pos(ui_effects_dropdown, "effects_dropdown"); ui_effects_dropdown->setInsertPolicy(QComboBox::InsertAtBottom); - ui_effects_dropdown->setToolTip( - tr("Choose an effect to play on your next spoken message.\n" - "The effects are defined in your theme/effects/effects.ini. Your " - "character can define custom effects by\n" - "char.ini [Options] category, effects = 'miscname' where it refers " - "to misc/<miscname>/effects.ini to read the effects.")); + ui_effects_dropdown->setToolTip(tr("Choose an effect to play on your next spoken message.\n" + "The effects are defined in your theme/effects/effects.ini. Your " + "character can define custom effects by\n" + "char.ini [Options] category, effects = 'miscname' where it refers " + "to misc/<miscname>/effects.ini to read the effects.")); // Todo: recode this entire fucking system with these dumbass goddamn ini's // why is everything so specifically coded for all these purposes is ABSTRACT // CODING not a thing now huh what the FUCK why do I gotta do this pleASE FOR @@ -913,8 +967,7 @@ void Courtroom::set_widgets() ui_defense_bar->set_image("defensebar" + QString::number(defense_bar_state)); set_size_and_pos(ui_prosecution_bar, "prosecution_bar"); - ui_prosecution_bar->set_image("prosecutionbar" + - QString::number(prosecution_bar_state)); + ui_prosecution_bar->set_image("prosecutionbar" + QString::number(prosecution_bar_state)); set_size_and_pos(ui_music_label, "music_label"); ui_music_label->setText(tr("Music")); @@ -943,8 +996,7 @@ void Courtroom::set_widgets() set_size_and_pos(ui_ooc_toggle, "ooc_toggle"); ui_ooc_toggle->setText(tr("Server")); - ui_ooc_toggle->setToolTip( - tr("Toggle between server chat and global AO2 chat.")); + ui_ooc_toggle->setToolTip(tr("Toggle between server chat and global AO2 chat.")); set_size_and_pos(ui_witness_testimony, "witness_testimony"); ui_witness_testimony->set_image("witnesstestimony"); @@ -968,29 +1020,26 @@ void Courtroom::set_widgets() set_size_and_pos(ui_change_character, "change_character"); ui_change_character->setText(tr("Change character")); ui_change_character->set_image("change_character"); - ui_change_character->setToolTip( - tr("Bring up the Character Select Screen and change your character.")); + ui_change_character->setToolTip(tr("Bring up the Character Select Screen and change your character.")); set_size_and_pos(ui_reload_theme, "reload_theme"); ui_reload_theme->setText(tr("Reload theme")); ui_reload_theme->set_image("reload_theme"); - ui_reload_theme->setToolTip( - tr("Refresh the theme and update all of the ui elements to match.")); + ui_reload_theme->setToolTip(tr("Refresh the theme and update all of the ui elements to match.")); set_size_and_pos(ui_call_mod, "call_mod"); ui_call_mod->setText(tr("Call mod")); ui_call_mod->set_image("call_mod"); - ui_call_mod->setToolTip( - tr("Request the attention of the current server's moderator.")); + ui_call_mod->setToolTip(tr("Request the attention of the current server's moderator.")); set_size_and_pos(ui_settings, "settings"); ui_settings->setText(tr("Settings")); ui_settings->set_image("courtroom_settings"); - if (ui_settings->icon().isNull()) { - ui_settings->set_image("settings"); // pre-2.10 filename + if (ui_settings->icon().isNull()) + { + ui_settings->set_image("settings"); // pre-2.10 filename } - ui_settings->setToolTip( - tr("Allows you to change various aspects of the client.")); + ui_settings->setToolTip(tr("Allows you to change various aspects of the client.")); set_size_and_pos(ui_switch_area_music, "switch_area_music"); ui_switch_area_music->setText(tr("A/M")); @@ -999,68 +1048,59 @@ void Courtroom::set_widgets() set_size_and_pos(ui_pre, "pre"); ui_pre->setText(tr("Preanim")); - ui_pre->setToolTip( - tr("Play a single-shot animation as defined by the emote when checked.")); + ui_pre->setToolTip(tr("Play a single-shot animation as defined by the emote when checked.")); - ui_immediate->setToolTip( - tr("If preanim is checked, display the input text immediately as the " - "animation plays concurrently.")); + ui_immediate->setToolTip(tr("If preanim is checked, display the input text immediately as the " + "animation plays concurrently.")); - design_ini_result = - ao_app->get_element_dimensions("immediate", "courtroom_design.ini"); + design_ini_result = ao_app->get_element_dimensions("immediate", "courtroom_design.ini"); // If we don't have new-style naming, fall back to the old method - if (design_ini_result.width < 0 || design_ini_result.height < 0) { + if (design_ini_result.width < 0 || design_ini_result.height < 0) + { set_size_and_pos(ui_immediate, "pre_no_interrupt"); truncate_label_text(ui_immediate, "pre_no_interrupt"); } - else {// Adopt the based new method instead + else + { // Adopt the based new method instead set_size_and_pos(ui_immediate, "immediate"); truncate_label_text(ui_immediate, "immediate"); } - set_size_and_pos(ui_flip, "flip"); ui_flip->setToolTip(tr("Mirror your character's emotes when checked.")); set_size_and_pos(ui_additive, "additive"); - ui_additive->setToolTip( - tr("Add text to your last spoken message when checked.")); + ui_additive->setToolTip(tr("Add text to your last spoken message when checked.")); set_size_and_pos(ui_guard, "guard"); - ui_guard->setToolTip( - tr("Do not listen to mod calls when checked, preventing them from " - "playing sounds or focusing attention on the window.")); + ui_guard->setToolTip(tr("Do not listen to mod calls when checked, preventing them from " + "playing sounds or focusing attention on the window.")); set_size_and_pos(ui_showname_enable, "showname_enable"); - ui_showname_enable->setToolTip( - tr("Display customized shownames for all users when checked.")); + ui_showname_enable->setToolTip(tr("Display customized shownames for all users when checked.")); set_size_and_pos(ui_custom_objection, "custom_objection"); ui_custom_objection->setText(tr("Custom Shout!")); ui_custom_objection->set_image("custom"); - ui_custom_objection->setToolTip( - tr("This will display the custom character-defined animation in the " - "viewport as soon as it is pressed.\n" - "To make one, your character's folder must contain " - "custom.[webp/apng/gif/png] and custom.[wav/ogg/opus] sound effect")); + ui_custom_objection->setToolTip(tr("This will display the custom character-defined animation in the " + "viewport as soon as it is pressed.\n" + "To make one, your character's folder must contain " + "custom.[webp/apng/gif/png] and custom.[wav/ogg/opus] sound effect")); set_size_and_pos(ui_realization, "realization"); ui_realization->set_image("realization"); - ui_realization->setToolTip( - tr("Play realization sound and animation in the viewport on the next " - "spoken message when checked.")); + ui_realization->setToolTip(tr("Play realization sound and animation in the viewport on the next " + "spoken message when checked.")); set_size_and_pos(ui_screenshake, "screenshake"); ui_screenshake->set_image("screenshake"); - ui_screenshake->setToolTip( - tr("Shake the screen on next spoken message when checked.")); + ui_screenshake->setToolTip(tr("Shake the screen on next spoken message when checked.")); set_size_and_pos(ui_mute, "mute_button"); ui_mute->setText("Mute"); ui_mute->set_image("mute"); - ui_mute->setToolTip( - tr("Display the list of character folders you wish to mute.")); + ui_mute->setToolTip(tr("Display the list of character folders you wish to mute.")); set_size_and_pos(ui_defense_plus, "defense_plus"); ui_defense_plus->set_image("defplus"); @@ -1079,10 +1119,9 @@ void Courtroom::set_widgets() ui_prosecution_minus->setToolTip(tr("Decrease the health bar.")); set_size_and_pos(ui_text_color, "text_color"); - ui_text_color->setToolTip( - tr("Change the text color of the spoken message.\n" - "You can also select a part of your currently typed message and use " - "the dropdown to change its color!")); + ui_text_color->setToolTip(tr("Change the text color of the spoken message.\n" + "You can also select a part of your currently typed message and use " + "the dropdown to change its color!")); set_text_color_dropdown(); set_size_and_pos(ui_music_slider, "music_slider"); @@ -1118,19 +1157,13 @@ void Courtroom::set_widgets() truncate_label_text(ui_sfx_label, "sfx_label"); truncate_label_text(ui_blip_label, "blip_label"); - free_brush = - QBrush(ao_app->get_color("area_free_color", "courtroom_design.ini")); - lfp_brush = - QBrush(ao_app->get_color("area_lfp_color", "courtroom_design.ini")); - casing_brush = - QBrush(ao_app->get_color("area_casing_color", "courtroom_design.ini")); - recess_brush = - QBrush(ao_app->get_color("area_recess_color", "courtroom_design.ini")); + free_brush = QBrush(ao_app->get_color("area_free_color", "courtroom_design.ini")); + lfp_brush = QBrush(ao_app->get_color("area_lfp_color", "courtroom_design.ini")); + casing_brush = QBrush(ao_app->get_color("area_casing_color", "courtroom_design.ini")); + recess_brush = QBrush(ao_app->get_color("area_recess_color", "courtroom_design.ini")); rp_brush = QBrush(ao_app->get_color("area_rp_color", "courtroom_design.ini")); - gaming_brush = - QBrush(ao_app->get_color("area_gaming_color", "courtroom_design.ini")); - locked_brush = - QBrush(ao_app->get_color("area_locked_color", "courtroom_design.ini")); + gaming_brush = QBrush(ao_app->get_color("area_gaming_color", "courtroom_design.ini")); + locked_brush = QBrush(ao_app->get_color("area_locked_color", "courtroom_design.ini")); refresh_evidence(); } @@ -1152,99 +1185,102 @@ void Courtroom::set_fonts(QString p_char) set_font(ui_music_name, "", "music_name", p_char); for (int i = 0; i < max_clocks; i++) + { set_font(ui_clock[i], "", "clock_" + QString::number(i), p_char); + } set_stylesheets(); } -void Courtroom::set_font(QWidget *widget, QString class_name, - QString p_identifier, QString p_char, - QString font_name, int f_pointsize) +void Courtroom::set_font(QWidget *widget, QString class_name, QString p_identifier, QString p_char, QString font_name, int f_pointsize) { QString design_file = "courtroom_fonts.ini"; if (f_pointsize <= 0) - f_pointsize = - ao_app->get_design_element(p_identifier, design_file, ao_app->get_chat(p_char)).toInt() * Options::getInstance().themeScalingFactor(); + { + f_pointsize = ao_app->get_design_element(p_identifier, design_file, ao_app->get_chat(p_char)).toInt() * Options::getInstance().themeScalingFactor(); + } if (font_name == "") - font_name = - ao_app->get_design_element(p_identifier + "_font", design_file, ao_app->get_chat(p_char)); - QString f_color_result = - ao_app->get_design_element(p_identifier + "_color", design_file, ao_app->get_chat(p_char)); + { + font_name = ao_app->get_design_element(p_identifier + "_font", design_file, ao_app->get_chat(p_char)); + } + QString f_color_result = ao_app->get_design_element(p_identifier + "_color", design_file, ao_app->get_chat(p_char)); QColor f_color(0, 0, 0); - if (f_color_result != "") { + if (f_color_result != "") + { QStringList color_list = f_color_result.split(","); - if (color_list.size() >= 3) { + if (color_list.size() >= 3) + { f_color.setRed(color_list.at(0).toInt()); f_color.setGreen(color_list.at(1).toInt()); f_color.setBlue(color_list.at(2).toInt()); } } - bool bold = - ao_app->get_design_element(p_identifier + "_bold", design_file, ao_app->get_chat(p_char)) == - "1"; // is the font bold or not? - bool antialias = ao_app->get_design_element(p_identifier + "_sharp", - design_file, ao_app->get_chat(p_char)) != - "1"; // is the font anti-aliased or not? + bool bold = ao_app->get_design_element(p_identifier + "_bold", design_file, ao_app->get_chat(p_char)) == "1"; // is the font bold or not? + bool antialias = ao_app->get_design_element(p_identifier + "_sharp", design_file, ao_app->get_chat(p_char)) != "1"; // is the font anti-aliased or not? bool outlined = ao_app->get_design_element(p_identifier + "_outlined", design_file, ao_app->get_chat(p_char)) == "1"; QColor outline_color; int outline_width = 1; - if (outlined) { - QString outline_color_result = - ao_app->get_design_element(p_identifier + "_outline_color", design_file, ao_app->get_chat(p_char)); - outline_color = QColor(0,0,0); - if (outline_color_result != "") { - QStringList o_color_list = outline_color_result.split(","); - - if (o_color_list.size() >= 3) { - outline_color.setRed(o_color_list.at(0).toInt()); - outline_color.setGreen(o_color_list.at(1).toInt()); - outline_color.setBlue(o_color_list.at(2).toInt()); - } + if (outlined) + { + QString outline_color_result = ao_app->get_design_element(p_identifier + "_outline_color", design_file, ao_app->get_chat(p_char)); + outline_color = QColor(0, 0, 0); + if (outline_color_result != "") + { + QStringList o_color_list = outline_color_result.split(","); + + if (o_color_list.size() >= 3) + { + outline_color.setRed(o_color_list.at(0).toInt()); + outline_color.setGreen(o_color_list.at(1).toInt()); + outline_color.setBlue(o_color_list.at(2).toInt()); } - outline_width = ao_app->get_design_element(p_identifier + "_outline_width", design_file, ao_app->get_chat(p_char)).toInt() * Options::getInstance().themeScalingFactor(); + } + outline_width = ao_app->get_design_element(p_identifier + "_outline_width", design_file, ao_app->get_chat(p_char)).toInt() * Options::getInstance().themeScalingFactor(); } - this->set_qfont(widget, class_name, - get_qfont(font_name, f_pointsize, antialias), f_color, bold, outlined, outline_color, outline_width); + this->set_qfont(widget, class_name, get_qfont(font_name, f_pointsize, antialias), f_color, bold, outlined, outline_color, outline_width); } QFont Courtroom::get_qfont(QString font_name, int f_pointsize, bool antialias) { QFont font; if (font_name.isEmpty()) + { font_name = "Arial"; + } QFont::StyleStrategy style_strategy = QFont::PreferDefault; if (!antialias) + { style_strategy = QFont::NoAntialias; + } font = QFont(font_name, f_pointsize); font.setStyleHint(QFont::SansSerif, style_strategy); return font; } -void Courtroom::set_qfont(QWidget *widget, QString class_name, QFont font, - QColor f_color, bool bold, bool outlined, QColor outline_color, int outline_width) +void Courtroom::set_qfont(QWidget *widget, QString class_name, QFont font, QColor f_color, bool bold, bool outlined, QColor outline_color, int outline_width) { if (class_name.isEmpty()) + { class_name = widget->metaObject()->className(); + } - if (class_name == "AOChatboxLabel") { // Only shownames can be outlined - ui_vp_showname->setIsOutlined(outlined); - ui_vp_showname->setOutlineColor(outline_color); - ui_vp_showname->setTextColor(f_color); - ui_vp_showname->setOutlineWidth(outline_width); + if (class_name == "AOChatboxLabel") + { // Only shownames can be outlined + ui_vp_showname->setIsOutlined(outlined); + ui_vp_showname->setOutlineColor(outline_color); + ui_vp_showname->setTextColor(f_color); + ui_vp_showname->setOutlineWidth(outline_width); } font.setBold(bold); widget->setFont(font); - QString style_sheet_string = - class_name + " { color: rgba(" + - QString::number(f_color.red()) + ", " + QString::number(f_color.green()) + - ", " + QString::number(f_color.blue()) + ", 255);}"; + QString style_sheet_string = class_name + " { color: rgba(" + QString::number(f_color.red()) + ", " + QString::number(f_color.green()) + ", " + QString::number(f_color.blue()) + ", 255);}"; widget->setStyleSheet(style_sheet_string); } @@ -1253,18 +1289,18 @@ void Courtroom::set_stylesheet(QWidget *widget) QString f_file = "courtroom_stylesheets.css"; QString style_sheet_string = ao_app->get_stylesheet(f_file); if (style_sheet_string != "") + { widget->setStyleSheet(style_sheet_string); + } } 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() - ); + 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) @@ -1276,14 +1312,15 @@ void Courtroom::set_size_and_pos(QWidget *p_widget, QString p_identifier, QStrin { QString filename = "courtroom_design.ini"; - pos_size_type design_ini_result = - ao_app->get_element_dimensions(p_identifier, filename, p_misc); + pos_size_type design_ini_result = ao_app->get_element_dimensions(p_identifier, filename, p_misc); - if (design_ini_result.width < 0 || design_ini_result.height < 0) { + if (design_ini_result.width < 0 || design_ini_result.height < 0) + { qWarning() << "could not find" << p_identifier << "in" << filename; p_widget->hide(); } - else { + else + { p_widget->move(design_ini_result.x, design_ini_result.y); p_widget->resize(design_ini_result.width, design_ini_result.height); } @@ -1291,7 +1328,8 @@ void Courtroom::set_size_and_pos(QWidget *p_widget, QString p_identifier, QStrin void Courtroom::set_taken(int n_char, bool p_taken) { - if (n_char >= char_list.size()) { + if (n_char >= char_list.size()) + { qWarning() << "set_taken attempted to set an index bigger than char_list size"; return; } @@ -1305,22 +1343,6 @@ void Courtroom::set_taken(int n_char, bool p_taken) char_list.replace(n_char, f_char); } -QPoint Courtroom::get_theme_pos(QString p_identifier) -{ - QString filename = "courtroom_design.ini"; - - pos_size_type design_ini_result = - ao_app->get_element_dimensions(p_identifier, filename); - - if (design_ini_result.width < 0 || design_ini_result.height < 0) { - qWarning() << "could not find" << p_identifier << "in" << filename; - return QPoint(0, 0); - } - else { - return QPoint(design_ini_result.x, design_ini_result.y); - } -} - void Courtroom::done_received() { m_cid = -1; @@ -1363,23 +1385,26 @@ 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 (const QString &key : default_pos.keys()) { - 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( - ao_app->get_image_suffix(ao_app->get_background_path(key)))) { // if we have pre-2.8-style positions, e.g. defenseempty.png + for (const QString &key : default_pos.keys()) + { + 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(ao_app->get_image_suffix(ao_app->get_background_path(key)))) + { // if we have pre-2.8-style positions, e.g. defenseempty.png pos_list.append(default_pos[key]); } } - 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)))) { + 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); } } set_pos_dropdown(pos_list); - if (display) { + if (display) + { ui_vp_speedlines->hide(); ui_vp_player_char->stop(); @@ -1388,11 +1413,13 @@ void Courtroom::set_background(QString p_background, bool display) ui_vp_message->hide(); ui_vp_chatbox->setVisible(chatbox_always_show); // Show it if chatbox always shows - if (Options::getInstance().characterStickerEnabled() && chatbox_always_show) { + if (Options::getInstance().characterStickerEnabled() && chatbox_always_show) + { ui_vp_sticker->load_image(m_chatmessage[CHAR_NAME]); } // Hide the face sticker - else { + else + { ui_vp_sticker->stop(); } // Stop the chat arrow from animating @@ -1409,20 +1436,24 @@ void Courtroom::set_background(QString p_background, bool display) ui_vp_evidence_display->reset(); QString f_side = current_side; if (current_side == "") + { f_side = ao_app->get_char_side(current_char); + } set_scene(true, f_side); } } void Courtroom::set_side(QString p_side) { - if (p_side.isEmpty() || p_side == ao_app->get_char_side(current_char)) { - ui_pos_remove->hide(); - current_side = ao_app->get_char_side(current_char); + if (p_side.isEmpty() || p_side == ao_app->get_char_side(current_char)) + { + ui_pos_remove->hide(); + current_side = ao_app->get_char_side(current_char); } - else { - ui_pos_remove->show(); - current_side = p_side; + else + { + ui_pos_remove->show(); + current_side = p_side; } set_judge_buttons(); @@ -1430,10 +1461,11 @@ void Courtroom::set_side(QString p_side) // Block the signals to prevent setCurrentIndex from triggering a pos // change ui_pos_dropdown->blockSignals(true); - for (int i = 0; i < ui_pos_dropdown->count(); ++i) { + for (int i = 0; i < ui_pos_dropdown->count(); ++i) + { QString pos = ui_pos_dropdown->itemText(i); - if (pos == current_side) { - + if (pos == current_side) + { // Set the index on dropdown ui element to let you know what pos you're on // right now ui_pos_dropdown->setCurrentIndex(i); @@ -1456,18 +1488,22 @@ void Courtroom::set_pos_dropdown(QStringList pos_dropdowns) ui_pos_dropdown->blockSignals(true); pos_dropdown_list = pos_dropdowns; ui_pos_dropdown->clear(); - for (int n = 0; n < pos_dropdown_list.size(); ++n) { + for (int n = 0; n < pos_dropdown_list.size(); ++n) + { QString pos = pos_dropdown_list.at(n); ui_pos_dropdown->addItem(pos); QPixmap image = QPixmap(ao_app->get_image_suffix(ao_app->get_background_path(ao_app->get_pos_path(pos)))); - if (!image.isNull()) { + if (!image.isNull()) + { image = image.scaledToHeight(ui_pos_dropdown->iconSize().height()); } ui_pos_dropdown->setItemIcon(n, image); } if (current_side != "" && !pos_dropdown_list.contains(current_side)) + { ui_pos_dropdown->setEditText(current_side); + } // Unblock the signals so the element can be used for setting pos again ui_pos_dropdown->blockSignals(false); @@ -1481,19 +1517,26 @@ void Courtroom::update_character(int p_cid, QString char_name, bool reset_emote) QString f_char; - if (m_cid == -1) { + if (m_cid == -1) + { if (Options::getInstance().discordEnabled()) + { ao_app->discord->state_spectate(); + } f_char = ""; } - else { + else + { f_char = char_name; - if (char_name.isEmpty()) { + if (char_name.isEmpty()) + { f_char = char_list.at(m_cid).name; } if (Options::getInstance().discordEnabled()) + { ao_app->discord->state_character(f_char.toStdString()); + } } current_char = f_char; @@ -1503,15 +1546,20 @@ void Courtroom::update_character(int p_cid, QString char_name, bool reset_emote) set_text_color_dropdown(); // If our cid changed or we're being told to reset - if (newchar || reset_emote) { + if (newchar || reset_emote) + { current_emote_page = 0; current_emote = 0; } if (m_cid == -1) + { ui_emotes->hide(); + } else + { ui_emotes->show(); + } refresh_emotes(); set_emote_page(); @@ -1521,28 +1569,34 @@ void Courtroom::update_character(int p_cid, QString char_name, bool reset_emote) set_effects_dropdown(); if (newchar) // Avoid infinite loop of death and suffering + { set_iniswap_dropdown(); + } ui_custom_objection->hide(); if (ao_app->custom_objection_supported) // if setting is enabled { custom_obj_menu->clear(); custom_objections_list.clear(); - if (file_exists(ao_app->get_image_suffix( - ao_app->get_character_path(current_char, "custom")))) { + if (file_exists(ao_app->get_image_suffix(ao_app->get_character_path(current_char, "custom")))) + { ui_custom_objection->show(); QString custom_name = ao_app->read_char_ini(f_char, "custom_name", "Shouts"); QAction *action; if (custom_name != "") + { action = custom_obj_menu->addAction(custom_name); + } else + { action = custom_obj_menu->addAction("Default"); + } custom_obj_menu->setDefaultAction(action); objection_custom = ""; } - QString custom_objection_dir = ao_app->get_real_path( - ao_app->get_character_path(current_char, "custom_objections")); - if (dir_exists(custom_objection_dir)) { + 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" @@ -1550,32 +1604,38 @@ void Courtroom::update_character(int p_cid, QString char_name, bool reset_emote) << "*.apng" << "*.webp", QDir::Files); - for (const QString &filename : custom_obj) { + for (const QString &filename : custom_obj) + { CustomObjection custom_objection; custom_objection.filename = filename; QString custom_name = ao_app->read_char_ini(f_char, filename.left(filename.lastIndexOf(".")) + "_name", "Shouts"); QAction *action; - if (custom_name != "") { + if (custom_name != "") + { custom_objection.name = custom_name; action = custom_obj_menu->addAction(custom_name); } - else { + else + { custom_objection.name = filename.left(filename.lastIndexOf(".")); action = custom_obj_menu->addAction(custom_objection.name); } - if (custom_obj_menu->defaultAction() == nullptr) { + if (custom_obj_menu->defaultAction() == nullptr) + { custom_obj_menu->setDefaultAction(action); objection_custom = custom_objection.filename; } - custom_objections_list.append(custom_objection); + custom_objections_list.append(custom_objection); } } } - if (m_cid != -1) { + if (m_cid != -1) + { ui_ic_chat_name->setPlaceholderText(char_list.at(m_cid).name); } - else { + else + { ui_ic_chat_name->setPlaceholderText("Spectator"); } ui_char_select_background->hide(); @@ -1589,20 +1649,27 @@ void Courtroom::enter_courtroom() set_evidence_page(); if (ao_app->flipping_supported) + { ui_flip->show(); + } else + { ui_flip->hide(); + } if (ao_app->additive_text_supported) + { ui_additive->show(); + } else + { ui_additive->hide(); + } list_music(); list_areas(); - switch ( - objection_state) // no need to reset these as it was done in set_widgets() + switch (objection_state) // no need to reset these as it was done in set_widgets() { case 1: ui_hold_it->set_image("holdit_selected"); @@ -1647,7 +1714,8 @@ void Courtroom::list_music() int n_listed_songs = 0; QTreeWidgetItem *parent = nullptr; - for (int n_song = 0; n_song < music_list.size(); ++n_song) { + for (int n_song = 0; n_song < music_list.size(); ++n_song) + { QString i_song = music_list.at(n_song); // It's a stop song or a stop category // yes we cannot properly parse a stop song without a stop category cuz otherwise areas break @@ -1657,36 +1725,46 @@ void Courtroom::list_music() // please end my suffering QString temp = i_song; if (i_song == "~stop.mp3" || (temp.remove('=').toLower() == "stop")) - continue; + { + continue; + } QString i_song_listname = i_song.left(i_song.lastIndexOf(".")); - i_song_listname = i_song_listname.right( - i_song_listname.length() - (i_song_listname.lastIndexOf("/") + 1)); + i_song_listname = i_song_listname.right(i_song_listname.length() - (i_song_listname.lastIndexOf("/") + 1)); QTreeWidgetItem *treeItem; - if (i_song_listname != i_song && - parent != nullptr) // not a category, parent exists + if (i_song_listname != i_song && parent != nullptr) // not a category, parent exists + { treeItem = new QTreeWidgetItem(parent); + } else + { treeItem = new QTreeWidgetItem(ui_music_list); + } treeItem->setText(0, i_song_listname); treeItem->setText(1, 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); + } else + { treeItem->setBackground(0, missing_brush); + } - if (i_song_listname == - i_song) // Not supposed to be a song to begin with - a category? + if (i_song_listname == i_song) // Not supposed to be a song to begin with - a category? + { parent = treeItem; + } ++n_listed_songs; } ui_music_list->expandAll(); // Needs to somehow remember which categories were // expanded/collapsed if the music list didn't // change since last time - if (ui_music_search->text() != "") { + if (ui_music_search->text() != "") + { on_music_search_edited(ui_music_search->text()); } } @@ -1696,23 +1774,27 @@ void Courtroom::list_areas() { int n_listed_areas = 0; - for (int n_area = 0; n_area < area_list.size(); ++n_area) { - QString i_area = ""; + for (int n_area = 0; n_area < area_list.size(); ++n_area) + { + QString i_area; i_area.append(area_list.at(n_area)); - if (ao_app->arup_supported) { + if (ao_app->arup_supported) + { i_area.append("\n "); i_area.append(arup_statuses.at(n_area)); - if (arup_cms.at(n_area) != "FREE") { + if (arup_cms.at(n_area) != "FREE") + { i_area.append(" | CM: "); i_area.append(arup_cms.at(n_area)); } i_area.append("\n "); - if (arup_players.at(n_area) != -1) { + if (arup_players.at(n_area) != -1) + { i_area.append(QString::number(arup_players.at(n_area))); i_area.append(" users | "); } @@ -1720,93 +1802,95 @@ void Courtroom::list_areas() i_area.append(arup_locks.at(n_area)); } - QTreeWidgetItem *treeItem = ui_area_list->topLevelItem(n_area); - if (treeItem == nullptr) { + if (treeItem == nullptr) + { treeItem = new QTreeWidgetItem(ui_area_list); } treeItem->setText(0, area_list.at(n_area)); treeItem->setText(1, i_area); - if (ao_app->arup_supported) { + if (ao_app->arup_supported) + { // Coloring logic here. treeItem->setBackground(1, free_brush); - if (arup_locks.at(n_area) == "LOCKED") { + if (arup_locks.at(n_area) == "LOCKED") + { treeItem->setBackground(1, locked_brush); } - else { + else + { if (arup_statuses.at(n_area) == "LOOKING-FOR-PLAYERS") + { treeItem->setBackground(1, lfp_brush); + } else if (arup_statuses.at(n_area) == "CASING") + { treeItem->setBackground(1, casing_brush); + } else if (arup_statuses.at(n_area) == "RECESS") + { treeItem->setBackground(1, recess_brush); + } else if (arup_statuses.at(n_area) == "RP") + { treeItem->setBackground(1, rp_brush); + } else if (arup_statuses.at(n_area) == "GAMING") + { treeItem->setBackground(1, gaming_brush); + } } } - else { + else + { treeItem->setBackground(1, free_brush); } ++n_listed_areas; } - while (ui_area_list->topLevelItemCount() > n_listed_areas) { - ui_area_list->takeTopLevelItem(ui_area_list->topLevelItemCount()-1); + while (ui_area_list->topLevelItemCount() > n_listed_areas) + { + ui_area_list->takeTopLevelItem(ui_area_list->topLevelItemCount() - 1); } - if (ui_music_search->text() != "") { + if (ui_music_search->text() != "") + { on_music_search_edited(ui_music_search->text()); } } -void Courtroom::debug_message_handler(QtMsgType type, const QMessageLogContext &context, - const QString &msg) +void Courtroom::debug_message_handler(QtMsgType type, const QMessageLogContext &context, const QString &msg) { Q_UNUSED(context); - const QMap<QtMsgType, QString> colors = { - {QtDebugMsg, "debug"}, - {QtInfoMsg, "info"}, - {QtWarningMsg, "warn"}, - {QtCriticalMsg, "critical"}, - {QtFatalMsg, "fatal"} - }; + const QMap<QtMsgType, QString> colors = {{QtDebugMsg, "debug"}, {QtInfoMsg, "info"}, {QtWarningMsg, "warn"}, {QtCriticalMsg, "critical"}, {QtFatalMsg, "fatal"}}; const QString color_id = QString("debug_log_%1_color").arg(colors.value(type, "info")); - ui_debug_log->append_chatmessage( - colors.value(type, "info"), msg, - QString(), ao_app->get_color(color_id, "courtroom_fonts.ini").name()); -} - -void Courtroom::append_debug_message(QString f_message) -{ - ui_debug_log->append_chatmessage( - QString(), f_message, - ao_app->get_color("debug_log_color", "courtroom_fonts.ini").name()); + ui_debug_log->append_chatmessage(colors.value(type, "info"), msg, QString(), ao_app->get_color(color_id, "courtroom_fonts.ini").name()); } -void Courtroom::append_server_chatmessage(QString p_name, QString p_message, - QString p_color) +void Courtroom::append_server_chatmessage(QString p_name, QString p_message, QString p_color) { QString color = "#000000"; if (p_color == "0") - color = ao_app->get_color("ms_chatlog_sender_color", "courtroom_fonts.ini") - .name(); + { + color = ao_app->get_color("ms_chatlog_sender_color", "courtroom_fonts.ini").name(); + } if (p_color == "1") - color = - ao_app->get_color("server_chatlog_sender_color", "courtroom_fonts.ini") - .name(); - if (!ao_app->auth_packet_supported && p_message == "Logged in as a moderator.") { + { + color = ao_app->get_color("server_chatlog_sender_color", "courtroom_fonts.ini").name(); + } + if (!ao_app->auth_packet_supported && p_message == "Logged in as a moderator.") + { // Emulate successful authentication on_authentication_state_received(1); } ui_server_chatlog->append_chatmessage(p_name, p_message, color); - if (Options::getInstance().logToTextFileEnabled() && !ao_app->log_filename.isEmpty()) { + if (Options::getInstance().logToTextFileEnabled() && !ao_app->log_filename.isEmpty()) + { QString full = "[OOC][" + QDateTime::currentDateTimeUtc().toString() + "] " + p_name + ": " + p_message; ao_app->append_to_file(full, ao_app->log_filename, true); } @@ -1814,27 +1898,46 @@ void Courtroom::append_server_chatmessage(QString p_name, QString p_message, void Courtroom::on_authentication_state_received(int p_state) { - if (p_state >= 1) { + if (p_state >= 1) + { ui_guard->show(); append_server_chatmessage(tr("CLIENT"), tr("You were granted the Disable Modcalls button."), "1"); } - else if (p_state == 0) { + else if (p_state == 0) + { append_server_chatmessage(tr("CLIENT"), tr("Login unsuccessful."), "1"); } - else if (p_state < 0) { + else if (p_state < 0) + { ui_guard->hide(); append_server_chatmessage(tr("CLIENT"), tr("You were logged out."), "1"); } } +Courtroom::JudgeState Courtroom::get_judge_state() +{ + return judge_state; +} + +void Courtroom::set_judge_state(JudgeState new_state) +{ + judge_state = new_state; +} + +void Courtroom::set_judge_buttons() +{ + show_judge_controls(ao_app->get_pos_is_judge(current_side)); +} + void Courtroom::on_chat_return_pressed() { if (is_muted) + { return; + } ui_ic_chat_message->blockSignals(true); - QTimer::singleShot(Options::getInstance().chatRateLimit(), this, - [this] { ui_ic_chat_message->blockSignals(false); }); + QTimer::singleShot(Options::getInstance().chatRateLimit(), this, [this] { ui_ic_chat_message->blockSignals(false); }); // MS# // deskmod# // pre-emote# @@ -1865,24 +1968,38 @@ void Courtroom::on_chat_return_pressed() int f_emote_mod = ao_app->get_emote_mod(current_char, current_emote); if (current_side == "") + { f_side = ao_app->get_char_side(current_char); + } else + { f_side = current_side; + } int f_desk_mod = DESK_SHOW; - if (ao_app->desk_mod_supported) { + if (ao_app->desk_mod_supported) + { f_desk_mod = ao_app->get_desk_mod(current_char, current_emote); - if (!ao_app->expanded_desk_mods_supported) { + if (!ao_app->expanded_desk_mods_supported) + { if (f_desk_mod == DESK_PRE_ONLY_EX || f_desk_mod == DESK_PRE_ONLY) + { f_desk_mod = DESK_HIDE; + } else if (f_desk_mod == DESK_EMOTE_ONLY_EX || f_desk_mod == DESK_EMOTE_ONLY) + { f_desk_mod = DESK_SHOW; + } } if (f_desk_mod == -1 && (f_emote_mod == 5 || f_emote_mod == 6)) // workaround for inis that broke after deprecating "chat" + { f_desk_mod = DESK_HIDE; + } else if (f_desk_mod == -1) + { f_desk_mod = DESK_SHOW; + } } packet_contents.append(QString::number(f_desk_mod)); @@ -1891,55 +2008,67 @@ void Courtroom::on_chat_return_pressed() QString f_sfx = "1"; int f_sfx_delay = get_char_sfx_delay(); -// EMOTE MOD OVERRIDES: + // EMOTE MOD OVERRIDES: // Emote_mod 2 is only used by objection check later, having it in the char.ini does nothing - if (f_emote_mod == 2) { + if (f_emote_mod == 2) + { f_emote_mod = PREANIM; } // No clue what emote_mod 3 is even supposed to be. - if (f_emote_mod == 3) { + if (f_emote_mod == 3) + { f_emote_mod = IDLE; } // Emote_mod 4 seems to be a legacy bugfix that just refers it to emote_mod 5 which is zoom emote - if (f_emote_mod == 4) { + if (f_emote_mod == 4) + { f_emote_mod = ZOOM; } // If we have "pre" on, and immediate is not checked - if (ui_pre->isChecked() && !ui_immediate->isChecked()) { + if (ui_pre->isChecked() && !ui_immediate->isChecked()) + { // Turn idle into preanim - if (f_emote_mod == IDLE) { + if (f_emote_mod == IDLE) + { f_emote_mod = PREANIM; } // Turn zoom into preanim zoom - else if (f_emote_mod == ZOOM && ao_app->prezoom_supported) { + else if (f_emote_mod == ZOOM && ao_app->prezoom_supported) + { f_emote_mod = PREANIM_ZOOM; } // Play the sfx f_sfx = get_char_sfx(); } // If we have "pre" off, or immediate is checked - else { + else + { // Turn preanim into idle - if (f_emote_mod == PREANIM) { + if (f_emote_mod == PREANIM) + { f_emote_mod = IDLE; } // Turn preanim zoom into zoom - else if (f_emote_mod == PREANIM_ZOOM) { + else if (f_emote_mod == PREANIM_ZOOM) + { f_emote_mod = ZOOM; } // Play the sfx if pre is checked - if (ui_pre->isChecked()) { + if (ui_pre->isChecked()) + { f_sfx = get_char_sfx(); } } // Custom sfx override via sound list dropdown. - if (!custom_sfx.isEmpty() || ui_sfx_dropdown->currentIndex() != 0) { + if (!custom_sfx.isEmpty() || ui_sfx_dropdown->currentIndex() != 0) + { f_sfx = get_char_sfx(); // We have a custom sfx but we're on idle emotes. // Turn them into pre so the sound plays if client setting sfx_on_idle is enabled. - if (Options::getInstance().playSelectedSFXOnIdle() && (f_emote_mod == IDLE || f_emote_mod == ZOOM)) { + if (Options::getInstance().playSelectedSFXOnIdle() && (f_emote_mod == IDLE || f_emote_mod == ZOOM)) + { // We turn idle into preanim, but make it not send a pre animation f_pre = ""; // Set sfx delay to 0 so the sfx plays immediately @@ -1967,40 +2096,56 @@ void Courtroom::on_chat_return_pressed() QString f_obj_state; - if ((objection_state == 4 && !ao_app->custom_objection_supported) || - (objection_state < 0)) + if ((objection_state == 4 && !ao_app->custom_objection_supported) || (objection_state < 0)) + { f_obj_state = "0"; - else if (objection_custom != "" && objection_state == 4) { - f_obj_state = QString::number(objection_state) + "&" + - objection_custom; // we add the name of the objection so the - // packet is like: 4&(name of custom obj) + } + else if (objection_custom != "" && objection_state == 4) + { + f_obj_state = QString::number(objection_state) + "&" + objection_custom; // we add the name of the objection so the + // packet is like: 4&(name of custom obj) } else + { f_obj_state = QString::number(objection_state); + } // We're doing an Objection (custom objections not yet supported) if (objection_state == 2 && Options::getInstance().objectionStopMusic()) + { music_stop(true); + } packet_contents.append(f_obj_state); if (is_presenting_evidence) + { // the evidence index is shifted by 1 because 0 is no evidence per legacy // standards besides, older clients crash if we pass -1 packet_contents.append(QString::number(current_evidence + 1)); + } else + { packet_contents.append("0"); + } QString f_flip; - if (ao_app->flipping_supported) { + if (ao_app->flipping_supported) + { if (ui_flip->isChecked()) + { f_flip = "1"; + } else + { f_flip = "0"; + } } else + { f_flip = QString::number(m_cid); + } packet_contents.append(f_flip); @@ -2009,78 +2154,96 @@ void Courtroom::on_chat_return_pressed() QString f_text_color; if (text_color < 0) + { f_text_color = "0"; + } else if (text_color >= max_colors) + { f_text_color = "0"; + } else + { f_text_color = QString::number(text_color); + } packet_contents.append(f_text_color); // If the server we're on supports CCCC stuff, we should use it! - if (ao_app->cccc_ic_supported) { + if (ao_app->cccc_ic_supported) + { // If there is a showname entered, use that -- else, just send an empty // packet-part. - if (!ui_ic_chat_name->text().isEmpty()) { + if (!ui_ic_chat_name->text().isEmpty()) + { packet_contents.append(ui_ic_chat_name->text()); } - else { + else + { packet_contents.append(""); } // Similarly, we send over whom we're paired with, unless we have chosen // ourselves. Or a charid of -1 or lower, through some means. - if (other_charid > -1 && other_charid != m_cid) { + if (other_charid > -1 && other_charid != m_cid) + { QString packet = QString::number(other_charid); if (ao_app->effects_supported) // Only servers with effects enabled will - // support pair reordering + // support pair reordering + { packet += "^" + QString::number(pair_order); + } packet_contents.append(packet); } - else { + else + { packet_contents.append("-1"); } // Send the offset as it's gonna be used regardless - if(ao_app->y_offset_supported) - packet_contents.append(QString::number(char_offset) + "&" + QString::number(char_vert_offset)); + if (ao_app->y_offset_supported) + { + packet_contents.append(QString::number(char_offset) + "&" + QString::number(char_vert_offset)); + } else - packet_contents.append(QString::number(char_offset)); + { + packet_contents.append(QString::number(char_offset)); + } // Finally, we send over if we want our pres to not interrupt. - if (ui_immediate->isChecked() && ui_pre->isChecked()) { + if (ui_immediate->isChecked() && ui_pre->isChecked()) + { packet_contents.append("1"); } - else { + else + { packet_contents.append("0"); } } // If the server we're on supports Looping SFX and Screenshake, use it if the // emote uses it. - if (ao_app->looping_sfx_supported) { - packet_contents.append( - ao_app->get_sfx_looping(current_char, current_emote)); + if (ao_app->looping_sfx_supported) + { + packet_contents.append(ao_app->get_sfx_looping(current_char, current_emote)); packet_contents.append(QString::number(screenshake_state)); QString pre_emote = ao_app->get_pre_emote(current_char, current_emote); QString emote = ao_app->get_emote(current_char, current_emote); QStringList emotes_to_check = {pre_emote, "(b)" + emote, "(a)" + emote}; - QStringList effects_to_check = {"_FrameScreenshake", "_FrameRealization", - "_FrameSFX"}; + QStringList effects_to_check = {"_FrameScreenshake", "_FrameRealization", "_FrameSFX"}; - foreach (QString f_effect, effects_to_check) { + foreach (QString f_effect, effects_to_check) + { QString packet; - foreach (QString f_emote, emotes_to_check) { + foreach (QString f_emote, emotes_to_check) + { packet += f_emote; - if (Options::getInstance().networkedFrameSfxEnabled()) { - QString sfx_frames = - ao_app - ->read_ini_tags( - ao_app->get_character_path(current_char, "char.ini"), - f_emote.append(f_effect)) - .join("|"); + if (Options::getInstance().networkedFrameSfxEnabled()) + { + QString sfx_frames = ao_app->read_ini_tags(ao_app->get_character_path(current_char, "char.ini"), f_emote.append(f_effect)).join("|"); if (sfx_frames != "") + { packet += "|" + sfx_frames; + } } packet += "^"; } @@ -2088,22 +2251,24 @@ void Courtroom::on_chat_return_pressed() } } - if (ao_app->additive_text_supported) { + if (ao_app->additive_text_supported) + { packet_contents.append(ui_additive->isChecked() ? "1" : "0"); } - if (ao_app->effects_supported) { - QString p_effect_folder = - ao_app->read_char_ini(current_char, "effects", "Options"); - QString fx_sound = - ao_app->get_effect_property(effect, current_char, p_effect_folder, "sound"); + if (ao_app->effects_supported) + { + QString p_effect_folder = ao_app->read_char_ini(current_char, "effects", "Options"); + QString fx_sound = ao_app->get_effect_property(effect, current_char, p_effect_folder, "sound"); // Don't overlap the two sfx - if (!ui_pre->isChecked() && (!custom_sfx.isEmpty() || ui_sfx_dropdown->currentIndex() == 1)) { + if (!ui_pre->isChecked() && (!custom_sfx.isEmpty() || ui_sfx_dropdown->currentIndex() == 1)) + { fx_sound = "0"; } packet_contents.append(effect + "|" + p_effect_folder + "|" + fx_sound); - if (!Options::getInstance().clearEffectsDropdownOnPlayEnabled() && !ao_app->get_effect_property(effect, current_char, p_effect_folder, "sticky").startsWith("true")) { + if (!Options::getInstance().clearEffectsDropdownOnPlayEnabled() && !ao_app->get_effect_property(effect, current_char, p_effect_folder, "sticky").startsWith("true")) + { ui_effects_dropdown->blockSignals(true); ui_effects_dropdown->setCurrentIndex(0); ui_effects_dropdown->blockSignals(false); @@ -2111,14 +2276,16 @@ void Courtroom::on_chat_return_pressed() } } - ao_app->send_server_packet(new AOPacket("MS", packet_contents)); + ao_app->send_server_packet(AOPacket("MS", packet_contents)); } void Courtroom::reset_ui() { ui_ic_chat_message->clear(); if (ui_additive->isChecked()) + { ui_ic_chat_message->insert(" "); + } objection_state = 0; realization_state = 0; screenshake_state = 0; @@ -2132,7 +2299,8 @@ void Courtroom::reset_ui() ui_evidence_present->set_image("present"); // If sticky sounds is disabled and we either have SFX on Idle enabled, or our Preanim checkbox is checked - if (!Options::getInstance().clearSoundsDropdownOnPlayEnabled() && (Options::getInstance().playSelectedSFXOnIdle() || ui_pre->isChecked())) { + if (!Options::getInstance().clearSoundsDropdownOnPlayEnabled() && (Options::getInstance().playSelectedSFXOnIdle() || ui_pre->isChecked())) + { // Reset the SFX Dropdown to "Default" ui_sfx_dropdown->setCurrentIndex(0); ui_sfx_remove->hide(); @@ -2140,8 +2308,10 @@ void Courtroom::reset_ui() } // If sticky preanims is disabled if (!Options::getInstance().clearPreOnPlayEnabled()) + { // Turn off our Preanim checkbox ui_pre->setChecked(false); + } } void Courtroom::chatmessage_enqueue(QStringList p_contents) @@ -2150,21 +2320,29 @@ void Courtroom::chatmessage_enqueue(QStringList p_contents) // amount of packages, we'll check if it has at least 15. // That was the original chatmessage_size. if (p_contents.size() < MS_MINIMUM) + { return; + } // Check the validity of the character ID we got int f_char_id = p_contents[CHAR_ID].toInt(); if (f_char_id < -1 || f_char_id >= char_list.size()) + { return; + } // We muted this char, gtfo if (mute_map.value(f_char_id)) + { return; + } // Use null showname if packet does not support 2.6+ extensions QString showname = QString(); if (SHOWNAME < p_contents.size()) + { showname = p_contents[SHOWNAME]; + } // if the char ID matches our client's char ID (most likely, this is our message coming back to us) bool sender = f_char_id == m_cid; @@ -2173,23 +2351,23 @@ void Courtroom::chatmessage_enqueue(QStringList p_contents) LogMode log_mode = IO_ONLY; // User-created blankpost - if (p_contents[MESSAGE].trimmed().isEmpty()) { + if (p_contents[MESSAGE].trimmed().isEmpty()) + { // Turn it into true blankpost p_contents[MESSAGE] = ""; } // If we determine we sent this message - if (sender) { + if (sender) + { // Reset input UI elements, clear input box, etc. reset_ui(); } // If we determine we sent this message, or we have desync enabled - if (sender || Options::getInstance().desynchronisedLogsEnabled()) { + if (sender || Options::getInstance().desynchronisedLogsEnabled()) + { // Initialize operation "message queue ghost" - log_chatmessage(p_contents[MESSAGE], p_contents[CHAR_ID].toInt(), - p_contents[SHOWNAME], p_contents[CHAR_NAME], - p_contents[OBJECTION_MOD], p_contents[EVIDENCE_ID].toInt(), - p_contents[TEXT_COLOR].toInt(), QUEUED, sender || Options::getInstance().desynchronisedLogsEnabled()); + log_chatmessage(p_contents[MESSAGE], p_contents[CHAR_ID].toInt(), p_contents[SHOWNAME], p_contents[CHAR_NAME], p_contents[OBJECTION_MOD], p_contents[EVIDENCE_ID].toInt(), p_contents[TEXT_COLOR].toInt(), QUEUED, sender || Options::getInstance().desynchronisedLogsEnabled()); } bool is_objection = false; @@ -2199,7 +2377,8 @@ void Courtroom::chatmessage_enqueue(QStringList p_contents) int objection_mod = p_contents[OBJECTION_MOD].split("&")[0].toInt(); is_objection = objection_mod >= 1 && objection_mod <= 5; // If this is an objection, nuke the queue - if (is_objection) { + if (is_objection) + { text_queue_timer->stop(); skip_chatmessage_queue(); } @@ -2214,7 +2393,9 @@ void Courtroom::chatmessage_enqueue(QStringList p_contents) bool start_queue = Options::getInstance().textStayTime() <= 0 || (text_state >= 2 && !text_queue_timer->isActive()); // Objections also immediately play the message if (start_queue || is_objection) + { chatmessage_dequeue(); // Process the message instantly + } // Otherwise, since a message is being parsed, chat_tick() should be called which will call dequeue once it's done. } @@ -2222,18 +2403,23 @@ void Courtroom::chatmessage_dequeue() { // Nothing to parse in the queue if (chatmessage_queue.isEmpty()) + { return; + } // Stop the text queue timer if (text_queue_timer->isActive()) + { text_queue_timer->stop(); + } unpack_chatmessage(chatmessage_queue.dequeue()); } void Courtroom::skip_chatmessage_queue() { - while (!chatmessage_queue.isEmpty()) { + while (!chatmessage_queue.isEmpty()) + { QStringList p_contents = chatmessage_queue.dequeue(); // if the char ID matches our client's char ID (most likely, this is our message coming back to us) bool sender = Options::getInstance().desynchronisedLogsEnabled() || p_contents[CHAR_ID].toInt() == m_cid; @@ -2243,17 +2429,19 @@ void Courtroom::skip_chatmessage_queue() void Courtroom::unpack_chatmessage(QStringList p_contents) { - for (int n_string = 0; n_string < MS_MAXIMUM; ++n_string) { + for (int n_string = 0; n_string < MS_MAXIMUM; ++n_string) + { // Note that we have added stuff that vanilla clients and servers simply // won't send. So now, we have to check if the thing we want even exists // amongst the packet's content. We also have to check if the server even // supports CCCC's IC features, or if it's just japing us. Also, don't // forget! A size 15 message will have indices from 0 to 14. - if (n_string < p_contents.size() && - (n_string < MS_MINIMUM || ao_app->cccc_ic_supported)) { + if (n_string < p_contents.size() && (n_string < MS_MINIMUM || ao_app->cccc_ic_supported)) + { m_chatmessage[n_string] = p_contents.at(n_string); } - else { + else + { m_chatmessage[n_string] = ""; } } @@ -2277,145 +2465,173 @@ void Courtroom::unpack_chatmessage(QStringList p_contents) ui_vp_evidence_display->reset(); // This chat msg is not objection so we're not waiting on the objection animation to finish to display the character. if (!handle_objection()) + { handle_ic_message(); + } } void Courtroom::log_chatmessage(QString f_message, int f_char_id, QString f_showname, QString f_char, QString f_objection_mod, int f_evi_id, int f_color, LogMode f_log_mode, bool sender) { // Display name will use the showname QString f_displayname = f_showname; - if (f_char_id != -1) { + if (f_char_id != -1) + { // Grab the char.ini showname f_showname = ao_app->get_showname(char_list.at(f_char_id).name); } // If display name is just whitespace, use the char.ini showname. if (f_displayname.trimmed().isEmpty()) + { f_displayname = f_showname; + } bool ghost = f_log_mode == QUEUED; // Detect if we're trying to log a blankpost - bool blankpost = (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.mid(0, last_ic_message.lastIndexOf(":")) == f_displayname); // the blankpost's showname is the same as ours + bool blankpost = (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.mid(0, last_ic_message.lastIndexOf(":")) == f_displayname); // the blankpost's showname is the same as ours bool selfname = f_char_id == m_cid; - if (log_ic_actions) { + if (log_ic_actions) + { // Check if a custom objection is in use int objection_mod = 0; - QString custom_objection = ""; - if (f_objection_mod.contains("4&")) { + QString custom_objection; + if (f_objection_mod.contains("4&")) + { objection_mod = 4; - custom_objection = f_objection_mod.split( - "4&")[1]; // takes the name of custom objection. + custom_objection = f_objection_mod.split("4&")[1]; // takes the name of custom objection. } - else { + else + { objection_mod = f_objection_mod.toInt(); } - //QString f_custom_theme = ao_app->get_chat(f_char); - if (objection_mod <= 4 && objection_mod >= 1) { + // QString f_custom_theme = ao_app->get_chat(f_char); + if (objection_mod <= 4 && objection_mod >= 1) + { blankpost = false; QString shout_message; - switch (objection_mod) { + switch (objection_mod) + { case 1: shout_message = ao_app->read_char_ini(f_char, "holdit_message", "Shouts"); if (shout_message == "") + { shout_message = tr("HOLD IT!"); + } break; case 2: shout_message = ao_app->read_char_ini(f_char, "objection_message", "Shouts"); if (shout_message == "") + { shout_message = tr("OBJECTION!"); + } break; case 3: shout_message = ao_app->read_char_ini(f_char, "takethat_message", "Shouts"); if (shout_message == "") + { shout_message = tr("TAKE THAT!"); + } break; // case 4 is AO2 only case 4: - if (custom_objection != "") { + if (custom_objection != "") + { shout_message = ao_app->read_char_ini(f_char, custom_objection.split('.')[0] + "_message", "Shouts"); if (shout_message == "") + { shout_message = custom_objection.split('.')[0]; + } } - else { + else + { shout_message = ao_app->read_char_ini(f_char, "custom_message", "Shouts"); if (shout_message == "") + { shout_message = tr("CUSTOM OBJECTION!"); + } } break; } - switch (f_log_mode) { - case IO_ONLY: - log_ic_text(f_char, f_displayname, shout_message, tr("shouts"), 0, selfname); - break; - case DISPLAY_AND_IO: - log_ic_text(f_char, f_displayname, shout_message, tr("shouts")); - append_ic_text(shout_message, f_displayname, tr("shouts"), - 0, selfname, QDateTime::currentDateTime(), false); - break; - case DISPLAY_ONLY: - case QUEUED: - if (!ghost && sender) - pop_ic_ghost(); - append_ic_text(shout_message, f_displayname, tr("shouts"), - 0, selfname, QDateTime::currentDateTime(), ghost); - break; + switch (f_log_mode) + { + case IO_ONLY: + log_ic_text(f_char, f_displayname, shout_message, tr("shouts"), 0, selfname); + break; + case DISPLAY_AND_IO: + log_ic_text(f_char, f_displayname, shout_message, tr("shouts")); + append_ic_text(shout_message, f_displayname, tr("shouts"), 0, selfname, QDateTime::currentDateTime(), false); + break; + case DISPLAY_ONLY: + case QUEUED: + if (!ghost && sender) + { + pop_ic_ghost(); + } + append_ic_text(shout_message, f_displayname, tr("shouts"), 0, selfname, QDateTime::currentDateTime(), ghost); + break; } } // If the evidence ID is in the valid range - if (f_evi_id > 0 && f_evi_id <= local_evidence_list.size()) { + if (f_evi_id > 0 && f_evi_id <= local_evidence_list.size()) + { blankpost = false; // Obtain the evidence name QString f_evi_name = local_evidence_list.at(f_evi_id - 1).name; - switch (f_log_mode) { - case IO_ONLY: - log_ic_text(f_showname, f_displayname, f_evi_name, tr("has presented evidence"), 0, selfname); - break; - case DISPLAY_AND_IO: - log_ic_text(f_showname, f_displayname, f_evi_name, tr("has presented evidence")); - append_ic_text(f_evi_name, f_displayname, tr("has presented evidence"), - 0, selfname, QDateTime::currentDateTime(), false); - break; - case DISPLAY_ONLY: - case QUEUED: - if (!ghost && sender) - pop_ic_ghost(); - append_ic_text(f_evi_name, f_displayname, tr("has presented evidence"), - 0, selfname, QDateTime::currentDateTime(), ghost); - break; + switch (f_log_mode) + { + case IO_ONLY: + log_ic_text(f_showname, f_displayname, f_evi_name, tr("has presented evidence"), 0, selfname); + break; + case DISPLAY_AND_IO: + log_ic_text(f_showname, f_displayname, f_evi_name, tr("has presented evidence")); + append_ic_text(f_evi_name, f_displayname, tr("has presented evidence"), 0, selfname, QDateTime::currentDateTime(), false); + break; + case DISPLAY_ONLY: + case QUEUED: + if (!ghost && sender) + { + pop_ic_ghost(); + } + append_ic_text(f_evi_name, f_displayname, tr("has presented evidence"), 0, selfname, QDateTime::currentDateTime(), ghost); + break; } } } // Do not display anything on a repeated blankpost if it's not a ghost - if (blankpost && !ghost) { + if (blankpost && !ghost) + { // Don't forget to clear the ghost if it's us if (sender) + { pop_ic_ghost(); + } return; } - switch (f_log_mode) { - case IO_ONLY: - log_ic_text(f_showname, f_displayname, f_message, "", f_color, selfname); - break; - case DISPLAY_AND_IO: - log_ic_text(f_showname, f_displayname, f_message, "", f_color, selfname); - append_ic_text(f_message, f_displayname, "", - f_color, selfname, QDateTime::currentDateTime(), false); - break; - case DISPLAY_ONLY: - case QUEUED: - if (!ghost && sender) - pop_ic_ghost(); - append_ic_text(f_message, f_displayname, "", - f_color, selfname, QDateTime::currentDateTime(), ghost); - break; + switch (f_log_mode) + { + case IO_ONLY: + log_ic_text(f_showname, f_displayname, f_message, "", f_color, selfname); + break; + case DISPLAY_AND_IO: + log_ic_text(f_showname, f_displayname, f_message, "", f_color, selfname); + append_ic_text(f_message, f_displayname, "", f_color, selfname, QDateTime::currentDateTime(), false); + break; + case DISPLAY_ONLY: + case QUEUED: + if (!ghost && sender) + { + pop_ic_ghost(); + } + append_ic_text(f_message, f_displayname, "", f_color, selfname, QDateTime::currentDateTime(), ghost); + break; } } @@ -2423,18 +2639,20 @@ bool Courtroom::handle_objection() { // Check if a custom objection is in use int objection_mod = 0; - QString custom_objection = ""; - if (m_chatmessage[OBJECTION_MOD].contains("4&")) { + QString custom_objection; + if (m_chatmessage[OBJECTION_MOD].contains("4&")) + { objection_mod = 4; - custom_objection = m_chatmessage[OBJECTION_MOD].split( - "4&")[1]; // takes the name of custom objection. + custom_objection = m_chatmessage[OBJECTION_MOD].split("4&")[1]; // takes the name of custom objection. } - else { + else + { objection_mod = m_chatmessage[OBJECTION_MOD].toInt(); } // if an objection is used - if (objection_mod <= 4 && objection_mod >= 1) { + if (objection_mod <= 4 && objection_mod >= 1) + { ui_vp_chatbox->setVisible(chatbox_always_show); ui_vp_message->setVisible(chatbox_always_show); ui_vp_chat_arrow->setVisible(chatbox_always_show); @@ -2442,48 +2660,44 @@ bool Courtroom::handle_objection() ui_vp_objection->set_static_duration(shout_static_time); ui_vp_objection->set_max_duration(shout_max_time); QString filename; - switch (objection_mod) { + switch (objection_mod) + { case 1: filename = "holdit_bubble"; - objection_player->play("holdit", m_chatmessage[CHAR_NAME], - ao_app->get_chat(m_chatmessage[CHAR_NAME])); + objection_player->play("holdit", m_chatmessage[CHAR_NAME], ao_app->get_chat(m_chatmessage[CHAR_NAME])); break; case 2: filename = "objection_bubble"; - objection_player->play("objection", m_chatmessage[CHAR_NAME], - ao_app->get_chat(m_chatmessage[CHAR_NAME])); + objection_player->play("objection", m_chatmessage[CHAR_NAME], ao_app->get_chat(m_chatmessage[CHAR_NAME])); break; case 3: filename = "takethat_bubble"; - objection_player->play("takethat", m_chatmessage[CHAR_NAME], - ao_app->get_chat(m_chatmessage[CHAR_NAME])); + objection_player->play("takethat", m_chatmessage[CHAR_NAME], ao_app->get_chat(m_chatmessage[CHAR_NAME])); break; // case 4 is AO2 only case 4: - if (custom_objection != "") { + if (custom_objection != "") + { filename = "custom_objections/" + custom_objection.left(custom_objection.lastIndexOf(".")); - objection_player->play(filename, - m_chatmessage[CHAR_NAME], - ao_app->get_chat(m_chatmessage[CHAR_NAME])); + objection_player->play(filename, m_chatmessage[CHAR_NAME], ao_app->get_chat(m_chatmessage[CHAR_NAME])); } - else { + else + { filename = "custom"; - objection_player->play( - "custom", m_chatmessage[CHAR_NAME], - ao_app->get_chat(m_chatmessage[CHAR_NAME])); + objection_player->play("custom", m_chatmessage[CHAR_NAME], ao_app->get_chat(m_chatmessage[CHAR_NAME])); } break; m_chatmessage[EMOTE_MOD] = QChar(PREANIM); } - ui_vp_objection->load_image( - filename, m_chatmessage[CHAR_NAME], - ao_app->get_chat(m_chatmessage[CHAR_NAME])); + ui_vp_objection->load_image(filename, m_chatmessage[CHAR_NAME], ao_app->get_chat(m_chatmessage[CHAR_NAME])); sfx_player->clear(); // Objection played! Cut all sfx. ui_vp_player_char->set_play_once(true); return true; } if (m_chatmessage[EMOTE] != "") + { display_character(); + } return false; } @@ -2499,25 +2713,27 @@ void Courtroom::display_character() ui_vp_message->hide(); ui_vp_chatbox->setVisible(chatbox_always_show); // Show it if chatbox always shows - if (Options::getInstance().characterStickerEnabled() && chatbox_always_show) { + if (Options::getInstance().characterStickerEnabled() && chatbox_always_show) + { ui_vp_sticker->load_image(m_chatmessage[CHAR_NAME]); } // Hide the face sticker - else { + else + { ui_vp_sticker->stop(); } // Arrange the netstrings of the frame SFX for the character to know about - if (!m_chatmessage[FRAME_SFX].isEmpty() && - Options::getInstance().networkedFrameSfxEnabled()) { + if (!m_chatmessage[FRAME_SFX].isEmpty() && Options::getInstance().networkedFrameSfxEnabled()) + { // ORDER IS IMPORTANT!! - QStringList netstrings = {m_chatmessage[FRAME_SCREENSHAKE], - m_chatmessage[FRAME_REALIZATION], - m_chatmessage[FRAME_SFX]}; - ui_vp_player_char->network_strings = netstrings; + QStringList netstrings = {m_chatmessage[FRAME_SCREENSHAKE], m_chatmessage[FRAME_REALIZATION], m_chatmessage[FRAME_SFX]}; + ui_vp_player_char->set_network_string(netstrings); } else - ui_vp_player_char->network_strings.clear(); + { + ui_vp_player_char->set_network_string(QStringList()); + } // Determine if we should flip the character or not ui_vp_player_char->set_flipped(m_chatmessage[FLIP].toInt() == 1); @@ -2528,13 +2744,15 @@ void Courtroom::display_character() void Courtroom::display_pair_character(QString other_charid, QString other_offset) { // If pair information exists - if (!other_charid.isEmpty()) { + if (!other_charid.isEmpty()) + { // Initialize the "ok" bool check to see if the toInt conversion succeeded bool ok; // Grab the charid of the pair int charid = other_charid.split("^")[0].toInt(&ok); // If the charid is an int and is valid... - if (ok && charid > -1) { + if (ok && charid > -1) + { // Show the pair character ui_vp_sideplayer_char->show(); // Obtain the offsets, splitting it up by & char @@ -2542,28 +2760,29 @@ void Courtroom::display_pair_character(QString other_charid, QString other_offse int offset_x; int offset_y; // If we only got one number... - if (offsets.length() <= 1) { + if (offsets.length() <= 1) + { // That's just the X offset. Make Y offset 0. offset_x = other_offset.toInt(); offset_y = 0; } - else { + else + { // We got two numbers, set x and y offsets! offset_x = offsets[0].toInt(); offset_y = offsets[1].toInt(); } // Move pair character according to the offsets - ui_vp_sideplayer_char->move(ui_viewport->width() * offset_x / 100, - ui_viewport->height() * offset_y / 100); + ui_vp_sideplayer_char->move(ui_viewport->width() * offset_x / 100, ui_viewport->height() * offset_y / 100); // Split the charid according to the ^ to determine if we have "ordering" info QStringList args = other_charid.split("^"); - if (args.size() > - 1) // This ugly workaround is so we don't make an extra packet just - // for this purpose. Rewrite pairing when? + if (args.size() > 1) // This ugly workaround is so we don't make an extra packet just + // for this purpose. Rewrite pairing when? { // Change the order of appearance based on the pair order variable int order = args.at(1).toInt(); - switch (order) { + switch (order) + { case 0: // Our character is in front ui_vp_sideplayer_char->stackUnder(ui_vp_player_char); break; @@ -2576,39 +2795,47 @@ void Courtroom::display_pair_character(QString other_charid, QString other_offse } // Flip the pair character if (ao_app->flipping_supported && m_chatmessage[OTHER_FLIP].toInt() == 1) + { ui_vp_sideplayer_char->set_flipped(true); + } else + { ui_vp_sideplayer_char->set_flipped(false); + } // 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); - } + ui_vp_sideplayer_char->load_image(filename, m_chatmessage[OTHER_NAME], 0, false); } + } } void Courtroom::handle_emote_mod(int emote_mod, bool p_immediate) { // Deal with invalid emote modifiers - if (emote_mod != IDLE && emote_mod != PREANIM && emote_mod != ZOOM && emote_mod != PREANIM_ZOOM) { + if (emote_mod != IDLE && emote_mod != PREANIM && emote_mod != ZOOM && emote_mod != PREANIM_ZOOM) + { // If emote mod is 4... - if (emote_mod == 4) { + if (emote_mod == 4) + { emote_mod = PREANIM_ZOOM; // Addresses issue with an old bug that sent the wrong - // emote modifier for zoompre + // emote modifier for zoompre } - else if (emote_mod == 2) { + else if (emote_mod == 2) + { // Addresses the deprecated "objection preanim" emote_mod = PREANIM; } - else { + else + { emote_mod = IDLE; // Reset emote mod to 0 } } // Handle the emote mod - switch (emote_mod) { + switch (emote_mod) + { case PREANIM: case PREANIM_ZOOM: // play preanim that makes the chatbox wait for it to finish. @@ -2635,7 +2862,10 @@ void Courtroom::handle_emote_mod(int emote_mod, bool p_immediate) } } -void Courtroom::objection_done() { handle_ic_message(); } +void Courtroom::objection_done() +{ + handle_ic_message(); +} void Courtroom::handle_ic_message() { @@ -2644,7 +2874,8 @@ void Courtroom::handle_ic_message() int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); bool immediate = m_chatmessage[IMMEDIATE].toInt() == 1; - if (m_chatmessage[EMOTE] != "") { + if (m_chatmessage[EMOTE] != "") + { // Display our own character display_character(); @@ -2653,7 +2884,8 @@ void Courtroom::handle_ic_message() ui_vp_sideplayer_char->move(0, 0); // If the emote_mod is not zooming - if (emote_mod != ZOOM && emote_mod != PREANIM_ZOOM) { + if (emote_mod != ZOOM && emote_mod != PREANIM_ZOOM) + { // Display the pair character display_pair_character(m_chatmessage[OTHER_CHARID], m_chatmessage[OTHER_OFFSET]); } @@ -2675,30 +2907,32 @@ void Courtroom::handle_ic_message() bool is_objection = objection_mod >= 1 && objection_mod <= 5; // If this is an objection, we'll need to interrupt our current message. if (is_objection) + { text_queue_timer->start(objection_threshold); + } } } void Courtroom::do_screenshake() { if (!Options::getInstance().shakeEnabled()) + { return; + } // This way, the animation is reset in such a way that last played screenshake // would return to its "final frame" properly. This properly resets all UI // elements without having to bother keeping track of "origin" positions. // Works great with the chat text being detached from the chat box! - screenshake_animation_group->setCurrentTime( - screenshake_animation_group->duration()); + screenshake_animation_group->setCurrentTime(screenshake_animation_group->duration()); screenshake_animation_group->clear(); - const QList<QWidget *> &affected_list = {ui_vp_background, ui_vp_player_char, - ui_vp_sideplayer_char, ui_vp_chatbox}; + const QList<QWidget *> &affected_list = {ui_vp_background, ui_vp_player_char, ui_vp_sideplayer_char, ui_vp_chatbox}; // I would prefer if this was its own "shake" function to be honest. - for (QWidget *ui_element : affected_list) { - QPropertyAnimation *screenshake_animation = - new QPropertyAnimation(ui_element, "pos", this); + for (QWidget *ui_element : affected_list) + { + QPropertyAnimation *screenshake_animation = new QPropertyAnimation(ui_element, "pos", this); QPoint pos_default = QPoint(ui_element->x(), ui_element->y()); int duration = 300; // How long does the screenshake last @@ -2709,7 +2943,8 @@ void Courtroom::do_screenshake() int max_deviation = 7 * (float(ui_viewport->height()) / 192); int maxframes = 15; // duration / frequency; screenshake_animation->setDuration(duration); - for (int frame = 0; frame < maxframes; frame++) { + for (int frame = 0; frame < maxframes; frame++) + { double fraction = double(frame * frequency) / duration; #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) int rand_x = max_deviation * (2 * (qrand() / (float)RAND_MAX) - 1) + 1; @@ -2731,69 +2966,68 @@ void Courtroom::do_screenshake() void Courtroom::do_flash() { if (!Options::getInstance().effectsEnabled()) + { return; + } QString f_char = m_chatmessage[CHAR_NAME]; QString f_custom_theme = ao_app->get_chat(f_char); do_effect("realization", "", f_char, f_custom_theme); } -void Courtroom::do_effect(QString fx_path, QString fx_sound, QString p_char, - QString p_folder) +void Courtroom::do_effect(QString fx_path, QString fx_sound, QString p_char, QString p_folder) { - if (fx_path == "") { + if (fx_path == "") + { return; } QString effect = ao_app->get_effect(fx_path, p_char, p_folder); - if (effect == "") { + if (effect == "") + { return; } - if (fx_sound != "") { + if (fx_sound != "") + { sfx_player->play(fx_sound); } // Only check if effects are disabled after playing the sound if it exists - if (!Options::getInstance().effectsEnabled()) { + if (!Options::getInstance().effectsEnabled()) + { return; } - ui_vp_effect->transform_mode = ao_app->get_scaling( - ao_app->get_effect_property(fx_path, p_char, p_folder, "scaling")); - ui_vp_effect->stretch = - ao_app->get_effect_property(fx_path, p_char, p_folder, "stretch") - .startsWith("true"); + ui_vp_effect->transform_mode = ao_app->get_scaling(ao_app->get_effect_property(fx_path, p_char, p_folder, "scaling")); + ui_vp_effect->stretch = ao_app->get_effect_property(fx_path, p_char, p_folder, "stretch").startsWith("true"); ui_vp_effect->set_flipped(ao_app->get_effect_property(fx_path, p_char, p_folder, "respect_flip").startsWith("true") && m_chatmessage[FLIP].toInt() == 1); - ui_vp_effect->set_play_once( - false); // The effects themselves dictate whether or not they're looping. - // Static effects will linger. + ui_vp_effect->set_play_once(false); // The effects themselves dictate whether or not they're looping. + // Static effects will linger. - bool looping = - ao_app->get_effect_property(fx_path, p_char, p_folder, "loop") - .startsWith("true"); + bool looping = ao_app->get_effect_property(fx_path, p_char, p_folder, "loop").startsWith("true"); - int max_duration = - ao_app->get_effect_property(fx_path, p_char, p_folder, "max_duration") - .toInt(); + int max_duration = ao_app->get_effect_property(fx_path, p_char, p_folder, "max_duration").toInt(); - bool cull = - ao_app->get_effect_property(fx_path, p_char, p_folder, "cull") - .startsWith("true"); + bool cull = ao_app->get_effect_property(fx_path, p_char, p_folder, "cull").startsWith("true"); // Possible values: "chat", "character", "behind" QString layer = ao_app->get_effect_property(fx_path, p_char, p_folder, "layer").toLower(); - if (layer == "behind"){ + if (layer == "behind") + { ui_vp_effect->setParent(ui_viewport); ui_vp_effect->stackUnder(ui_vp_player_char); } - else if (layer == "character") { + else if (layer == "character") + { ui_vp_effect->setParent(ui_viewport); ui_vp_effect->stackUnder(ui_vp_desk); } - else if (layer == "over") { + else if (layer == "over") + { ui_vp_effect->setParent(ui_viewport); ui_vp_effect->raise(); } - else { // if (layer == "chat") { + else + { // if (layer == "chat") { ui_vp_effect->setParent(this); ui_vp_effect->stackUnder(ui_vp_objection); } @@ -2801,20 +3035,24 @@ void Courtroom::do_effect(QString fx_path, QString fx_sound, QString p_char, int effect_x = 0; int effect_y = 0; // The effect is not parented to viewport, meaning we're overlaying ui elements - if (ui_vp_effect->parentWidget() != ui_viewport) { - //We need to add the viewport as an offset as effects are not bound to it. + if (ui_vp_effect->parentWidget() != ui_viewport) + { + // We need to add the viewport as an offset as effects are not bound to it. effect_x = ui_viewport->x(); effect_y = ui_viewport->y(); } // This effect respects the character offset settings - if (ao_app->get_effect_property(fx_path, p_char, p_folder, "respect_offset") == "true") { + if (ao_app->get_effect_property(fx_path, p_char, p_folder, "respect_offset") == "true") + { QStringList self_offsets = m_chatmessage[SELF_OFFSET].split("&"); int self_offset = self_offsets[0].toInt(); int self_offset_v; - if (self_offsets.length() <= 1) { + if (self_offsets.length() <= 1) + { self_offset_v = 0; } - else { + else + { self_offset_v = self_offsets[1].toInt(); } @@ -2838,21 +3076,23 @@ void Courtroom::play_char_sfx(QString sfx_name) void Courtroom::initialize_chatbox() { - int f_charid = m_chatmessage[CHAR_ID].toInt(); - if (f_charid >= 0 && f_charid < char_list.size() && - (m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked())) { + if (f_charid >= 0 && f_charid < char_list.size() && (m_chatmessage[SHOWNAME].isEmpty() || !ui_showname_enable->isChecked())) + { QString real_name = char_list.at(f_charid).name; QString f_showname = ao_app->get_showname(real_name); ui_vp_showname->setText(f_showname); } - else { + else + { ui_vp_showname->setText(m_chatmessage[SHOWNAME]); } QString customchar; if (Options::getInstance().customChatboxEnabled()) + { customchar = m_chatmessage[CHAR_NAME]; + } QString p_misc = ao_app->get_chat(customchar); set_size_and_pos(ui_vp_chatbox, "ao2_chatbox", p_misc); @@ -2864,8 +3104,7 @@ void Courtroom::initialize_chatbox() // We detached the text as parent from the chatbox so it doesn't get affected // by the screenshake. - ui_vp_message->move(ui_vp_message->x() + ui_vp_chatbox->x(), - ui_vp_message->y() + ui_vp_chatbox->y()); + ui_vp_message->move(ui_vp_message->x() + ui_vp_chatbox->x(), ui_vp_message->y() + ui_vp_chatbox->y()); ui_vp_message->setTextInteractionFlags(Qt::NoTextInteraction); if (ui_vp_showname->text().trimmed().isEmpty()) // Whitespace showname @@ -2876,31 +3115,32 @@ void Courtroom::initialize_chatbox() { ui_vp_showname->setVisible(true); if (!ui_vp_chatbox->set_image("chat", p_misc)) + { ui_vp_chatbox->set_image("chatbox", p_misc); - + } // Remember to set the showname font before the font metrics check. set_font(ui_vp_showname, "", "showname", customchar); - pos_size_type default_width = ao_app->get_element_dimensions( - "showname", "courtroom_design.ini", p_misc); - int extra_width = - ao_app - ->get_design_element("showname_extra_width", "courtroom_design.ini", - p_misc) - .toInt(); - QString align = ao_app - ->get_design_element("showname_align", - "courtroom_design.ini", p_misc) - .toLower(); + pos_size_type default_width = ao_app->get_element_dimensions("showname", "courtroom_design.ini", p_misc); + int extra_width = ao_app->get_design_element("showname_extra_width", "courtroom_design.ini", p_misc).toInt(); + QString align = ao_app->get_design_element("showname_align", "courtroom_design.ini", p_misc).toLower(); if (align == "right") + { ui_vp_showname->setAlignment(Qt::AlignRight); + } else if (align == "center") + { ui_vp_showname->setAlignment(Qt::AlignHCenter); + } else if (align == "justify") + { ui_vp_showname->setAlignment(Qt::AlignHCenter); + } else + { ui_vp_showname->setAlignment(Qt::AlignLeft); + } QFontMetrics fm(ui_vp_showname->font()); // Gotta support the slow paced ubuntu 18 STUCK IN 5.9.5!! @@ -2909,53 +3149,55 @@ void Courtroom::initialize_chatbox() #else int fm_width = fm.boundingRect((ui_vp_showname->text())).width(); #endif - if (extra_width > 0) { - QString current_path = ui_vp_chatbox->path.left(ui_vp_chatbox->path.lastIndexOf('.')); - if (fm_width > default_width.width && - ui_vp_chatbox->set_image(current_path + - "med")) // This text be big. Let's do some shenanigans. + if (extra_width > 0) + { + QString current_path = ui_vp_chatbox->file_name().left(ui_vp_chatbox->file_name().lastIndexOf('.')); + if (fm_width > default_width.width && ui_vp_chatbox->set_image(current_path + "med")) // This text be big. Let's do some shenanigans. { - ui_vp_showname->resize(default_width.width + extra_width, - ui_vp_showname->height()); - if (fm_width > ui_vp_showname->width() && - ui_vp_chatbox->set_image(current_path + "big")) // Biggest possible size for us. + ui_vp_showname->resize(default_width.width + extra_width, ui_vp_showname->height()); + if (fm_width > ui_vp_showname->width() && ui_vp_chatbox->set_image(current_path + "big")) // Biggest possible size for us. { - ui_vp_showname->resize( - static_cast<int>(default_width.width + (extra_width * 2)), - ui_vp_showname->height()); + ui_vp_showname->resize(static_cast<int>(default_width.width + (extra_width * 2)), ui_vp_showname->height()); } } else + { ui_vp_showname->resize(default_width.width, ui_vp_showname->height()); + } } - else { + else + { ui_vp_showname->resize(default_width.width, ui_vp_showname->height()); } } // This should probably be called only if any change from the last chat // arrow was actually detected. - pos_size_type design_ini_result = ao_app->get_element_dimensions( - "chat_arrow", "courtroom_design.ini", p_misc); - if (design_ini_result.width < 0 || design_ini_result.height < 0) { + pos_size_type design_ini_result = ao_app->get_element_dimensions("chat_arrow", "courtroom_design.ini", p_misc); + if (design_ini_result.width < 0 || design_ini_result.height < 0) + { qWarning() << "could not find \"chat_arrow\" in courtroom_design.ini"; ui_vp_chat_arrow->hide(); } - else { + else + { ui_vp_chat_arrow->move(design_ini_result.x + ui_vp_chatbox->x(), design_ini_result.y + ui_vp_chatbox->y()); - ui_vp_chat_arrow->combo_resize(design_ini_result.width, - design_ini_result.height); + ui_vp_chat_arrow->combo_resize(design_ini_result.width, design_ini_result.height); } QString font_name; QString chatfont = ao_app->get_chat_font(m_chatmessage[CHAR_NAME]); if (chatfont != "") + { font_name = chatfont; + } int f_pointsize = 0; int chatsize = ao_app->get_chat_size(m_chatmessage[CHAR_NAME]); if (chatsize > 0) + { f_pointsize = chatsize; + } set_font(ui_vp_message, "", "message", customchar, font_name, f_pointsize); } @@ -2963,12 +3205,14 @@ void Courtroom::handle_callwords() { // Quickly check through the message for the word_call (callwords) sfx QString f_message = m_chatmessage[MESSAGE]; - //No more file IO on every message. + // No more file IO on every message. QStringList call_words = Options::getInstance().callwords(); // Loop through each word in the call words list - for (const QString &word : qAsConst(call_words)) { + for (const QString &word : qAsConst(call_words)) + { // If our message contains that specific call word - if (f_message.contains(word, Qt::CaseInsensitive)) { + if (f_message.contains(word, Qt::CaseInsensitive)) + { // Play the call word sfx on the modcall_player sound container modcall_player->play(ao_app->get_court_sfx("word_call")); // Make the window flash @@ -2983,15 +3227,14 @@ void Courtroom::display_evidence_image() { QString side = m_chatmessage[SIDE]; int f_evi_id = m_chatmessage[EVIDENCE_ID].toInt(); - if (f_evi_id > 0 && f_evi_id <= local_evidence_list.size()) { + 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; - // 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"); - ui_vp_evidence_display->show_evidence(f_evi_id, f_image, is_left_side, - sfx_player->get_volume()); + // 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"); + ui_vp_evidence_display->show_evidence(f_evi_id, f_image, is_left_side, sfx_player->get_volume()); } } @@ -3000,7 +3243,8 @@ void Courtroom::handle_ic_speaking() QString side = m_chatmessage[SIDE]; int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); // emote_mod 5 is zoom and emote_mod 6 is zoom w/ preanim. - if (emote_mod == ZOOM || emote_mod == PREANIM_ZOOM) { + if (emote_mod == ZOOM || emote_mod == PREANIM_ZOOM) + { // Hide the desks ui_vp_desk->hide(); @@ -3008,23 +3252,25 @@ void Courtroom::handle_ic_speaking() QString filename; // I still hate this hardcoding. If we're on pos pro, hlp and wit, use prosecution_speedlines. Otherwise, defense_speedlines. if (side == "pro" || side == "hlp" || side == "wit") + { filename = "prosecution_speedlines"; + } else + { filename = "defense_speedlines"; + } // We're zooming, so hide the pair character and ignore pair offsets. This ain't about them. ui_vp_sideplayer_char->hide(); - ui_vp_player_char->move_and_center(0,0); + ui_vp_player_char->move_and_center(0, 0); ui_vp_speedlines->load_image(filename, m_chatmessage[CHAR_NAME], ao_app->get_chat(m_chatmessage[CHAR_NAME])); } // Check if this is a talking color (white text, etc.) - color_is_talking = - color_markdown_talking_list.at(m_chatmessage[TEXT_COLOR].toInt()); + color_is_talking = color_markdown_talking_list.at(m_chatmessage[TEXT_COLOR].toInt()); QString filename; // If color is talking, and our state isn't already talking - if (color_is_talking && text_state == 1 && - anim_state < 2) + if (color_is_talking && text_state == 1 && anim_state < 2) { // Stop the previous animation and play the talking animation ui_vp_player_char->stop(); @@ -3034,8 +3280,7 @@ void Courtroom::handle_ic_speaking() // Set the anim state accordingly anim_state = 2; } - else if (anim_state < 3 && - anim_state != 3) // Set it to idle as we're not on that already + else if (anim_state < 3 && anim_state != 3) // Set it to idle as we're not on that already { // Stop the previous animation and play the idle animation ui_vp_player_char->stop(); @@ -3050,8 +3295,7 @@ void Courtroom::handle_ic_speaking() start_chat_ticking(); } -QString Courtroom::filter_ic_text(QString p_text, bool html, int target_pos, - int default_color) +QString Courtroom::filter_ic_text(QString p_text, bool html, int target_pos, int default_color) { QString p_text_escaped; @@ -3062,35 +3306,44 @@ QString Courtroom::filter_ic_text(QString p_text, bool html, int target_pos, // Text alignment shenanigans. Could make a dropdown for this later, too! QString align; - if (p_text.trimmed().startsWith("~~")) { + if (p_text.trimmed().startsWith("~~")) + { p_text.remove(p_text.indexOf("~~"), 2); - if (target_pos != -1) { + if (target_pos != -1) + { target_pos = qMax(0, target_pos - 2); } align = "center"; } - else if (p_text.trimmed().startsWith("~>")) { + else if (p_text.trimmed().startsWith("~>")) + { p_text.remove(p_text.indexOf("~>"), 2); - if (target_pos != -1) { + if (target_pos != -1) + { target_pos = qMax(0, target_pos - 2); } align = "right"; } - else if (p_text.trimmed().startsWith("<>")) { + else if (p_text.trimmed().startsWith("<>")) + { p_text.remove(p_text.indexOf("<>"), 2); - if (target_pos != -1) { + if (target_pos != -1) + { target_pos = qMax(0, target_pos - 2); } align = "justify"; } // If html is enabled, prepare this text to be all ready for it. - if (html) { + if (html) + { ic_color_stack.push(default_color); QString appendage = "<font color=\"$c" + QString::number(default_color) + "\">"; if (!align.isEmpty()) + { appendage.prepend("<div align=" + align + ">"); + } p_text_escaped.insert(check_pos_escaped, appendage); check_pos_escaped += appendage.size(); @@ -3099,7 +3352,8 @@ QString Courtroom::filter_ic_text(QString p_text, bool html, int target_pos, // Current issue: does not properly escape html stuff. // Solution: probably parse p_text and export into a different string // separately, perform some mumbo jumbo to properly adjust string indexes. - while (check_pos < p_text.size()) { + while (check_pos < p_text.size()) + { QString f_rest = p_text.right(p_text.size() - check_pos); QTextBoundaryFinder tbf(QTextBoundaryFinder::Grapheme, f_rest); QString f_character; @@ -3109,9 +3363,13 @@ QString Courtroom::filter_ic_text(QString p_text, bool html, int target_pos, tbf.toNextBoundary(); if (tbf.position() == -1) + { f_character = f_rest; + } else + { f_character = f_rest.left(tbf.position()); + } // if (f_character == "&") //oh shit it's probably an escaped html // { @@ -3128,7 +3386,8 @@ QString Courtroom::filter_ic_text(QString p_text, bool html, int target_pos, f_char_bytes = f_char_length = f_character.length(); - if (html) { + if (html) + { f_character = f_character.toHtmlEscaped(); f_char_length = f_character.length(); } @@ -3137,43 +3396,50 @@ QString Courtroom::filter_ic_text(QString p_text, bool html, int target_pos, bool is_end = false; bool skip = false; - if (!parse_escape_seq) { - if (f_character == "\\") { + if (!parse_escape_seq) + { + if (f_character == "\\") + { parse_escape_seq = true; skip = true; } // Nothing related to colors here - else if (f_character == "{" || - f_character == - "}") //|| f_character == "@" || f_character == "$") + else if (f_character == "{" || f_character == "}") //|| f_character == "@" || f_character == "$") { skip = true; } // Parse markdown colors - else { - for (int c = 0; c < max_colors; ++c) { + else + { + for (int c = 0; c < max_colors; ++c) + { // Clear the stored optimization information QString markdown_start = color_markdown_start_list.at(c); QString markdown_end = color_markdown_end_list.at(c); - if (html) { + if (html) + { markdown_start = markdown_start.toHtmlEscaped(); markdown_end = markdown_end.toHtmlEscaped(); } bool markdown_remove = color_markdown_remove_list.at(c); if (markdown_start.isEmpty()) // Not defined + { continue; + } - if (markdown_end.isEmpty() || - markdown_end == markdown_start) //"toggle switch" type + if (markdown_end.isEmpty() || markdown_end == markdown_start) //"toggle switch" type { - if (f_character == markdown_start) { - if (html) { - if (!ic_color_stack.empty() && ic_color_stack.top() == c && - default_color != c) { + if (f_character == markdown_start) + { + if (html) + { + if (!ic_color_stack.empty() && ic_color_stack.top() == c && default_color != c) + { ic_color_stack.pop(); // Cease our coloring is_end = true; } - else { + else + { ic_color_stack.push(c); // Begin our coloring } color_update = true; @@ -3182,15 +3448,17 @@ QString Courtroom::filter_ic_text(QString p_text, bool html, int target_pos, break; // Prevent it from looping forward for whatever reason } } - else if (f_character == markdown_start || - (f_character == markdown_end && !ic_color_stack.empty() && - ic_color_stack.top() == c)) { - if (html) { - if (f_character == markdown_end) { + else if (f_character == markdown_start || (f_character == markdown_end && !ic_color_stack.empty() && ic_color_stack.top() == c)) + { + if (html) + { + if (f_character == markdown_end) + { ic_color_stack.pop(); // Cease our coloring is_end = true; } - else if (f_character == markdown_start) { + else if (f_character == markdown_start) + { ic_color_stack.push(c); // Begin our coloring } color_update = true; @@ -3200,20 +3468,22 @@ QString Courtroom::filter_ic_text(QString p_text, bool html, int target_pos, } } // Parse the newest color stack - if (color_update && (target_pos <= -1 || check_pos < target_pos)) { - if (!parse_escape_seq) { + if (color_update && (target_pos <= -1 || check_pos < target_pos)) + { + if (!parse_escape_seq) + { QString appendage = "</font>"; if (!ic_color_stack.empty()) - appendage += - "<font color=\"$c" + QString::number(ic_color_stack.top()) + - "\">"; + { + appendage += "<font color=\"$c" + QString::number(ic_color_stack.top()) + "\">"; + } - if (is_end && !skip) { + if (is_end && !skip) + { p_text_escaped.insert(check_pos_escaped, f_character); // Add that char right now - check_pos_escaped += - f_char_length; // So the closing char is captured too + check_pos_escaped += f_char_length; // So the closing char is captured too skip = true; } p_text_escaped.insert(check_pos_escaped, appendage); @@ -3222,11 +3492,13 @@ QString Courtroom::filter_ic_text(QString p_text, bool html, int target_pos, } } } - else { + else + { if (f_character == "n") // \n, that's a line break son { QString appendage = "<br/>"; - if (!html) { + if (!html) + { // actual newline commented out // appendage = "\n"; // size = 1; //yeah guess what \n is a "single character" @@ -3238,48 +3510,55 @@ QString Courtroom::filter_ic_text(QString p_text, bool html, int target_pos, skip = true; } if (f_character == "s" || f_character == "f" || f_character == "p") // screenshake/flash/pause + { skip = true; + } parse_escape_seq = false; } // Make all chars we're not supposed to see invisible - if (target_pos > -1 && check_pos == target_pos) { - QString appendage = ""; - if (!ic_color_stack.empty()) { + if (target_pos > -1 && check_pos == target_pos) + { + QString appendage; + if (!ic_color_stack.empty()) + { if (!is_end) // Was our last coloring char ending the color stack or nah { // God forgive me for my transgressions but I have refactored this // whole thing about 25 times and having to refactor it again to more // elegantly support this will finally make me go insane. - color_is_talking = - color_markdown_talking_list.at(ic_color_stack.top()); + color_is_talking = color_markdown_talking_list.at(ic_color_stack.top()); } // Clean it up, we're done here while (!ic_color_stack.empty()) + { ic_color_stack.pop(); + } appendage += "</font>"; } - ic_color_stack.push( - -1); // Dummy colorstack push for maximum </font> appendage + ic_color_stack.push(-1); // Dummy colorstack push for maximum </font> appendage appendage += "<font color=\"#00000000\">"; p_text_escaped.insert(check_pos_escaped, appendage); check_pos_escaped += appendage.size(); } - if (!skip) { + if (!skip) + { p_text_escaped.insert(check_pos_escaped, f_character); check_pos_escaped += f_char_length; } check_pos += f_char_bytes; } - if (!ic_color_stack.empty() && html) { + if (!ic_color_stack.empty() && html) + { p_text_escaped.append("</font>"); } - if (html) { + if (html) + { // Example: https://regex101.com/r/oL4nM9/37 - this replaces // excessive/trailing/etc. whitespace with non-breaking space. I WOULD use // white-space: pre; stylesheet tag, but for whataver reason it doesn't work @@ -3287,28 +3566,30 @@ QString Courtroom::filter_ic_text(QString p_text, bool html, int target_pos, // memery to work, please do. p_text_escaped.replace(QRegularExpression("^\\s|(?<=\\s)\\s"), " "); if (!align.isEmpty()) + { p_text_escaped.append("</div>"); + } } return p_text_escaped; } -void Courtroom::log_ic_text(QString p_name, QString p_showname, - QString p_message, QString p_action, int p_color, bool p_selfname) +void Courtroom::log_ic_text(QString p_name, QString p_showname, QString p_message, QString p_action, int p_color, bool p_selfname) { - chatlogpiece log_entry(p_name, p_showname, p_message, p_action, p_color, p_selfname); + ChatLogPiece log_entry(p_name, p_showname, p_message, p_action, p_color, p_selfname); ic_chatlog_history.append(log_entry); if (Options::getInstance().logToTextFileEnabled() && !ao_app->log_filename.isEmpty()) + { ao_app->append_to_file(log_entry.get_full(), ao_app->log_filename, true); + } - while (ic_chatlog_history.size() > log_maximum_blocks && - log_maximum_blocks > 0) { + while (ic_chatlog_history.size() > log_maximum_blocks && log_maximum_blocks > 0) + { ic_chatlog_history.removeFirst(); } } -void Courtroom::append_ic_text(QString p_text, QString p_name, QString p_action, - int color, bool selfname, QDateTime timestamp, bool ghost) +void Courtroom::append_ic_text(QString p_text, QString p_name, QString p_action, int color, bool selfname, QDateTime timestamp, bool ghost) { QColor chatlog_color = ao_app->get_color("ic_chatlog_color", "courtroom_fonts.ini"); QTextCharFormat bold; @@ -3332,47 +3613,49 @@ void Courtroom::append_ic_text(QString p_text, QString p_name, QString p_action, const QTextCursor old_cursor = ui_ic_chatlog->textCursor(); const int old_scrollbar_value = ui_ic_chatlog->verticalScrollBar()->value(); const bool need_newline = !ui_ic_chatlog->document()->isEmpty(); - const int scrollbar_target_value = - log_goes_downwards ? ui_ic_chatlog->verticalScrollBar()->maximum() - : ui_ic_chatlog->verticalScrollBar()->minimum(); + const int scrollbar_target_value = log_goes_downwards ? ui_ic_chatlog->verticalScrollBar()->maximum() : ui_ic_chatlog->verticalScrollBar()->minimum(); - if (ghost) { + if (ghost) + { ghost_blocks++; chatlog_color.setAlpha(128); bold.setForeground(chatlog_color); normal.setForeground(chatlog_color); italics.setForeground(chatlog_color); } - else { + else + { last_ic_message = p_name + ":" + p_text; } - ui_ic_chatlog->moveCursor(log_goes_downwards ? QTextCursor::End - : QTextCursor::Start); + ui_ic_chatlog->moveCursor(log_goes_downwards ? QTextCursor::End : QTextCursor::Start); - if (!ghost && ghost_blocks > 0) { - for (int i = 0; i < ghost_blocks; ++i) { - ui_ic_chatlog->moveCursor(log_goes_downwards ? QTextCursor::PreviousBlock - : QTextCursor::NextBlock); + if (!ghost && ghost_blocks > 0) + { + for (int i = 0; i < ghost_blocks; ++i) + { + ui_ic_chatlog->moveCursor(log_goes_downwards ? QTextCursor::PreviousBlock : QTextCursor::NextBlock); } - ui_ic_chatlog->moveCursor(log_goes_downwards ? QTextCursor::EndOfBlock - : QTextCursor::StartOfBlock); + ui_ic_chatlog->moveCursor(log_goes_downwards ? QTextCursor::EndOfBlock : QTextCursor::StartOfBlock); } // Only prepend with newline if log goes downwards - if (log_goes_downwards && need_newline) { + if (log_goes_downwards && need_newline) + { ui_ic_chatlog->textCursor().insertBlock(format); } - // Timestamp if we're doing that meme - if (log_timestamp) { + if (log_timestamp) + { // Format the timestamp QTextCharFormat format = selfname ? selftimestamp_format : timestamp_format; - if (timestamp.isValid()) { - ui_ic_chatlog->textCursor().insertText( - "[" + timestamp.toString(log_timestamp_format) + "] ", format); - } else { + if (timestamp.isValid()) + { + ui_ic_chatlog->textCursor().insertText("[" + timestamp.toString(log_timestamp_format) + "] ", format); + } + else + { qCritical() << "could not insert invalid timestamp" << timestamp; } } @@ -3381,53 +3664,65 @@ void Courtroom::append_ic_text(QString p_text, QString p_name, QString p_action, QTextCharFormat name_format = selfname ? own_name : other_name; ui_ic_chatlog->textCursor().insertText(p_name, name_format); // Special case for stopping the music - if (p_action == tr("has stopped the music")) { + if (p_action == tr("has stopped the music")) + { ui_ic_chatlog->textCursor().insertText(" " + p_action + ".", normal); } // Make shout text bold - else if (p_action == tr("shouts") && log_ic_actions) { + else if (p_action == tr("shouts") && log_ic_actions) + { ui_ic_chatlog->textCursor().insertText(" " + p_action + " ", normal); - if (log_colors && !ghost) { - ui_ic_chatlog->textCursor().insertHtml( - "<b>" + - filter_ic_text(p_text, true, -1, 0) - .replace( - "$c0", - chatlog_color.name(QColor::HexArgb)) + - "</b>"); + if (log_colors && !ghost) + { + ui_ic_chatlog->textCursor().insertHtml("<b>" + filter_ic_text(p_text, true, -1, 0).replace("$c0", chatlog_color.name(QColor::HexArgb)) + "</b>"); } else + { ui_ic_chatlog->textCursor().insertText(" " + p_text, italics); + } } // If action not blank: - else if (p_action != "" && log_ic_actions) { + else if (p_action != "" && log_ic_actions) + { // Format the action in normal ui_ic_chatlog->textCursor().insertText(" " + p_action, normal); if (log_newline) + { // For some reason, we're forced to use <br> instead of the more sensible // \n. Why? Because \n is treated as a new Block instead of a soft newline // within a paragraph! ui_ic_chatlog->textCursor().insertHtml("<br>"); + } else + { ui_ic_chatlog->textCursor().insertText(": ", normal); + } // Format the result in italics ui_ic_chatlog->textCursor().insertText(p_text + ".", italics); } - else { + else + { if (log_newline) + { // For some reason, we're forced to use <br> instead of the more sensible // \n. Why? Because \n is treated as a new Block instead of a soft newline // within a paragraph! ui_ic_chatlog->textCursor().insertHtml("<br>"); + } else + { ui_ic_chatlog->textCursor().insertText(": ", normal); + } // Format the result according to html - if (log_colors) { + if (log_colors) + { QString p_text_filtered = filter_ic_text(p_text, true, -1, color); p_text_filtered = p_text_filtered.replace("$c0", chatlog_color.name(QColor::HexArgb)); - for (int c = 1; c < max_colors; ++c) { + for (int c = 1; c < max_colors; ++c) + { QColor color_result = default_color_rgb_list.at(c); - if (ghost) { + if (ghost) + { color_result.setAlpha(128); } p_text_filtered = p_text_filtered.replace("$c" + QString::number(c), color_result.name(QColor::HexArgb)); @@ -3435,55 +3730,62 @@ void Courtroom::append_ic_text(QString p_text, QString p_name, QString p_action, ui_ic_chatlog->textCursor().insertHtml(p_text_filtered); } else + { ui_ic_chatlog->textCursor().insertText(filter_ic_text(p_text, false), normal); + } } // Only append with newline if log goes upwards - if (!log_goes_downwards && need_newline) { + if (!log_goes_downwards && need_newline) + { ui_ic_chatlog->textCursor().insertBlock(format); } // If we got too many blocks in the current log, delete some. - while (ui_ic_chatlog->document()->blockCount() > log_maximum_blocks && - log_maximum_blocks > 0) { + while (ui_ic_chatlog->document()->blockCount() > log_maximum_blocks && log_maximum_blocks > 0) + { QTextCursor temp_curs = ui_ic_chatlog->textCursor(); - temp_curs.movePosition(log_goes_downwards ? QTextCursor::Start - : QTextCursor::End); + temp_curs.movePosition(log_goes_downwards ? QTextCursor::Start : QTextCursor::End); temp_curs.select(QTextCursor::BlockUnderCursor); temp_curs.removeSelectedText(); if (log_goes_downwards) + { temp_curs.deleteChar(); + } else + { temp_curs.deletePreviousChar(); + } } // Finally, scroll the scrollbar to the correct position. - if (old_cursor.hasSelection() || - old_scrollbar_value != scrollbar_target_value) { + if (old_cursor.hasSelection() || old_scrollbar_value != scrollbar_target_value) + { // The user has selected text or scrolled away from the bottom: maintain // position. ui_ic_chatlog->setTextCursor(old_cursor); ui_ic_chatlog->verticalScrollBar()->setValue(old_scrollbar_value); } - else { - ui_ic_chatlog->verticalScrollBar()->setValue( - log_goes_downwards ? ui_ic_chatlog->verticalScrollBar()->maximum() : 0); + else + { + ui_ic_chatlog->verticalScrollBar()->setValue(log_goes_downwards ? ui_ic_chatlog->verticalScrollBar()->maximum() : 0); } } void Courtroom::pop_ic_ghost() { QTextCursor ghost = ui_ic_chatlog->textCursor(); - ghost.movePosition(log_goes_downwards ? QTextCursor::End - : QTextCursor::Start); - for (int i = 1; i < ghost_blocks; ++i) { - ghost.movePosition(log_goes_downwards ? QTextCursor::PreviousBlock - : QTextCursor::NextBlock); + ghost.movePosition(log_goes_downwards ? QTextCursor::End : QTextCursor::Start); + for (int i = 1; i < ghost_blocks; ++i) + { + ghost.movePosition(log_goes_downwards ? QTextCursor::PreviousBlock : QTextCursor::NextBlock); } ghost.select(QTextCursor::BlockUnderCursor); ghost.removeSelectedText(); if (ghost_blocks <= 1 && !log_goes_downwards) + { ghost.deleteChar(); + } ghost_blocks--; } @@ -3498,13 +3800,17 @@ void Courtroom::play_preanim(bool immediate) int sfx_delay = m_chatmessage[SFX_DELAY].toInt() * time_mod; sfx_delay_timer->start(sfx_delay); - QString anim_to_find = - ao_app->get_image_suffix(ao_app->get_character_path(f_char, f_preanim)); - if (!file_exists(anim_to_find)) { + QString anim_to_find = ao_app->get_image_suffix(ao_app->get_character_path(f_char, f_preanim)); + if (!file_exists(anim_to_find)) + { if (immediate) + { anim_state = 4; + } else + { anim_state = 1; + } preanim_done(); qWarning() << "could not find preanim" << f_preanim << "for character" << f_char; return; @@ -3513,31 +3819,36 @@ void Courtroom::play_preanim(bool immediate) ui_vp_player_char->set_play_once(true); ui_vp_player_char->load_image(f_preanim, f_char, preanim_duration, true); - switch (m_chatmessage[DESK_MOD].toInt()) { - case DESK_EMOTE_ONLY_EX: - ui_vp_sideplayer_char->hide(); - ui_vp_player_char->move_and_center(0, 0); - [[fallthrough]]; - case DESK_EMOTE_ONLY: - case DESK_HIDE: - set_scene(false, m_chatmessage[SIDE]); - break; + switch (m_chatmessage[DESK_MOD].toInt()) + { + case DESK_EMOTE_ONLY_EX: + ui_vp_sideplayer_char->hide(); + ui_vp_player_char->move_and_center(0, 0); + [[fallthrough]]; + case DESK_EMOTE_ONLY: + case DESK_HIDE: + set_scene(false, m_chatmessage[SIDE]); + break; - case DESK_PRE_ONLY_EX: - case DESK_PRE_ONLY: - case DESK_SHOW: - set_scene(true, m_chatmessage[SIDE]); - break; + case DESK_PRE_ONLY_EX: + case DESK_PRE_ONLY: + case DESK_SHOW: + set_scene(true, m_chatmessage[SIDE]); + break; } - if (immediate) { + if (immediate) + { anim_state = 4; handle_ic_speaking(); } - else { + else + { anim_state = 1; if (stay_time >= 0) + { text_delay_timer->start(stay_time); + } } } @@ -3545,7 +3856,9 @@ void Courtroom::preanim_done() { // Currently, someone's talking over us mid-preanim... if (anim_state != 1 && anim_state != 4 && anim_state != 5) + { return; + } anim_state = 1; handle_ic_speaking(); @@ -3557,77 +3870,94 @@ void Courtroom::start_chat_ticking() // we need to ensure that the text isn't already ticking because this function // can be called by two logic paths if (text_state != 0) + { return; + } // Display the evidence display_evidence_image(); // handle expanded desk mods - switch(m_chatmessage[DESK_MOD].toInt()) { - case DESK_EMOTE_ONLY_EX: - set_self_offset(m_chatmessage[SELF_OFFSET]); - [[fallthrough]]; - case DESK_EMOTE_ONLY: - case DESK_SHOW: - set_scene(true, m_chatmessage[SIDE]); - break; + switch (m_chatmessage[DESK_MOD].toInt()) + { + case DESK_EMOTE_ONLY_EX: + set_self_offset(m_chatmessage[SELF_OFFSET]); + [[fallthrough]]; + case DESK_EMOTE_ONLY: + case DESK_SHOW: + set_scene(true, m_chatmessage[SIDE]); + break; - case DESK_PRE_ONLY_EX: - ui_vp_sideplayer_char->hide(); - ui_vp_player_char->move_and_center(0, 0); - [[fallthrough]]; - case DESK_PRE_ONLY: - case DESK_HIDE: - set_scene(false, m_chatmessage[SIDE]); - break; + case DESK_PRE_ONLY_EX: + ui_vp_sideplayer_char->hide(); + ui_vp_player_char->move_and_center(0, 0); + [[fallthrough]]; + case DESK_PRE_ONLY: + case DESK_HIDE: + set_scene(false, m_chatmessage[SIDE]); + break; } - if (m_chatmessage[EFFECTS] != "") { + if (m_chatmessage[EFFECTS] != "") + { QStringList fx_list = m_chatmessage[EFFECTS].split("|"); QString fx = fx_list[0]; QString fx_sound; QString fx_folder; if (fx_list.length() > 1) + { fx_sound = fx_list[1]; + } - if (fx_list.length() > 2) { + if (fx_list.length() > 2) + { fx_folder = fx_list[1]; fx_sound = fx_list[2]; } this->do_effect(fx, fx_sound, m_chatmessage[CHAR_NAME], fx_folder); } - else if (m_chatmessage[REALIZATION] == "1") { + else if (m_chatmessage[REALIZATION] == "1") + { this->do_flash(); sfx_player->play(ao_app->get_custom_realization(m_chatmessage[CHAR_NAME])); } int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); // text meme bonanza - if ((emote_mod == IDLE || emote_mod == ZOOM) && m_chatmessage[SCREENSHAKE] == "1") { + if ((emote_mod == IDLE || emote_mod == ZOOM) && m_chatmessage[SCREENSHAKE] == "1") + { this->do_screenshake(); } - if (m_chatmessage[MESSAGE].isEmpty()) { + if (m_chatmessage[MESSAGE].isEmpty()) + { // since the message is empty, it's technically done ticking text_state = 2; - if (m_chatmessage[ADDITIVE] == "1") { + if (m_chatmessage[ADDITIVE] == "1") + { // Cool behavior ui_vp_chatbox->show(); ui_vp_message->show(); } - else { + else + { ui_vp_chatbox->setVisible(chatbox_always_show); ui_vp_message->hide(); // Show it if chatbox always shows if (Options::getInstance().characterStickerEnabled() && chatbox_always_show) + { ui_vp_sticker->load_image(m_chatmessage[CHAR_NAME]); + } // Hide the face sticker - else { + else + { ui_vp_sticker->stop(); } } // If we're not already waiting on the next message, start the timer. We could be overriden if there's an objection planned. int delay = Options::getInstance().textStayTime(); if (delay > 0 && !text_queue_timer->isActive()) + { text_queue_timer->start(delay); + } return; } @@ -3635,9 +3965,12 @@ void Courtroom::start_chat_ticking() ui_vp_message->show(); if (Options::getInstance().characterStickerEnabled()) + { ui_vp_sticker->load_image(m_chatmessage[CHAR_NAME]); + } - if (m_chatmessage[ADDITIVE] != "1") { + if (m_chatmessage[ADDITIVE] != "1") + { ui_vp_message->clear(); real_tick_pos = 0; additive_previous = ""; @@ -3656,7 +3989,9 @@ void Courtroom::start_chat_ticking() last_misc = current_misc; current_misc = ao_app->get_chat(m_chatmessage[CHAR_NAME]); if (last_misc != current_misc || char_color_rgb_list.size() < max_colors) + { gen_char_rgb_list(current_misc); + } QString f_blips = ao_app->get_blips(m_chatmessage[CHAR_NAME]); blip_player->set_blips(f_blips); @@ -3679,54 +4014,60 @@ void Courtroom::chat_tick() ui_vp_player_char->set_static_duration(0); QString filename; - if (tick_pos >= f_message.size()) { + if (tick_pos >= f_message.size()) + { text_state = 2; // Check if we're a narrator msg - if (m_chatmessage[EMOTE] != "") { - if (anim_state < 3) { - QStringList c_paths = { - ao_app->get_image_suffix(ao_app->get_character_path(m_chatmessage[CHAR_NAME], "(c)" + m_chatmessage[EMOTE])), - ao_app->get_image_suffix(ao_app->get_character_path(m_chatmessage[CHAR_NAME], "(c)/" + m_chatmessage[EMOTE])) - }; + if (m_chatmessage[EMOTE] != "") + { + if (anim_state < 3) + { + QStringList c_paths = {ao_app->get_image_suffix(ao_app->get_character_path(m_chatmessage[CHAR_NAME], "(c)" + m_chatmessage[EMOTE])), ao_app->get_image_suffix(ao_app->get_character_path(m_chatmessage[CHAR_NAME], "(c)/" + m_chatmessage[EMOTE]))}; // if there is a (c) animation for this emote and we haven't played it already - if (file_exists(ui_vp_player_char->find_image(c_paths)) &&(!c_played)) { + if (file_exists(ui_vp_player_char->find_image(c_paths)) && (!c_played)) + { anim_state = 5; ui_vp_player_char->set_play_once(true); filename = "(c)" + m_chatmessage[EMOTE]; c_played = true; } - else { + else + { anim_state = 3; ui_vp_player_char->set_play_once(false); filename = "(a)" + m_chatmessage[EMOTE]; } - ui_vp_player_char->load_image(filename, m_chatmessage[CHAR_NAME], 0, - false); + ui_vp_player_char->load_image(filename, m_chatmessage[CHAR_NAME], 0, false); } } else // We're a narrator msg + { anim_state = 3; + } QString f_char; QString f_custom_theme; - if (Options::getInstance().customChatboxEnabled()) { + if (Options::getInstance().customChatboxEnabled()) + { f_char = m_chatmessage[CHAR_NAME]; f_custom_theme = ao_app->get_chat(f_char); } 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()); - for (int c = 0; c < max_colors; ++c) { + 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)); } additive_previous = additive_previous + f_message_filtered; real_tick_pos = ui_vp_message->toPlainText().size(); - // If we're not already waiting on the next message, start the timer. We could be overriden if there's an objection planned. int delay = Options::getInstance().textStayTime(); if (delay > 0 && !text_queue_timer->isActive()) + { text_queue_timer->start(delay); + } // if we have instant objections disabled, and queue is not empty, check if next message after this is an objection. if (!Options::getInstance().objectionSkipQueueEnabled() && chatmessage_queue.size() > 0) @@ -3736,7 +4077,9 @@ void Courtroom::chat_tick() bool is_objection = objection_mod >= 1 && objection_mod <= 5; // If this is an objection, we'll need to interrupt our current message. if (is_objection) + { chatmessage_dequeue(); + } } return; } @@ -3747,9 +4090,12 @@ void Courtroom::chat_tick() QString f_rest = f_message; // Alignment characters - if (tick_pos < 2) { + if (tick_pos < 2) + { if (f_rest.startsWith("~~") || f_rest.startsWith("~>") || f_rest.startsWith("<>")) + { tick_pos += 2; + } } f_rest.remove(0, tick_pos); QTextBoundaryFinder tbf(QTextBoundaryFinder::Grapheme, f_rest); @@ -3760,52 +4106,70 @@ void Courtroom::chat_tick() tbf.toNextBoundary(); if (tbf.position() == -1) + { f_character = f_rest; + } else + { f_character = f_rest.left(tbf.position()); + } f_char_length = f_character.length(); tick_pos += f_char_length; // Escape character. - if (!next_character_is_not_special) { - if (f_character == "\\") { + if (!next_character_is_not_special) + { + if (f_character == "\\") + { next_character_is_not_special = true; formatting_char = true; } // Text speed modifier. - else if (f_character == "{") { + else if (f_character == "{") + { // ++, because it INCREASES delay! current_display_speed++; formatting_char = true; } - else if (f_character == "}") { + else if (f_character == "}") + { current_display_speed--; formatting_char = true; } - else { + else + { // Parse markdown colors - for (int c = 0; c < max_colors; ++c) { + for (int c = 0; c < max_colors; ++c) + { QString markdown_start = color_markdown_start_list.at(c); QString markdown_end = color_markdown_end_list.at(c); bool markdown_remove = color_markdown_remove_list.at(c); if (markdown_start.isEmpty()) + { continue; + } - if (f_character == markdown_start || f_character == markdown_end) { + if (f_character == markdown_start || f_character == markdown_end) + { if (markdown_remove) + { formatting_char = true; + } break; } } } } - else { + else + { if (f_character == "n") + { formatting_char = true; // it's a newline - if (f_character == "s") // Screenshake. + } + if (f_character == "s") // Screenshake. { this->do_screenshake(); formatting_char = true; @@ -3824,30 +4188,42 @@ void Courtroom::chat_tick() // Keep the speed at bay. if (current_display_speed < 0) + { current_display_speed = 0; + } else if (current_display_speed > 6) + { current_display_speed = 6; + } if (msg_delay == 0) + { msg_delay = text_crawl * message_display_mult[current_display_speed]; + } - if ((msg_delay <= 0 && - tick_pos < f_message.size() - 1) || - formatting_char) { + if ((msg_delay <= 0 && tick_pos < f_message.size() - 1) || formatting_char) + { if (f_character == "p") + { chat_tick_timer->start(100); // wait the pause lol + } else + { chat_tick_timer->start(0); // Don't bother rendering anything out as we're // doing the SPEED. (there's latency otherwise) - if (!formatting_char || f_character == "n" || f_character == "f" || - f_character == "s" || f_character == "p") + } + if (!formatting_char || f_character == "n" || f_character == "f" || f_character == "s" || f_character == "p") + { real_tick_pos += f_char_length; // Adjust the tick position for the // scrollbar convenience + } } - else { + else + { // Do the colors, gradual showing, etc. in here QString f_message_filtered = filter_ic_text(f_message, true, tick_pos, m_chatmessage[TEXT_COLOR].toInt()); - for (int c = 0; c < max_colors; ++c) { + 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)); } @@ -3871,24 +4247,26 @@ void Courtroom::chat_tick() // where ! is the blip sound int b_rate = blip_rate; // Overwhelming blip spam prevention, this method is more consistent than timers - if (msg_delay != 0 && msg_delay <= 25) { + if (msg_delay != 0 && msg_delay <= 25) + { // The default blip speed is 40ms, and if current msg_delay is 25ms, // the formula will result in the blip rate of: // 40/25 = 1.6 = 2 // And if it's faster than that: // 40/10 = 4 - b_rate = - qMax(b_rate, qRound(static_cast<float>(text_crawl) / - msg_delay)); + b_rate = qMax(b_rate, qRound(static_cast<float>(text_crawl) / msg_delay)); } - if ((blip_rate <= 0 && blip_ticker < 1) || (b_rate > 0 && blip_ticker % b_rate == 0)) { + if ((blip_rate <= 0 && blip_ticker < 1) || (b_rate > 0 && blip_ticker % b_rate == 0)) + { // ignoring white space unless blank_blip is enabled. - if (!formatting_char && (f_character != ' ' || blank_blip)) { + if (!formatting_char && (f_character != ' ' || blank_blip)) + { blip_player->blip_tick(); ++blip_ticker; } } - else { + else + { // Don't fully ignore whitespace still, keep ticking until // we reached the need to play a blip sound - we also just // need to wait for a letter to play it on. @@ -3896,35 +4274,32 @@ void Courtroom::chat_tick() } // Punctuation delayer, only kicks in on speed ticks less than }} - if (current_display_speed > 1 && punctuation_chars.contains(f_character)) { + if (current_display_speed > 1 && punctuation_chars.contains(f_character)) + { // Making the user have to wait any longer than 1.5 of the slowest speed // is downright unreasonable int max_delay = text_crawl * message_display_mult[6] * 1.5; msg_delay = qMin(max_delay, msg_delay * punctuation_modifier); } - if (m_chatmessage[EMOTE] != "") { + if (m_chatmessage[EMOTE] != "") + { // If this color is talking - if (color_is_talking && anim_state != 2 && - anim_state < - 4) // Set it to talking as we're not on that already (though we have - // to avoid interrupting a non-interrupted preanim) + if (color_is_talking && anim_state != 2 && anim_state < 4) // Set it to talking as we're not on that already (though we have + // to avoid interrupting a non-interrupted preanim) { ui_vp_player_char->stop(); ui_vp_player_char->set_play_once(false); filename = "(b)" + m_chatmessage[EMOTE]; - ui_vp_player_char->load_image(filename, m_chatmessage[CHAR_NAME], 0, - false); + ui_vp_player_char->load_image(filename, m_chatmessage[CHAR_NAME], 0, false); anim_state = 2; } - else if (!color_is_talking && anim_state < 3 && - anim_state != 3) // Set it to idle as we're not on that already + else if (!color_is_talking && anim_state < 3 && anim_state != 3) // Set it to idle as we're not on that already { ui_vp_player_char->stop(); ui_vp_player_char->set_play_once(false); filename = "(a)" + m_chatmessage[EMOTE]; - ui_vp_player_char->load_image(filename, m_chatmessage[CHAR_NAME], 0, - false); + ui_vp_player_char->load_image(filename, m_chatmessage[CHAR_NAME], 0, false); anim_state = 3; } } @@ -3936,18 +4311,20 @@ void Courtroom::chat_tick() void Courtroom::play_sfx() { QString sfx_name = m_chatmessage[SFX_NAME]; - if (m_chatmessage[SCREENSHAKE] == - "1") // Screenshake dependant on preanim sfx delay meme + if (m_chatmessage[SCREENSHAKE] == "1") // Screenshake dependant on preanim sfx delay meme { this->do_screenshake(); } if (sfx_name == "1") + { return; + } sfx_player->play(sfx_name); if (Options::getInstance().loopingSfx()) - sfx_player->set_looping( - ao_app->get_sfx_looping(current_char, current_emote) == "1"); + { + sfx_player->set_looping(ao_app->get_sfx_looping(current_char, current_emote) == "1"); + } } void Courtroom::set_scene(bool show_desk, const QString f_side) @@ -3956,23 +4333,29 @@ void Courtroom::set_scene(bool show_desk, const QString f_side) ui_vp_desk->load_image(ao_app->get_pos_path(f_side, true)); if (show_desk) + { ui_vp_desk->show(); + } else + { ui_vp_desk->hide(); + } } -void Courtroom::set_self_offset(const QString& p_list) { - QStringList self_offsets = p_list.split("&"); - int self_offset = self_offsets[0].toInt(); - int self_offset_v; - if (self_offsets.length() <= 1) { - self_offset_v = 0; - } - else { - self_offset_v = self_offsets[1].toInt(); - } - ui_vp_player_char->move_and_center(ui_viewport->width() * self_offset / 100, - ui_viewport->height() * self_offset_v / 100); +void Courtroom::set_self_offset(const QString &p_list) +{ + QStringList self_offsets = p_list.split("&"); + int self_offset = self_offsets[0].toInt(); + int self_offset_v; + if (self_offsets.length() <= 1) + { + self_offset_v = 0; + } + else + { + self_offset_v = self_offsets[1].toInt(); + } + ui_vp_player_char->move_and_center(ui_viewport->width() * self_offset / 100, ui_viewport->height() * self_offset_v / 100); } void Courtroom::set_ip_list(QString p_list) @@ -3985,11 +4368,16 @@ void Courtroom::set_ip_list(QString p_list) void Courtroom::set_mute(bool p_muted, int p_cid) { if (p_cid != m_cid && p_cid != -1) + { return; + } if (p_muted) + { ui_muted->show(); - else { + } + else + { ui_muted->hide(); ui_ic_chat_message->setFocus(); } @@ -4001,15 +4389,14 @@ void Courtroom::set_mute(bool p_muted, int p_cid) ui_ic_chat_message->setEnabled(!p_muted); } -void Courtroom::set_ban(int p_cid) +QString Courtroom::get_current_char() { - if (p_cid != m_cid && p_cid != -1) - return; - - call_notice(tr("You have been banned.")); + return current_char; +} - ao_app->construct_lobby(); - ao_app->destruct_courtroom(); +QString Courtroom::get_current_background() +{ + return current_background; } void Courtroom::handle_song(QStringList *p_contents) @@ -4017,11 +4404,13 @@ void Courtroom::handle_song(QStringList *p_contents) QStringList f_contents = *p_contents; if (f_contents.size() < 2) + { return; + } - bool ok; // Used for charID, channel, effect check + bool ok; // Used for charID, channel, effect check bool looping = false; // No loop due to outdated server using serverside looping - int channel = 0; // Channel 0 is 'master music', other for ambient + int channel = 0; // Channel 0 is 'master music', other for ambient int effect_flags = 0; // No effects by default - vanilla functionality QString f_song = f_contents.at(0); @@ -4030,129 +4419,158 @@ void Courtroom::handle_song(QStringList *p_contents) int n_char = f_contents.at(1).toInt(&ok); if (!ok) + { return; + } if (p_contents->length() > 3 && p_contents->at(3) == "1") + { looping = true; + } - if (p_contents->length() > 4) { + if (p_contents->length() > 4) + { // eyyy we want to change this song's CHANNEL huh // let the music player handle it if it's bigger than the channel list channel = p_contents->at(4).toInt(&ok); if (!ok) + { return; + } } - if (p_contents->length() > 5) { + if (p_contents->length() > 5) + { // Flags provided to us by server such as Fade In, Fade Out, Sync Pos etc. effect_flags = p_contents->at(5).toInt(&ok); if (!ok) + { return; + } } - if(!file_exists(ao_app->get_sfx_suffix(ao_app->get_music_path(f_song))) && !f_song.startsWith("http") - && f_song != "~stop.mp3" && !ao_app->asset_url.isEmpty()) { - f_song = (ao_app->asset_url + "sounds/music/" + f_song).toLower(); + if (!file_exists(ao_app->get_sfx_suffix(ao_app->get_music_path(f_song))) && !f_song.startsWith("http") && f_song != "~stop.mp3" && !ao_app->asset_url.isEmpty()) + { + f_song = (ao_app->asset_url + "sounds/music/" + f_song).toLower(); } bool is_stop = (f_song == "~stop.mp3"); - if (n_char >= 0 && n_char < char_list.size()) { + if (n_char >= 0 && n_char < char_list.size()) + { QString str_char = char_list.at(n_char).name; QString str_show = ao_app->get_showname(str_char); - if (p_contents->length() > 2) { - if (p_contents->at(2) != "") { + if (p_contents->length() > 2) + { + if (p_contents->at(2) != "") + { str_show = p_contents->at(2); } } - if (!mute_map.value(n_char)) { + if (!mute_map.value(n_char)) + { bool selfname = n_char == m_cid; - if (is_stop) { + if (is_stop) + { log_ic_text(str_char, str_show, "", tr("has stopped the music"), 0, selfname); append_ic_text("", str_show, tr("has stopped the music"), 0, selfname); } - else { + else + { log_ic_text(str_char, str_show, f_song, tr("has played a song"), 0, selfname); append_ic_text(f_song_clear, str_show, tr("has played a song"), 0, selfname); } } } - if (channel == 0) { + if (channel == 0) + { // Current song UI only displays the song playing, not other channels. // Any other music playing is irrelevant. - if (music_player->music_watcher.isRunning()) { - music_player->music_watcher.cancel(); + if (music_player->music_watcher.isRunning()) + { + music_player->music_watcher.cancel(); } ui_music_name->setText(tr("[LOADING] %1").arg(f_song_clear)); } #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - music_player->music_watcher.setFuture(QtConcurrent::run(music_player, &AOMusicPlayer::play, f_song, channel, - looping, effect_flags)); + music_player->music_watcher.setFuture(QtConcurrent::run(music_player, &AOMusicPlayer::play, f_song, channel, looping, effect_flags)); #else - music_player->music_watcher.setFuture(QtConcurrent::run(&AOMusicPlayer::play, music_player, f_song, channel, - looping, effect_flags)); + music_player->music_watcher.setFuture(QtConcurrent::run(&AOMusicPlayer::play, music_player, f_song, channel, looping, effect_flags)); #endif } void Courtroom::update_ui_music_name() { - QString result = music_player->music_watcher.result(); - if (result.isEmpty()) - return; - ui_music_name->setText(result); + QString result = music_player->music_watcher.result(); + if (result.isEmpty()) + { + return; + } + ui_music_name->setText(result); } 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; ui_vp_wtce->set_static_duration(wtce_static_time); ui_vp_wtce->set_max_duration(wtce_max_time); // witness testimony - if (p_wtce == "testimony1") { + if (p_wtce == "testimony1") + { // End testimony indicator - if (variant == 1) { + if (variant == 1) + { ui_vp_testimony->kill(); return; } sfx_name = ao_app->get_court_sfx("witness_testimony", bg_misc); - if (sfx_name == "") { + if (sfx_name == "") + { sfx_name = ao_app->get_court_sfx("witnesstestimony", bg_misc); } filename = "witnesstestimony_bubble"; ui_vp_testimony->load_image("testimony", "", bg_misc); } // cross examination - else if (p_wtce == "testimony2") { - sfx_name = ao_app->get_court_sfx("cross_examination", bg_misc); - if (sfx_name == "") { + else if (p_wtce == "testimony2") + { + sfx_name = ao_app->get_court_sfx("cross_examination", bg_misc); + if (sfx_name == "") + { sfx_name = ao_app->get_court_sfx("crossexamination", bg_misc); } filename = "crossexamination_bubble"; ui_vp_testimony->kill(); } - else { + else + { ui_vp_wtce->set_static_duration(verdict_static_time); ui_vp_wtce->set_max_duration(verdict_max_time); // Verdict? - if (p_wtce == "judgeruling") { - if (variant == 0) { + if (p_wtce == "judgeruling") + { + if (variant == 0) + { sfx_name = ao_app->get_court_sfx("not_guilty", bg_misc); - if (sfx_name == "") { + if (sfx_name == "") + { sfx_name = ao_app->get_court_sfx("notguilty", bg_misc); } filename = "notguilty_bubble"; ui_vp_testimony->kill(); } - else if (variant == 1) { + else if (variant == 1) + { sfx_name = ao_app->get_court_sfx("guilty", bg_misc); filename = "guilty_bubble"; ui_vp_testimony->kill(); } } // Completely custom WTCE - else { + else + { sfx_name = p_wtce; filename = p_wtce; } @@ -4165,15 +4583,19 @@ void Courtroom::handle_wtce(QString p_wtce, int variant) void Courtroom::set_hp_bar(int p_bar, int p_state) { if (p_state < 0 || p_state > 10) + { return; + } int prev_state = p_state; - if (p_bar == 1) { + if (p_bar == 1) + { ui_defense_bar->set_image("defensebar" + QString::number(p_state)); prev_state = defense_bar_state; defense_bar_state = p_state; } - else if (p_bar == 2) { + else if (p_bar == 2) + { ui_prosecution_bar->set_image("prosecutionbar" + QString::number(p_state)); prev_state = prosecution_bar_state; prosecution_bar_state = p_state; @@ -4181,62 +4603,66 @@ void Courtroom::set_hp_bar(int p_bar, int p_state) QString sfx_name; QString effect_name; - if (p_state > prev_state) { + if (p_state > prev_state) + { sfx_name = ao_app->get_penalty_value("hp_increased_sfx"); effect_name = ao_app->get_penalty_value("hp_increased_effect").toLower(); } - else if (p_state < prev_state) { + else if (p_state < prev_state) + { sfx_name = ao_app->get_penalty_value("hp_decreased_sfx"); effect_name = ao_app->get_penalty_value("hp_decreased_effect").toLower(); } - else { + else + { return; } - if (effect_name == "screenshake") { + if (effect_name == "screenshake") + { do_screenshake(); } - else if (effect_name == "flash") { + else if (effect_name == "flash") + { do_flash(); } - else { + else + { do_effect(effect_name, "", "", ""); } - if (!sfx_name.isEmpty()) { + if (!sfx_name.isEmpty()) + { sfx_player->play(sfx_name); } } void Courtroom::show_judge_controls(bool visible) { - if (judge_state != POS_DEPENDENT) { + if (judge_state != POS_DEPENDENT) + { visible = judge_state == SHOW_CONTROLS; // Server-side override } - QList<QWidget*> judge_controls = - { - ui_witness_testimony, - ui_cross_examination, - ui_guilty, - ui_not_guilty, - ui_defense_minus, - ui_defense_plus, - ui_prosecution_minus, - ui_prosecution_plus - }; - - for (QWidget* control : judge_controls) { - if (visible) - control->show(); - else - control->hide(); + QList<QWidget *> judge_controls = {ui_witness_testimony, ui_cross_examination, ui_guilty, ui_not_guilty, ui_defense_minus, ui_defense_plus, ui_prosecution_minus, ui_prosecution_plus}; + + for (QWidget *control : judge_controls) + { + if (visible) + { + control->show(); + } + else + { + control->hide(); + } } } void Courtroom::mod_called(QString p_ip) { ui_server_chatlog->append(p_ip); - if (!ui_guard->isChecked()) { + if (!ui_guard->isChecked()) + { modcall_player->play(ao_app->get_court_sfx("mod_call")); ao_app->alert(this); } @@ -4246,32 +4672,36 @@ void Courtroom::on_ooc_return_pressed() { QString ooc_message = ui_ooc_chat_message->text(); - //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_supported) { - if (ooc_message == "/pos jud") { + // 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_supported) + { + if (ooc_message == "/pos jud") + { show_judge_controls(true); } - else { + else + { show_judge_controls(false); } } - 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(get_base_path()+"/cases"); - if (!casefolder.exists()) { + QDir casefolder(get_base_path() + "/cases"); + if (!casefolder.exists()) + { QDir::current().mkdir(get_base_path() + casefolder.dirName()); - append_server_chatmessage( - "CLIENT", - tr("You don't have a `base/cases/` folder! It was just made for you, " - "but seeing as it WAS just made for you, it's likely the case " - "file you're looking for can't be found in there."), - "1"); + append_server_chatmessage("CLIENT", + tr("You don't have a `base/cases/` folder! It was just made for you, " + "but seeing as it WAS just made for you, it's likely the case " + "file you're looking for can't be found in there."), + "1"); ui_ooc_chat_message->clear(); return; } @@ -4280,30 +4710,29 @@ void Courtroom::on_ooc_return_pressed() caseslist.removeOne(".."); caseslist.replaceInStrings(".ini", ""); - if (command.size() < 2) { - append_server_chatmessage( - "CLIENT", - tr("You need to give a filename to load (extension not needed)! Make " - "sure that it is in the `base/cases/` folder, and that it is a " - "correctly formatted ini.\nCases you can load: %1") - .arg(caseslist.join(", ")), - "1"); + if (command.size() < 2) + { + append_server_chatmessage("CLIENT", + tr("You need to give a filename to load (extension not needed)! Make " + "sure that it is in the `base/cases/` folder, and that it is a " + "correctly formatted ini.\nCases you can load: %1") + .arg(caseslist.join(", ")), + "1"); ui_ooc_chat_message->clear(); return; } - if (command.size() > 2) { - append_server_chatmessage( - "CLIENT", - tr("Too many arguments to load a case! You only need one filename, " - "without extension."), - "1"); + if (command.size() > 2) + { + append_server_chatmessage("CLIENT", + tr("Too many arguments to load a case! You only need one filename, " + "without extension."), + "1"); ui_ooc_chat_message->clear(); return; } - QSettings casefile(get_base_path() + "/cases/" + command[1] + ".ini", - QSettings::IniFormat); + QSettings casefile(get_base_path() + "/cases/" + command[1] + ".ini", QSettings::IniFormat); QString caseauth = casefile.value("author", "").value<QString>(); QString casedoc = casefile.value("doc", "").value<QString>(); @@ -4311,67 +4740,68 @@ void Courtroom::on_ooc_return_pressed() QString casestatus = casefile.value("status", "").value<QString>(); if (!caseauth.isEmpty()) - append_server_chatmessage(tr("CLIENT"), - tr("Case made by %1.").arg(caseauth), "1"); - if (!casedoc.isEmpty()) { - ao_app->send_server_packet(new AOPacket("CT", {ui_ooc_chat_name->text(), "/doc " + casedoc})); + { + append_server_chatmessage(tr("CLIENT"), tr("Case made by %1.").arg(caseauth), "1"); } - if (!casestatus.isEmpty()) { - ao_app->send_server_packet(new AOPacket("CT", {ui_ooc_chat_name->text(), "/status " + casestatus})); + if (!casedoc.isEmpty()) + { + ao_app->send_server_packet(AOPacket("CT", {ui_ooc_chat_name->text(), "/doc " + casedoc})); + } + if (!casestatus.isEmpty()) + { + ao_app->send_server_packet(AOPacket("CT", {ui_ooc_chat_name->text(), "/status " + casestatus})); } if (!cmdoc.isEmpty()) - append_server_chatmessage( - "CLIENT", tr("Navigate to %1 for the CM doc.").arg(cmdoc), "1"); + { + append_server_chatmessage("CLIENT", tr("Navigate to %1 for the CM doc.").arg(cmdoc), "1"); + } - for (int i = local_evidence_list.size() - 1; i >= 0; i--) { - ao_app->send_server_packet( - new AOPacket("DE", {QString::number(i)})); + for (int i = local_evidence_list.size() - 1; i >= 0; i--) + { + ao_app->send_server_packet(AOPacket("DE", {QString::number(i)})); } // sort the case_evidence numerically QStringList case_evidence = casefile.childGroups(); - std::sort(case_evidence.begin(), case_evidence.end(), - [] (const QString &a, const QString &b) { - return a.toInt() < b.toInt(); - }); + std::sort(case_evidence.begin(), case_evidence.end(), [](const QString &a, const QString &b) { return a.toInt() < b.toInt(); }); // load evidence - foreach (QString evi, case_evidence) { + foreach (QString evi, case_evidence) + { if (evi == "General") + { continue; + } QStringList f_contents; - f_contents.append( - casefile.value(evi + "/name", tr("UNKNOWN")).value<QString>()); - f_contents.append( - casefile.value(evi + "/description", tr("UNKNOWN")).value<QString>()); - f_contents.append( - casefile.value(evi + "/image", "UNKNOWN.png").value<QString>()); + f_contents.append(casefile.value(evi + "/name", tr("UNKNOWN")).value<QString>()); + f_contents.append(casefile.value(evi + "/description", tr("UNKNOWN")).value<QString>()); + f_contents.append(casefile.value(evi + "/image", "UNKNOWN.png").value<QString>()); - ao_app->send_server_packet(new AOPacket("PE", f_contents)); + ao_app->send_server_packet(AOPacket("PE", f_contents)); } - append_server_chatmessage( - "CLIENT", tr("Your case \"%1\" was loaded!").arg(command[1]), "1"); + append_server_chatmessage("CLIENT", tr("Your case \"%1\" was loaded!").arg(command[1]), "1"); ui_ooc_chat_message->clear(); return; } - else if (ooc_message.startsWith("/save_case")) { + 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(get_base_path() + "cases"); - if (!casefolder.exists()) { + if (!casefolder.exists()) + { QDir(get_base_path()).mkdir(casefolder.dirName()); - append_server_chatmessage( - "CLIENT", - tr("You don't have a `base/cases/` folder! It was just made for you, " - "but seeing as it WAS just made for you, it's likely that you " - "somehow deleted it."), - "1"); + append_server_chatmessage("CLIENT", + tr("You don't have a `base/cases/` folder! It was just made for you, " + "but seeing as it WAS just made for you, it's likely that you " + "somehow deleted it."), + "1"); ui_ooc_chat_message->clear(); return; } @@ -4380,37 +4810,35 @@ void Courtroom::on_ooc_return_pressed() caseslist.removeOne(".."); caseslist.replaceInStrings(".ini", ""); - if (command.size() < 3) { - append_server_chatmessage( - "CLIENT", - tr("You need to give a filename to save (extension not needed) and " - "the courtroom status!"), - "1"); + if (command.size() < 3) + { + append_server_chatmessage("CLIENT", + tr("You need to give a filename to save (extension not needed) and " + "the courtroom status!"), + "1"); ui_ooc_chat_message->clear(); return; } - if (command.size() > 3) { - append_server_chatmessage( - "CLIENT", - tr("Too many arguments to save a case! You only need a filename " - "without extension and the courtroom status!"), - "1"); + if (command.size() > 3) + { + append_server_chatmessage("CLIENT", + tr("Too many arguments to save a case! You only need a filename " + "without extension and the courtroom status!"), + "1"); ui_ooc_chat_message->clear(); return; } - QSettings casefile(get_base_path() + "/cases/" + command[1] + ".ini", - QSettings::IniFormat); + QSettings casefile(get_base_path() + "/cases/" + command[1] + ".ini", QSettings::IniFormat); casefile.setValue("author", ui_ooc_chat_name->text()); casefile.setValue("cmdoc", ""); casefile.setValue("doc", ""); casefile.setValue("status", command[2]); casefile.sync(); - for (int i = 0; i < local_evidence_list.size(); i++) { - QString clean_evidence_dsc = local_evidence_list[i].description.replace( - QRegularExpression("<owner = ...>..."), ""); - clean_evidence_dsc = clean_evidence_dsc.replace( - clean_evidence_dsc.lastIndexOf(">"), 1, ""); + for (int i = 0; i < local_evidence_list.size(); i++) + { + QString clean_evidence_dsc = local_evidence_list[i].description.replace(QRegularExpression("<owner = ...>..."), ""); + clean_evidence_dsc = clean_evidence_dsc.replace(clean_evidence_dsc.lastIndexOf(">"), 1, ""); casefile.beginGroup(QString::number(i)); casefile.sync(); casefile.setValue("name", local_evidence_list[i].name); @@ -4419,9 +4847,7 @@ void Courtroom::on_ooc_return_pressed() casefile.endGroup(); } casefile.sync(); - append_server_chatmessage( - "CLIENT", tr("Succesfully saved, edit doc and cmdoc link on the ini!"), - "1"); + append_server_chatmessage("CLIENT", tr("Succesfully saved, edit doc and cmdoc link on the ini!"), "1"); ui_ooc_chat_message->clear(); return; } @@ -4430,10 +4856,12 @@ void Courtroom::on_ooc_return_pressed() packet_contents.append(ui_ooc_chat_name->text()); packet_contents.append(ooc_message); - AOPacket *f_packet = new AOPacket("CT", packet_contents); + AOPacket f_packet("CT", packet_contents); if (server_ooc) + { ao_app->send_server_packet(f_packet); + } ui_ooc_chat_message->clear(); @@ -4442,14 +4870,16 @@ void Courtroom::on_ooc_return_pressed() void Courtroom::on_ooc_toggle_clicked() { - if (server_ooc) { + if (server_ooc) + { ui_debug_log->show(); ui_server_chatlog->hide(); ui_ooc_toggle->setText(tr("Debug")); server_ooc = false; } - else { + else + { ui_debug_log->hide(); ui_server_chatlog->show(); ui_ooc_toggle->setText(tr("Server")); @@ -4462,43 +4892,54 @@ void Courtroom::on_ooc_toggle_clicked() void Courtroom::on_music_search_edited(QString p_text) { // Iterate through all QTreeWidgetItem items - if (!ui_music_list->isHidden()) { + if (!ui_music_list->isHidden()) + { QTreeWidgetItemIterator it(ui_music_list); - while (*it) { + while (*it) + { (*it)->setHidden(p_text != ""); ++it; } last_music_search = p_text; } - if (!ui_area_list->isHidden()) { + if (!ui_area_list->isHidden()) + { QTreeWidgetItemIterator ait(ui_area_list); - while (*ait) { + while (*ait) + { (*ait)->setHidden(p_text != ""); ++ait; } last_area_search = p_text; } - if (p_text != "") { - if (!ui_music_list->isHidden()) { + if (p_text != "") + { + if (!ui_music_list->isHidden()) + { // Search in metadata - QList<QTreeWidgetItem *> clist = ui_music_list->findItems( - ui_music_search->text(), Qt::MatchContains | Qt::MatchRecursive, 1); - foreach (QTreeWidgetItem *item, clist) { + QList<QTreeWidgetItem *> clist = ui_music_list->findItems(ui_music_search->text(), Qt::MatchContains | Qt::MatchRecursive, 1); + foreach (QTreeWidgetItem *item, clist) + { if (item->parent() != nullptr) // So the category shows up too + { item->parent()->setHidden(false); + } item->setHidden(false); } } - if (!ui_area_list->isHidden()) { + if (!ui_area_list->isHidden()) + { // Search in metadata - QList<QTreeWidgetItem *> alist = ui_area_list->findItems( - ui_music_search->text(), Qt::MatchContains | Qt::MatchRecursive, 1); - foreach (QTreeWidgetItem *item, alist) { + QList<QTreeWidgetItem *> alist = ui_area_list->findItems(ui_music_search->text(), Qt::MatchContains | Qt::MatchRecursive, 1); + foreach (QTreeWidgetItem *item, alist) + { if (item->parent() != nullptr) // So the category shows up too + { item->parent()->setHidden(false); + } item->setHidden(false); } } @@ -4507,7 +4948,8 @@ void Courtroom::on_music_search_edited(QString p_text) void Courtroom::on_music_search_return_pressed() { - if (ui_music_search->text() == "") { + if (ui_music_search->text() == "") + { ui_music_list->collapseAll(); } } @@ -4515,7 +4957,9 @@ void Courtroom::on_music_search_return_pressed() void Courtroom::on_pos_dropdown_changed(int p_index) { if (p_index < 0) + { return; + } on_pos_dropdown_changed(ui_pos_dropdown->itemText(p_index)); } @@ -4531,15 +4975,14 @@ void Courtroom::on_pos_dropdown_context_menu_requested(const QPoint &pos) menu->setAttribute(Qt::WA_DeleteOnClose); menu->addSeparator(); - menu->addAction(QString("Open background " + current_background), this, - [=] { + menu->addAction(QString("Open background " + current_background), this, [=] { QString p_path = ao_app->get_real_path(VPath("background/" + current_background + "/")); - if (!dir_exists(p_path)) { - return; + if (!dir_exists(p_path)) + { + return; } QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); - } - ); + }); menu->popup(ui_iniswap_dropdown->mapToGlobal(pos)); } @@ -4550,18 +4993,24 @@ void Courtroom::on_pos_remove_clicked() show_judge_controls(ao_app->get_pos_is_judge(default_side)); - for (int i = 0; i < ui_pos_dropdown->count(); ++i) { + for (int i = 0; i < ui_pos_dropdown->count(); ++i) + { QString pos = ui_pos_dropdown->itemText(i); - if (pos == default_side) { + if (pos == default_side) + { ui_pos_dropdown->setCurrentIndex(i); break; } } int wit_index = ui_pos_dropdown->findText("wit"); - if (ui_pos_dropdown->currentText() != default_side && wit_index != -1) //i.e. this bg doesn't have our pos + if (ui_pos_dropdown->currentText() != default_side && wit_index != -1) // i.e. this bg doesn't have our pos + { ui_pos_dropdown->setCurrentIndex(wit_index); // fall back to "wit" + } else if (ui_pos_dropdown->currentText() != default_side) // we don't have "wit" either? + { ui_pos_dropdown->setCurrentIndex(0); // as a last resort, choose the first item in the dropdown + } ui_pos_dropdown->blockSignals(false); current_side = ""; ui_pos_remove->hide(); @@ -4572,34 +5021,39 @@ void Courtroom::set_iniswap_dropdown() { ui_iniswap_dropdown->blockSignals(true); ui_iniswap_dropdown->clear(); - if (m_cid == -1) { + if (m_cid == -1) + { ui_iniswap_dropdown->hide(); 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(VPath("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(VPath("iniswaps.ini")); iniswaps.prepend(char_list.at(m_cid).name); iniswaps.removeDuplicates(); - if (iniswaps.size() <= 0) { + if (iniswaps.size() <= 0) + { ui_iniswap_dropdown->hide(); ui_iniswap_remove->hide(); return; } ui_iniswap_dropdown->show(); - for (int i = 0; i < iniswaps.size(); ++i) { + for (int i = 0; i < iniswaps.size(); ++i) + { ui_iniswap_dropdown->addItem(iniswaps.at(i)); - QString icon_path = ao_app->get_image_suffix(ao_app->get_character_path( - iniswaps.at(i), "char_icon")); + QString icon_path = ao_app->get_image_suffix(ao_app->get_character_path(iniswaps.at(i), "char_icon")); ui_iniswap_dropdown->setItemIcon(i, QIcon(icon_path)); - if (iniswaps.at(i) == current_char) { + if (iniswaps.at(i) == current_char) + { ui_iniswap_dropdown->setCurrentIndex(i); if (i != 0) + { ui_iniswap_remove->show(); + } else + { ui_iniswap_remove->hide(); + } } } ui_iniswap_dropdown->blockSignals(false); @@ -4612,13 +5066,17 @@ void Courtroom::on_iniswap_dropdown_changed(int p_index) QStringList swaplist; QStringList defswaplist = ao_app->get_list_file(ao_app->get_character_path(char_list.at(m_cid).name, "iniswaps.ini")); - for (int i = 0; i < ui_iniswap_dropdown->count(); ++i) { + for (int i = 0; i < ui_iniswap_dropdown->count(); ++i) + { QString entry = ui_iniswap_dropdown->itemText(i); if (!swaplist.contains(entry) && entry != char_list.at(m_cid).name && !defswaplist.contains(entry)) + { swaplist.append(entry); + } } QString p_path = ao_app->get_real_path(VPath("iniswaps.ini")); - if (!file_exists(p_path)) { + if (!file_exists(p_path)) + { p_path = get_base_path() + "iniswaps.ini"; } ao_app->write_to_file(swaplist.join("\n"), p_path); @@ -4626,13 +5084,16 @@ void Courtroom::on_iniswap_dropdown_changed(int p_index) ui_iniswap_dropdown->setCurrentIndex(p_index); ui_iniswap_dropdown->blockSignals(false); update_character(m_cid, iniswap, true); - QString icon_path = ao_app->get_image_suffix(ao_app->get_character_path( - iniswap, "char_icon")); + QString icon_path = ao_app->get_image_suffix(ao_app->get_character_path(iniswap, "char_icon")); ui_iniswap_dropdown->setItemIcon(p_index, QIcon(icon_path)); if (p_index != 0) + { ui_iniswap_remove->show(); + } else + { ui_iniswap_remove->hide(); + } } void Courtroom::on_iniswap_context_menu_requested(const QPoint &pos) @@ -4641,33 +5102,33 @@ void Courtroom::on_iniswap_context_menu_requested(const QPoint &pos) menu->setAttribute(Qt::WA_DeleteOnClose); menu->addSeparator(); - 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, - &Courtroom::on_iniswap_edit_requested); - if (ui_iniswap_dropdown->itemText(ui_iniswap_dropdown->currentIndex()) != - char_list.at(m_cid).name) - menu->addAction(QString("Remove " + current_char), this, - &Courtroom::on_iniswap_remove_clicked); + 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, &Courtroom::on_iniswap_edit_requested); + } + if (ui_iniswap_dropdown->itemText(ui_iniswap_dropdown->currentIndex()) != char_list.at(m_cid).name) + { + menu->addAction(QString("Remove " + current_char), this, &Courtroom::on_iniswap_remove_clicked); + } menu->addSeparator(); - menu->addAction(QString("Open character folder " + current_char), this, - [=] { + menu->addAction(QString("Open character folder " + current_char), this, [=] { QString p_path = ao_app->get_real_path(VPath("characters/" + current_char + "/")); - if (!dir_exists(p_path)) { + if (!dir_exists(p_path)) + { return; } QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); - } - ); + }); menu->popup(ui_iniswap_dropdown->mapToGlobal(pos)); } void Courtroom::on_iniswap_edit_requested() { QString p_path = ao_app->get_real_path(ao_app->get_character_path(current_char, "char.ini")); - if (!file_exists(p_path)) { + if (!file_exists(p_path)) + { return; } QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); @@ -4675,14 +5136,16 @@ void Courtroom::on_iniswap_edit_requested() void Courtroom::on_iniswap_remove_clicked() { - if (ui_iniswap_dropdown->count() <= 0) { + if (ui_iniswap_dropdown->count() <= 0) + { ui_iniswap_remove->hide(); // We're not supposed to see it. Do this or the // client will crash return; } QStringList defswaplist = ao_app->get_list_file(ao_app->get_character_path(char_list.at(m_cid).name, "iniswaps.ini")); QString iniswap = ui_iniswap_dropdown->itemText(ui_iniswap_dropdown->currentIndex()); - if (iniswap != char_list.at(m_cid).name && !defswaplist.contains(iniswap)) { + if (iniswap != char_list.at(m_cid).name && !defswaplist.contains(iniswap)) + { ui_iniswap_dropdown->removeItem(ui_iniswap_dropdown->currentIndex()); } on_iniswap_dropdown_changed(0); // Reset back to original @@ -4693,29 +5156,31 @@ void Courtroom::set_sfx_dropdown() { ui_sfx_dropdown->blockSignals(true); ui_sfx_dropdown->clear(); - if (m_cid == -1) { + if (m_cid == -1) + { ui_sfx_dropdown->hide(); ui_sfx_remove->hide(); return; } // Initialzie character sound list first. Will be empty if not found. - sound_list = ao_app->get_list_file( - ao_app->get_character_path(current_char, "soundlist.ini")); + sound_list = ao_app->get_list_file(ao_app->get_character_path(current_char, "soundlist.ini")); // If AO2 sound list is empty, try to find the DRO one. - if (sound_list.isEmpty()) { - sound_list = ao_app->get_list_file( - ao_app->get_character_path(current_char, "sounds.ini")); + if (sound_list.isEmpty()) + { + sound_list = ao_app->get_list_file(ao_app->get_character_path(current_char, "sounds.ini")); } // Append default sound list after the character sound list. sound_list += ao_app->get_list_file(VPath("soundlist.ini")); QStringList display_sounds; - for (const QString &sound : qAsConst(sound_list)) { + for (const QString &sound : qAsConst(sound_list)) + { QStringList unpacked = sound.split("="); QString display = unpacked[0].trimmed(); - if (unpacked.size() > 1) { + if (unpacked.size() > 1) + { display = unpacked[1].trimmed(); } @@ -4735,8 +5200,9 @@ void Courtroom::on_sfx_dropdown_changed(int p_index) { custom_sfx = ""; ui_ic_chat_message->setFocus(); - if (p_index == 0) { - ui_sfx_remove->hide(); + if (p_index == 0) + { + ui_sfx_remove->hide(); } } @@ -4753,29 +5219,32 @@ void Courtroom::on_sfx_context_menu_requested(const QPoint &pos) menu->setAttribute(Qt::WA_DeleteOnClose); menu->addSeparator(); // SFX is not "Nothing" or "Default"? - if (get_char_sfx() != "0" && get_char_sfx() != "1" && get_char_sfx() != "-") { + if (get_char_sfx() != "0" && get_char_sfx() != "1" && get_char_sfx() != "-") + { // Add an option to play the SFX - menu->addAction(QString("Play " + get_char_sfx()), this, &Courtroom::on_sfx_play_clicked);; + menu->addAction(QString("Play " + get_char_sfx()), this, &Courtroom::on_sfx_play_clicked); + } + 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, &Courtroom::on_sfx_edit_requested); } - 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, - &Courtroom::on_sfx_edit_requested); else - menu->addAction(QString("Edit base soundlist.ini"), this, - &Courtroom::on_sfx_edit_requested); + { + menu->addAction(QString("Edit base soundlist.ini"), this, &Courtroom::on_sfx_edit_requested); + } if (!custom_sfx.isEmpty()) + { menu->addAction(QString("Clear Edit Text"), this, &Courtroom::on_sfx_remove_clicked); + } menu->addSeparator(); - menu->addAction(QString("Open base sounds folder"), this, - [=] { + menu->addAction(QString("Open base sounds folder"), this, [=] { QString p_path = get_base_path() + "sounds/general/"; - if (!dir_exists(p_path)) { + if (!dir_exists(p_path)) + { return; } QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); - } - ); + }); menu->popup(ui_sfx_dropdown->mapToGlobal(pos)); } @@ -4787,15 +5256,18 @@ void Courtroom::on_sfx_play_clicked() void Courtroom::on_sfx_edit_requested() { QString p_path = ao_app->get_real_path(ao_app->get_character_path(current_char, "soundlist.ini")); - if (!file_exists(p_path)) { + if (!file_exists(p_path)) + { p_path = ao_app->get_real_path(ao_app->get_character_path(current_char, "sounds.ini")); } - if (!file_exists(p_path)) { + if (!file_exists(p_path)) + { p_path = ao_app->get_real_path(VPath("soundlist.ini")); } - if (!file_exists(p_path)) { + if (!file_exists(p_path)) + { p_path = get_base_path() + "soundlist.ini"; } QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); @@ -4812,14 +5284,16 @@ void Courtroom::set_effects_dropdown() { ui_effects_dropdown->blockSignals(true); ui_effects_dropdown->clear(); - if (m_cid == -1) { + if (m_cid == -1) + { ui_effects_dropdown->hide(); return; } QStringList effectslist; effectslist.append(ao_app->get_effects(current_char)); - if (effectslist.empty()) { + if (effectslist.empty()) + { ui_effects_dropdown->hide(); return; } @@ -4830,7 +5304,8 @@ void Courtroom::set_effects_dropdown() ui_effects_dropdown->addItems(effectslist); // Make the icons - for (int i = 0; i < ui_effects_dropdown->count(); ++i) { + for (int i = 0; i < ui_effects_dropdown->count(); ++i) + { QString iconpath = ao_app->get_effect("icons/" + ui_effects_dropdown->itemText(i), current_char, ""); ui_effects_dropdown->setItemIcon(i, QIcon(iconpath)); } @@ -4842,24 +5317,23 @@ void Courtroom::set_effects_dropdown() void Courtroom::on_effects_context_menu_requested(const QPoint &pos) { QMenu *menu = new QMenu(this); - menu->setAttribute(Qt::WA_DeleteOnClose); + if (!ao_app->read_char_ini(current_char, "effects", "Options").isEmpty()) - menu->addAction( - QString("Open misc/" + - ao_app->read_char_ini(current_char, "effects", "Options") + - " folder"), - this, &Courtroom::on_character_effects_edit_requested); - menu->addAction(QString("Open theme's effects folder"), this, - &Courtroom::on_effects_edit_requested); + { + menu->addAction(QString("Open misc/" + ao_app->read_char_ini(current_char, "effects", "Options") + " folder"), this, &Courtroom::on_character_effects_edit_requested); + } + menu->addAction(QString("Open theme's effects folder"), this, &Courtroom::on_effects_edit_requested); menu->popup(ui_effects_dropdown->mapToGlobal(pos)); } void Courtroom::on_effects_edit_requested() { QString p_path = ao_app->get_real_path(ao_app->get_theme_path("effects/")); - if (!dir_exists(p_path)) { + if (!dir_exists(p_path)) + { p_path = ao_app->get_real_path(ao_app->get_theme_path("effects/", "default")); - if (!dir_exists(p_path)) { + if (!dir_exists(p_path)) + { return; } } @@ -4870,7 +5344,9 @@ 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_real_path(VPath("misc/" + p_effect + "/")); if (!dir_exists(p_path)) + { return; + } QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); } @@ -4883,9 +5359,11 @@ void Courtroom::on_effects_dropdown_changed(int p_index) bool Courtroom::effects_dropdown_find_and_set(QString effect) { - for (int i = 0; i < ui_effects_dropdown->count(); ++i) { + for (int i = 0; i < ui_effects_dropdown->count(); ++i) + { QString entry = ui_effects_dropdown->itemText(i); - if (entry == effect) { + if (entry == effect) + { ui_effects_dropdown->setCurrentIndex(i); return true; } @@ -4896,17 +5374,23 @@ bool Courtroom::effects_dropdown_find_and_set(QString effect) QString Courtroom::get_char_sfx() { if (!custom_sfx.isEmpty()) + { return custom_sfx; + } int index = ui_sfx_dropdown->currentIndex(); - if (index == 0) { // Default + if (index == 0) + { // Default return ao_app->get_sfx_name(current_char, current_emote); } - if (index == 1) { // Nothing + if (index == 1) + { // Nothing return "1"; } - QString sfx = sound_list[index-2].split("=")[0].trimmed(); + QString sfx = sound_list[index - 2].split("=")[0].trimmed(); if (sfx == "") + { return "1"; + } return sfx; } @@ -4922,27 +5406,37 @@ void Courtroom::on_mute_list_clicked(QModelIndex p_index) QString real_char; if (f_char.endsWith(" [x]")) + { real_char = f_char.left(f_char.size() - 4); + } else + { real_char = f_char; + } int f_cid = -1; - for (int n_char = 0; n_char < char_list.size(); n_char++) { + for (int n_char = 0; n_char < char_list.size(); n_char++) + { if (char_list.at(n_char).name == real_char) + { f_cid = n_char; + } } - if (f_cid < 0 || f_cid >= char_list.size()) { + if (f_cid < 0 || f_cid >= char_list.size()) + { qWarning() << "" << real_char << " not present in char_list"; return; } - if (mute_map.value(f_cid)) { + if (mute_map.value(f_cid)) + { mute_map.insert(f_cid, false); f_item->setText(real_char); } - else { + else + { mute_map.insert(f_cid, true); f_item->setText(real_char + " [x]"); } @@ -4955,19 +5449,25 @@ void Courtroom::on_pair_list_clicked(QModelIndex p_index) QString real_char; int f_cid = -1; - if (f_char.endsWith(" [x]")) { + if (f_char.endsWith(" [x]")) + { real_char = f_char.left(f_char.size() - 4); f_item->setText(real_char); } - else { + else + { real_char = f_char; - for (int n_char = 0; n_char < char_list.size(); n_char++) { + for (int n_char = 0; n_char < char_list.size(); n_char++) + { if (char_list.at(n_char).name == real_char) + { f_cid = n_char; + } } } - if (f_cid < -2 || f_cid >= char_list.size()) { + if (f_cid < -2 || f_cid >= char_list.size()) + { qWarning() << "" << real_char << " not present in char_list"; return; } @@ -4978,79 +5478,84 @@ void Courtroom::on_pair_list_clicked(QModelIndex p_index) QStringList sorted_pair_list; for (const char_type &i_char : qAsConst(char_list)) + { sorted_pair_list.append(i_char.name); + } sorted_pair_list.sort(); - for (int i = 0; i < ui_pair_list->count(); i++) { + for (int i = 0; i < ui_pair_list->count(); i++) + { ui_pair_list->item(i)->setText(sorted_pair_list.at(i)); } - if (other_charid != -1) { + if (other_charid != -1) + { f_item->setText(real_char + " [x]"); } } -void Courtroom::on_music_list_double_clicked(QTreeWidgetItem *p_item, - int column) +void Courtroom::on_music_list_double_clicked(QTreeWidgetItem *p_item, int column) { if (is_muted) + { return; + } if (!Options::getInstance().stopMusicOnCategoryEnabled() && p_item->parent() == nullptr) + { return; + } column = 1; // Column 1 is always the metadata (which we want) QString p_song = p_item->text(column); QStringList packet_contents; packet_contents.append(p_song); packet_contents.append(QString::number(m_cid)); - if ((!ui_ic_chat_name->text().isEmpty() && ao_app->cccc_ic_supported) || - ao_app->effects_supported) + if ((!ui_ic_chat_name->text().isEmpty() && ao_app->cccc_ic_supported) || ao_app->effects_supported) + { packet_contents.append(ui_ic_chat_name->text()); + } if (ao_app->effects_supported) + { packet_contents.append(QString::number(music_flags)); - ao_app->send_server_packet(new AOPacket("MC", packet_contents)); + } + ao_app->send_server_packet(AOPacket("MC", packet_contents)); } 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, &Courtroom::music_stop); menu->addAction(QString(tr("Play Random Song")), this, &Courtroom::music_random); menu->addSeparator(); - menu->addAction(QString(tr("Expand All Categories")), this, - &Courtroom::music_list_expand_all); - menu->addAction(QString(tr("Collapse All Categories")), this, - &Courtroom::music_list_collapse_all); + menu->addAction(QString(tr("Expand All Categories")), this, &Courtroom::music_list_expand_all); + menu->addAction(QString(tr("Collapse All Categories")), this, &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(), &QAction::toggled, this, - &Courtroom::music_fade_out); + 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(), &QAction::toggled, this, - &Courtroom::music_fade_in); + 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(), &QAction::toggled, this, - &Courtroom::music_synchronize); + connect(menu->actions().back(), &QAction::toggled, this, &Courtroom::music_synchronize); menu->addSeparator(); - menu->addAction(QString("Open base music folder"), this, - [=] { + menu->addAction(QString("Open base music folder"), this, [=] { QString p_path = get_base_path() + "sounds/music/"; - if (!dir_exists(p_path)) { + if (!dir_exists(p_path)) + { return; } QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); - } - ); + }); menu->popup(ui_music_list->mapToGlobal(pos)); } @@ -5058,41 +5563,55 @@ void Courtroom::on_music_list_context_menu_requested(const QPoint &pos) void Courtroom::music_fade_out(bool toggle) { if (toggle) + { music_flags |= FADE_OUT; + } else + { music_flags &= ~FADE_OUT; + } } void Courtroom::music_fade_in(bool toggle) { if (toggle) + { music_flags |= FADE_IN; + } else + { music_flags &= ~FADE_IN; + } } void Courtroom::music_synchronize(bool toggle) { if (toggle) + { music_flags |= SYNC_POS; + } else + { music_flags &= ~SYNC_POS; + } } void Courtroom::music_random() { QList<QTreeWidgetItem *> clist; - QTreeWidgetItemIterator it(ui_music_list, - QTreeWidgetItemIterator::NotHidden | - QTreeWidgetItemIterator::NoChildren); - while (*it) { - if (!(*it)->parent() || (*it)->parent()->isExpanded()) { // add top level songs and songs in expanded categories + QTreeWidgetItemIterator it(ui_music_list, QTreeWidgetItemIterator::NotHidden | QTreeWidgetItemIterator::NoChildren); + while (*it) + { + if (!(*it)->parent() || (*it)->parent()->isExpanded()) + { // add top level songs and songs in expanded categories clist += (*it); } ++it; } if (clist.length() == 0) - return; + { + return; + } #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) on_music_list_double_clicked(clist.at(qrand() % clist.length()), 1); #else @@ -5100,69 +5619,86 @@ void Courtroom::music_random() #endif } -void Courtroom::music_list_expand_all() { ui_music_list->expandAll(); } +void Courtroom::music_list_expand_all() +{ + ui_music_list->expandAll(); +} void Courtroom::music_list_collapse_all() { ui_music_list->collapseAll(); QTreeWidgetItem *current = ui_music_list->selectedItems()[0]; if (current->parent() != nullptr) + { current = current->parent(); + } ui_music_list->setCurrentItem(current); } void Courtroom::music_stop(bool no_effects) { if (is_muted) + { return; + } // Default fake song is a song present in Vanilla content, the ~stop.mp3 QString fake_song = "~stop.mp3"; // If the fake song is not present in the music list - if (!music_list.contains(fake_song)) { - // Loop through our 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 - fake_song = song; - break; - } + if (!music_list.contains(fake_song)) + { + // Loop through our 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 + fake_song = song; + break; } + } } - QStringList packet_contents; // its music list - packet_contents.append( - fake_song); // this is our fake song, playing it triggers special code + QStringList packet_contents; // its music list + packet_contents.append(fake_song); // this is our fake song, playing it triggers special code packet_contents.append(QString::number(m_cid)); - if ((!ui_ic_chat_name->text().isEmpty() && ao_app->cccc_ic_supported) || - ao_app->effects_supported) + if ((!ui_ic_chat_name->text().isEmpty() && ao_app->cccc_ic_supported) || ao_app->effects_supported) + { packet_contents.append(ui_ic_chat_name->text()); - if (ao_app->effects_supported) { + } + if (ao_app->effects_supported) + { if (no_effects) + { packet_contents.append("0"); + } else + { packet_contents.append(QString::number(music_flags)); + } } - ao_app->send_server_packet(new AOPacket("MC", packet_contents)); + ao_app->send_server_packet(AOPacket("MC", packet_contents)); } void Courtroom::on_area_list_double_clicked(QTreeWidgetItem *p_item, int column) { - column = 0; // The metadata + column = 0; // The metadata Q_UNUSED(column); // so gcc shuts up QString p_area = p_item->text(0); QStringList packet_contents; packet_contents.append(p_area); packet_contents.append(QString::number(m_cid)); - ao_app->send_server_packet(new AOPacket("MC", packet_contents)); + ao_app->send_server_packet(AOPacket("MC", packet_contents)); } void Courtroom::on_hold_it_clicked() { - if (objection_state == 1) { + if (objection_state == 1) + { ui_hold_it->set_image("holdit"); objection_state = 0; } - else { + else + { ui_objection->set_image("objection"); ui_take_that->set_image("takethat"); ui_custom_objection->set_image("custom"); @@ -5176,11 +5712,13 @@ void Courtroom::on_hold_it_clicked() void Courtroom::on_objection_clicked() { - if (objection_state == 2) { + if (objection_state == 2) + { ui_objection->set_image("objection"); objection_state = 0; } - else { + else + { ui_hold_it->set_image("holdit"); ui_take_that->set_image("takethat"); ui_custom_objection->set_image("custom"); @@ -5194,11 +5732,13 @@ void Courtroom::on_objection_clicked() void Courtroom::on_take_that_clicked() { - if (objection_state == 3) { + if (objection_state == 3) + { ui_take_that->set_image("takethat"); objection_state = 0; } - else { + else + { ui_objection->set_image("objection"); ui_hold_it->set_image("holdit"); ui_custom_objection->set_image("custom"); @@ -5212,11 +5752,13 @@ void Courtroom::on_take_that_clicked() void Courtroom::on_custom_objection_clicked() { - if (objection_state == 4) { + if (objection_state == 4) + { ui_custom_objection->set_image("custom"); objection_state = 0; } - else { + else + { ui_objection->set_image("objection"); ui_take_that->set_image("takethat"); ui_hold_it->set_image("holdit"); @@ -5232,16 +5774,22 @@ void Courtroom::show_custom_objection_menu(const QPoint &pos) { QPoint globalPos = ui_custom_objection->mapToGlobal(pos); QAction *selecteditem = custom_obj_menu->exec(globalPos); - if (selecteditem) { + if (selecteditem) + { ui_objection->set_image("objection"); ui_take_that->set_image("takethat"); ui_hold_it->set_image("holdit"); ui_custom_objection->set_image("custom_selected"); if (selecteditem->text() == ao_app->read_char_ini(current_char, "custom_name", "Shouts") || selecteditem->text() == "Default") + { objection_custom = ""; - else { - foreach (CustomObjection custom_objection, custom_objections_list) { - if (custom_objection.name == selecteditem->text()) { + } + else + { + foreach (CustomObjection custom_objection, custom_objections_list) + { + if (custom_objection.name == selecteditem->text()) + { objection_custom = custom_objection.filename; break; } @@ -5254,14 +5802,18 @@ void Courtroom::show_custom_objection_menu(const QPoint &pos) void Courtroom::on_realization_clicked() { - if (realization_state == 0) { + if (realization_state == 0) + { realization_state = 1; if (effects_dropdown_find_and_set("realization")) + { on_effects_dropdown_changed(ui_effects_dropdown->currentIndex()); + } ui_realization->set_image("realization_pressed"); } - else { + else + { realization_state = 0; ui_effects_dropdown->setCurrentIndex(0); on_effects_dropdown_changed(ui_effects_dropdown->currentIndex()); @@ -5273,11 +5825,13 @@ void Courtroom::on_realization_clicked() void Courtroom::on_screenshake_clicked() { - if (screenshake_state == 0) { + if (screenshake_state == 0) + { screenshake_state = 1; ui_screenshake->set_image("screenshake_pressed"); } - else { + else + { screenshake_state = 0; ui_screenshake->set_image("screenshake"); } @@ -5287,7 +5841,8 @@ void Courtroom::on_screenshake_clicked() void Courtroom::on_mute_clicked() { - if (ui_mute_list->isHidden()) { + if (ui_mute_list->isHidden()) + { ui_mute_list->show(); ui_pair_list->hide(); ui_pair_offset_spinbox->hide(); @@ -5296,7 +5851,8 @@ void Courtroom::on_mute_clicked() ui_pair_button->set_image("pair_button"); ui_mute->set_image("mute_pressed"); } - else { + else + { ui_mute_list->hide(); ui_mute->set_image("mute"); } @@ -5304,17 +5860,21 @@ void Courtroom::on_mute_clicked() void Courtroom::on_pair_clicked() { - if (ui_pair_list->isHidden()) { + if (ui_pair_list->isHidden()) + { ui_pair_list->show(); ui_pair_offset_spinbox->show(); - if(ao_app->y_offset_supported) - ui_pair_vert_offset_spinbox->show(); + if (ao_app->y_offset_supported) + { + ui_pair_vert_offset_spinbox->show(); + } ui_pair_order_dropdown->show(); ui_mute_list->hide(); ui_mute->set_image("mute"); ui_pair_button->set_image("pair_button_pressed"); } - else { + else + { ui_pair_list->hide(); ui_pair_offset_spinbox->hide(); ui_pair_vert_offset_spinbox->hide(); @@ -5333,8 +5893,9 @@ void Courtroom::on_defense_minus_clicked() int f_state = defense_bar_state - 1; if (f_state >= 0) - ao_app->send_server_packet( - new AOPacket("HP", {"1", QString::number(f_state)})); + { + ao_app->send_server_packet(AOPacket("HP", {"1", QString::number(f_state)})); + } } void Courtroom::on_defense_plus_clicked() @@ -5342,8 +5903,9 @@ void Courtroom::on_defense_plus_clicked() int f_state = defense_bar_state + 1; if (f_state <= 10) - ao_app->send_server_packet( - new AOPacket("HP", {"1", QString::number(f_state)})); + { + ao_app->send_server_packet(AOPacket("HP", {"1", QString::number(f_state)})); + } } void Courtroom::on_prosecution_minus_clicked() @@ -5351,8 +5913,9 @@ void Courtroom::on_prosecution_minus_clicked() int f_state = prosecution_bar_state - 1; if (f_state >= 0) - ao_app->send_server_packet( - new AOPacket("HP", {"2", QString::number(f_state)})); + { + ao_app->send_server_packet(AOPacket("HP", {"2", QString::number(f_state)})); + } } void Courtroom::on_prosecution_plus_clicked() @@ -5360,23 +5923,24 @@ void Courtroom::on_prosecution_plus_clicked() int f_state = prosecution_bar_state + 1; if (f_state <= 10) - ao_app->send_server_packet( - new AOPacket("HP", {"2", QString::number(f_state)})); + { + ao_app->send_server_packet(AOPacket("HP", {"2", QString::number(f_state)})); + } } void Courtroom::on_text_color_context_menu_requested(const QPoint &pos) { QMenu *menu = new QMenu(this); + menu->setAttribute(Qt::WA_DeleteOnClose); - menu->addAction(QString("Open currently used chat_config.ini"), this, - [=] { + menu->addAction(QString("Open currently used chat_config.ini"), this, [=] { QString p_path = ao_app->get_asset("chat_config.ini", Options::getInstance().theme(), Options::getInstance().subTheme(), ao_app->default_theme, ao_app->get_chat(current_char)); - if (!file_exists(p_path)) { - return; + if (!file_exists(p_path)) + { + return; } QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); - } - ); + }); menu->popup(ui_text_color->mapToGlobal(pos)); } @@ -5396,27 +5960,22 @@ void Courtroom::set_text_color_dropdown() // Update markdown colors. TODO: make a loading function that only loads the // config file once instead of several times - for (int c = 0; c < max_colors; ++c) { - QColor color = - ao_app->get_chat_color("c" + QString::number(c), ao_app->get_chat(current_char)); + for (int c = 0; c < max_colors; ++c) + { + QColor color = ao_app->get_chat_color("c" + QString::number(c), ao_app->get_chat(current_char)); color_rgb_list.append(color); - color_markdown_start_list.append(ao_app->get_chat_markup( - "c" + QString::number(c) + "_start", ao_app->get_chat(current_char))); - color_markdown_end_list.append(ao_app->get_chat_markup( - "c" + QString::number(c) + "_end", ao_app->get_chat(current_char))); - color_markdown_remove_list.append( - ao_app->get_chat_markup("c" + QString::number(c) + "_remove", - ao_app->get_chat(current_char)) == "1"); - color_markdown_talking_list.append( - ao_app->get_chat_markup("c" + QString::number(c) + "_talking", - ao_app->get_chat(current_char)) != "0"); - - QString color_name = ao_app->get_chat_markup( - "c" + QString::number(c) + "_name", ao_app->get_chat(current_char)); + color_markdown_start_list.append(ao_app->get_chat_markup("c" + QString::number(c) + "_start", ao_app->get_chat(current_char))); + color_markdown_end_list.append(ao_app->get_chat_markup("c" + QString::number(c) + "_end", ao_app->get_chat(current_char))); + color_markdown_remove_list.append(ao_app->get_chat_markup("c" + QString::number(c) + "_remove", ao_app->get_chat(current_char)) == "1"); + color_markdown_talking_list.append(ao_app->get_chat_markup("c" + QString::number(c) + "_talking", ao_app->get_chat(current_char)) != "0"); + + QString color_name = ao_app->get_chat_markup("c" + QString::number(c) + "_name", ao_app->get_chat(current_char)); if (color_name.isEmpty()) // Not defined { if (c > 0) + { continue; + } color_name = tr("Default"); } ui_text_color->addItem(color_name); @@ -5425,15 +5984,18 @@ void Courtroom::set_text_color_dropdown() ui_text_color->setItemIcon(ui_text_color->count() - 1, pixmap); color_row_to_number.append(c); } - for (int c = 0; c < max_colors; ++c) { + for (int c = 0; c < max_colors; ++c) + { QColor color = ao_app->get_chat_color("c" + QString::number(c), ""); default_color_rgb_list.append(color); } } -void Courtroom::gen_char_rgb_list(QString p_misc) { +void Courtroom::gen_char_rgb_list(QString p_misc) +{ char_color_rgb_list.clear(); - for (int c = 0; c < max_colors; ++c) { + for (int c = 0; c < max_colors; ++c) + { QColor color = ao_app->get_chat_color("c" + QString::number(c), p_misc); char_color_rgb_list.append(color); } @@ -5445,14 +6007,17 @@ void Courtroom::on_text_color_changed(int p_color) { int c = color_row_to_number.at(p_color); QString markdown_start = color_markdown_start_list.at(c); - if (markdown_start.isEmpty()) { + if (markdown_start.isEmpty()) + { qWarning() << "Color list dropdown selected a non-existent markdown " - "start character"; + "start character"; return; } QString markdown_end = color_markdown_end_list.at(c); if (markdown_end.isEmpty()) + { markdown_end = markdown_start; + } int start = ui_ic_chat_message->selectionStart(); #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) int end = ui_ic_chat_message->selectionEnd() + 1; @@ -5467,11 +6032,16 @@ void Courtroom::on_text_color_changed(int p_color) // ui_ic_chat_message->end(false); ui_text_color->setCurrentIndex(0); } - else { + else + { if (p_color != -1 && p_color < color_row_to_number.size()) + { text_color = color_row_to_number.at(p_color); + } else + { text_color = 0; + } } ui_ic_chat_message->setFocus(); } @@ -5486,7 +6056,8 @@ void Courtroom::on_sfx_slider_moved(int p_value) { sfx_player->set_volume(p_value); // Set the ambience and other misc. music layers - for (int i = 1; i < music_player->m_channelmax; ++i) { + for (int i = 1; i < music_player->CHANNEL_COUNT; ++i) + { music_player->set_volume(p_value, i); } objection_player->set_volume(p_value); @@ -5499,9 +6070,15 @@ void Courtroom::on_blip_slider_moved(int p_value) ui_ic_chat_message->setFocus(); } -void Courtroom::on_log_limit_changed(int value) { log_maximum_blocks = value; } +void Courtroom::on_log_limit_changed(int value) +{ + log_maximum_blocks = value; +} -void Courtroom::on_pair_offset_changed(int value) { char_offset = value; } +void Courtroom::on_pair_offset_changed(int value) +{ + char_offset = value; +} void Courtroom::on_pair_vert_offset_changed(int value) { @@ -5511,9 +6088,11 @@ void Courtroom::on_pair_vert_offset_changed(int value) void Courtroom::on_witness_testimony_clicked() { if (is_muted) + { return; + } - ao_app->send_server_packet(new AOPacket("RT", {"testimony1"})); + ao_app->send_server_packet(AOPacket("RT", {"testimony1"})); ui_ic_chat_message->setFocus(); } @@ -5521,9 +6100,11 @@ void Courtroom::on_witness_testimony_clicked() void Courtroom::on_cross_examination_clicked() { if (is_muted) + { return; + } - ao_app->send_server_packet(new AOPacket("RT", {"testimony2"})); + ao_app->send_server_packet(AOPacket("RT", {"testimony2"})); ui_ic_chat_message->setFocus(); } @@ -5531,9 +6112,11 @@ void Courtroom::on_cross_examination_clicked() void Courtroom::on_not_guilty_clicked() { if (is_muted) + { return; + } - ao_app->send_server_packet(new AOPacket("RT", {"judgeruling", "0"})); + ao_app->send_server_packet(AOPacket("RT", {"judgeruling", "0"})); ui_ic_chat_message->setFocus(); } @@ -5541,9 +6124,11 @@ void Courtroom::on_not_guilty_clicked() void Courtroom::on_guilty_clicked() { if (is_muted) + { return; + } - ao_app->send_server_packet(new AOPacket("RT", {"judgeruling", "1"})); + ao_app->send_server_packet(AOPacket("RT", {"judgeruling", "1"})); ui_ic_chat_message->setFocus(); } @@ -5588,11 +6173,15 @@ void Courtroom::on_char_select_right_clicked() set_char_select_page(); } -void Courtroom::on_spectator_clicked() { char_clicked(-1); } +void Courtroom::on_spectator_clicked() +{ + char_clicked(-1); +} void Courtroom::on_call_mod_clicked() { - if (ao_app->modcall_reason_supported) { + if (ao_app->modcall_reason_supported) + { QMessageBox errorBox; QInputDialog input; @@ -5602,14 +6191,18 @@ void Courtroom::on_call_mod_clicked() auto code = input.exec(); if (code != QDialog::Accepted) + { return; + } QString text = input.textValue(); - if (text.isEmpty()) { + if (text.isEmpty()) + { errorBox.critical(nullptr, tr("Error"), tr("You must provide a reason.")); return; } - else if (text.length() > 256) { + else if (text.length() > 256) + { errorBox.critical(nullptr, tr("Error"), tr("The message is too long.")); return; } @@ -5617,24 +6210,35 @@ void Courtroom::on_call_mod_clicked() QStringList mod_reason; mod_reason.append(text); - ao_app->send_server_packet(new AOPacket("ZZ", mod_reason)); + ao_app->send_server_packet(AOPacket("ZZ", mod_reason)); } - else { - ao_app->send_server_packet(new AOPacket("ZZ")); + else + { + ao_app->send_server_packet(AOPacket("ZZ")); } ui_ic_chat_message->setFocus(); } -void Courtroom::on_settings_clicked() { ao_app->call_settings_menu(); } +void Courtroom::on_settings_clicked() +{ + ao_app->call_settings_menu(); +} -void Courtroom::on_pre_clicked() { ui_ic_chat_message->setFocus(); } +void Courtroom::on_pre_clicked() +{ + ui_ic_chat_message->setFocus(); +} -void Courtroom::on_flip_clicked() { ui_ic_chat_message->setFocus(); } +void Courtroom::on_flip_clicked() +{ + ui_ic_chat_message->setFocus(); +} void Courtroom::on_additive_clicked() { - if (ui_additive->isChecked()) { + if (ui_additive->isChecked()) + { ui_ic_chat_message->home(false); // move cursor to the start of the message ui_ic_chat_message->insert(" "); // preface the message by whitespace ui_ic_chat_message->end(false); // move cursor to the end of the message @@ -5643,7 +6247,10 @@ void Courtroom::on_additive_clicked() ui_ic_chat_message->setFocus(); } -void Courtroom::on_guard_clicked() { ui_ic_chat_message->setFocus(); } +void Courtroom::on_guard_clicked() +{ + ui_ic_chat_message->setFocus(); +} void Courtroom::on_showname_enable_clicked() { @@ -5655,24 +6262,23 @@ void Courtroom::regenerate_ic_chatlog() { ui_ic_chatlog->clear(); last_ic_message = ""; - foreach (chatlogpiece item, ic_chatlog_history) { - QString message = item.get_message(); - QString name = ui_showname_enable->isChecked() ? item.get_showname() - : item.get_name(); - append_ic_text(message, - name, - item.get_action(), item.get_chat_color(), - item.get_selfname(), item.get_datetime().toLocalTime()); + foreach (ChatLogPiece item, ic_chatlog_history) + { + QString message = item.message; + QString name = ui_showname_enable->isChecked() ? item.showname : item.name; + append_ic_text(message, name, item.action, item.color, item.selfname, item.datetime.toLocalTime()); } } void Courtroom::on_evidence_button_clicked() { - if (ui_evidence->isHidden()) { + if (ui_evidence->isHidden()) + { ui_evidence->show(); ui_evidence_overlay->hide(); } - else { + else + { ui_evidence->hide(); } } @@ -5680,61 +6286,55 @@ void Courtroom::on_evidence_button_clicked() void Courtroom::on_evidence_context_menu_requested(const QPoint &pos) { QMenu *menu = new QMenu(this); - menu->addAction(QString("Open base evidence folder"), this, - [=] { + menu->setAttribute(Qt::WA_DeleteOnClose, true); + menu->addAction(QString("Open base evidence folder"), this, [=] { QString p_path = get_base_path() + "evidence/"; - if (!dir_exists(p_path)) { + if (!dir_exists(p_path)) + { return; } QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); - } - ); + }); menu->popup(ui_evidence_button->mapToGlobal(pos)); } void Courtroom::on_switch_area_music_clicked() { - if (ui_area_list->isHidden()) { + if (ui_area_list->isHidden()) + { ui_area_list->show(); ui_music_list->hide(); last_music_search = ui_music_search->text(); ui_music_search->setText(last_area_search); } - else { + else + { ui_area_list->hide(); ui_music_list->show(); last_area_search = ui_music_search->text(); ui_music_search->setText(last_music_search); } on_music_search_edited(ui_music_search->text()); - } void Courtroom::ping_server() { ping_timer.start(); is_pinging = true; - ao_app->send_server_packet( - new AOPacket("CH", {QString::number(m_cid)})); + ao_app->send_server_packet(AOPacket("CH", {QString::number(m_cid)})); } qint64 Courtroom::pong() { if (!is_pinging) + { return -1; + } is_pinging = false; return ping_timer.elapsed(); } -void Courtroom::start_clock(int id) -{ - if (id >= 0 && id < max_clocks && ui_clock[id] != nullptr) - { - ui_clock[id]->start(); - } -} - void Courtroom::start_clock(int id, qint64 msecs) { if (id >= 0 && id < max_clocks && ui_clock[id] != nullptr) @@ -5755,10 +6355,13 @@ void Courtroom::set_clock(int id, qint64 msecs) void Courtroom::skip_clocks(qint64 msecs) { // Loop through all the timers - for (int i = 0; i < max_clocks; i++) { + for (int i = 0; i < max_clocks; i++) + { // Only skip time on active clocks if (ui_clock[i]->active()) + { ui_clock[i]->skip(msecs); + } } } @@ -5789,25 +6392,22 @@ void Courtroom::set_clock_visibility(int id, bool visible) void Courtroom::truncate_label_text(QWidget *p_widget, QString p_identifier) { QString filename = "courtroom_design.ini"; - pos_size_type design_ini_result = - ao_app->get_element_dimensions(p_identifier, filename); + pos_size_type design_ini_result = ao_app->get_element_dimensions(p_identifier, filename); // Get the width of the element as defined by the current theme // Cast to make sure we're working with one of the two supported widget types QLabel *p_label = qobject_cast<QLabel *>(p_widget); QCheckBox *p_checkbox = qobject_cast<QCheckBox *>(p_widget); - if (p_checkbox == nullptr && - p_label == - nullptr) { // i.e. the given p_widget isn't a QLabel or a QCheckBox + if (p_checkbox == nullptr && p_label == nullptr) + { // i.e. the given p_widget isn't a QLabel or a QCheckBox qWarning() << "Tried to truncate an unsupported widget:" << p_identifier; return; } // translate the text for the widget we're working with so we truncate the right string - QString label_text_tr = - QCoreApplication::translate(p_widget->metaObject()->className(), "%1") - .arg((p_label != nullptr ? p_label->text() : p_checkbox->text())); - if (label_text_tr.endsWith("…") || label_text_tr.endsWith("…")) { + QString label_text_tr = QCoreApplication::translate(p_widget->metaObject()->className(), "%1").arg((p_label != nullptr ? p_label->text() : p_checkbox->text())); + if (label_text_tr.endsWith("…") || label_text_tr.endsWith("…")) + { qInfo() << "Truncation aborted for label text" << label_text_tr << ", label text was already truncated!"; return; } @@ -5815,54 +6415,43 @@ void Courtroom::truncate_label_text(QWidget *p_widget, QString p_identifier) int checkbox_width = AOApplication::style()->pixelMetric(QStyle::PM_IndicatorWidth) + AOApplication::style()->pixelMetric(QStyle::PM_CheckBoxLabelSpacing); int label_theme_width = (p_label != nullptr ? design_ini_result.width : (design_ini_result.width - checkbox_width)); - int label_px_width = - p_widget->fontMetrics().boundingRect(label_text_tr).width(); // pixel width of our translated text - if (!p_widget->toolTip().startsWith(label_text_tr)) // don't want to append this multiple times + int label_px_width = p_widget->fontMetrics().boundingRect(label_text_tr).width(); // pixel width of our translated text + if (!p_widget->toolTip().startsWith(label_text_tr)) // don't want to append this multiple times + { p_widget->setToolTip(label_text_tr + "\n" + p_widget->toolTip()); + } // we can't do much with a 0-width widget, and there's no need to truncate if // the theme gives us enough space - if (label_theme_width <= 0 || label_px_width < label_theme_width) { - qDebug().nospace() << "Truncation aborted for label text " << label_text_tr - << ", either theme width <= 0 or label width < theme width."; + if (label_theme_width <= 0 || label_px_width < label_theme_width) + { + qDebug().nospace() << "Truncation aborted for label text " << label_text_tr << ", either theme width <= 0 or label width < theme width."; return; } QString truncated_label = label_text_tr; int truncated_px_width = label_px_width; - while (truncated_px_width > label_theme_width && truncated_label != "…") { + while (truncated_px_width > label_theme_width && truncated_label != "…") + { truncated_label.chop(2); truncated_label.append("…"); - truncated_px_width = - p_widget->fontMetrics().boundingRect(truncated_label).width(); + truncated_px_width = p_widget->fontMetrics().boundingRect(truncated_label).width(); } - if (truncated_label == "…") { + if (truncated_label == "…") + { // Safeguard against edge case where label text is shorter in px than '…', // causing an infinite loop. Additionally, having just an ellipse for a // label looks strange, so we don't set the new label. - qWarning() << "Potential infinite loop prevented: Label text " - << label_text_tr - << "truncated to '…', so truncation was aborted."; + qWarning() << "Potential infinite loop prevented: Label text " << label_text_tr << "truncated to '…', so truncation was aborted."; return; } if (p_label != nullptr) + { p_label->setText(truncated_label); + } else if (p_checkbox != nullptr) + { p_checkbox->setText(truncated_label); - qDebug().nospace() << "Truncated label text from " << label_text_tr << " (" - << label_px_width << "px) to " << truncated_label << " (" - << truncated_px_width << "px)"; -} - -Courtroom::~Courtroom() -{ - //save sound settings - Options::getInstance().setMusicVolume(ui_music_slider->value()); - Options::getInstance().setSfxVolume(ui_sfx_slider->value()); - Options::getInstance().setBlipVolume(ui_blip_slider->value()); - - delete music_player; - delete sfx_player; - delete objection_player; - delete blip_player; + } + qDebug().nospace() << "Truncated label text from " << label_text_tr << " (" << label_px_width << "px) to " << truncated_label << " (" << truncated_px_width << "px)"; } diff --git a/src/courtroom.h b/src/courtroom.h new file mode 100644 index 00000000..cdcd1e11 --- /dev/null +++ b/src/courtroom.h @@ -0,0 +1,964 @@ +#pragma once + +#include "aoapplication.h" +#include "aoblipplayer.h" +#include "aobutton.h" +#include "aocharbutton.h" +#include "aoclocklabel.h" +#include "aoemotebutton.h" +#include "aoemotepreview.h" +#include "aoevidencebutton.h" +#include "aoevidencedisplay.h" +#include "aoimage.h" +#include "aolayer.h" +#include "aomusicplayer.h" +#include "aopacket.h" +#include "aosfxplayer.h" +#include "aotextarea.h" +#include "aotextboxwidgets.h" +#include "chatlogpiece.h" +#include "datatypes.h" +#include "debug_functions.h" +#include "eventfilters.h" +#include "file_functions.h" +#include "hardware_functions.h" +#include "lobby.h" +#include "scrolltext.h" +#include "widgets/aooptionsdialog.h" + +#include <QCheckBox> +#include <QCloseEvent> +#include <QComboBox> +#include <QHeaderView> +#include <QLineEdit> +#include <QListWidget> +#include <QMainWindow> +#include <QMap> +#include <QPlainTextEdit> +#include <QQueue> +#include <QSlider> +#include <QSpinBox> +#include <QTextBrowser> +#include <QTreeWidget> +#include <QVector> + +#include <QBrush> +#include <QDebug> +#include <QDesktopServices> +#include <QFileDialog> +#include <QFont> +#include <QInputDialog> +#include <QMenu> +#include <QMessageBox> +#include <QParallelAnimationGroup> +#include <QPropertyAnimation> +#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) +#include <QRandomGenerator> //added in Qt 5.10 +#endif +#include <QElapsedTimer> +#include <QRegularExpression> +#include <QScrollBar> +#include <QTextBoundaryFinder> +#include <QTextCharFormat> + +#include <QFuture> + +#include <algorithm> +#include <stack> + +class AOApplication; + +class Courtroom : public QMainWindow +{ + Q_OBJECT + +public: + explicit Courtroom(AOApplication *p_ao_app); + ~Courtroom(); + + void update_audio_volume(); + + void append_char(char_type p_char); + void append_music(QString f_music); + void append_area(QString f_area); + void clear_chars(); + void clear_music(); + void clear_areas(); + + void fix_last_area(); + + void arup_append(int players, QString status, QString cm, QString locked); + + void arup_clear(); + + void arup_modify(int type, int place, QString value); + + void character_loading_finished(); + + void set_courtroom_size(); + + // sets position of widgets based on theme ini files + void set_widgets(); + + // sets font size based on theme ini files + void set_font(QWidget *widget, QString class_name, QString p_identifier, QString p_char = QString(), QString font_name = QString(), int f_pointsize = 0); + + // Get the properly constructed font + QFont get_qfont(QString font_name, int f_pointsize, bool antialias = true); + + // actual operation of setting the font on a widget + void set_qfont(QWidget *widget, QString class_name, QFont font, QColor f_color = Qt::black, bool bold = false, bool outlined = false, QColor outline_color = QColor(0, 0, 0), int outline_width = 1); + + // helper function that calls above function on the relevant widgets + void set_fonts(QString p_char = QString()); + + // sets dropdown menu stylesheet + void set_stylesheet(QWidget *widget); + + // helper funciton that call above function on the relevant widgets + void set_stylesheets(); + + void set_window_title(QString p_title); + + // reads theme and sets size and pos based on the identifier (using p_misc if provided) + void set_size_and_pos(QWidget *p_widget, QString p_identifier, QString p_misc = QString()); + + // sets status as taken on character with cid n_char and places proper shading + // on charselect + void set_taken(int n_char, bool p_taken); + + // sets the current background to argument. also does some checks to see if + // it's a legacy bg + void set_background(QString p_background, bool display = false); + + // sets the local character pos/side to use. + void set_side(QString p_side); + + // sets the pos dropdown + void set_pos_dropdown(QStringList pos_dropdowns); + + // sets the evidence list member variable to argument + void set_evidence_list(QVector<evi_type> &p_evi_list); + + // called when a DONE#% from the server was received + void done_received(); + + // sets the local mute list based on characters available on the server + void set_mute_list(); + + // Sets the local pair list based on the characters available on the server. + void set_pair_list(); + + // sets desk and bg based on pos in chatmessage + void set_scene(bool show_desk, QString f_side); + + // sets ui_vp_player_char according to SELF_OFFSET, only a function bc it's used with desk_mod 4 and 5 + void set_self_offset(const QString &p_list); + + // takes in serverD-formatted IP list as prints a converted version to server + // OOC admittedly poorly named + void set_ip_list(QString p_list); + + // disables chat if current cid matches second argument + // enables if p_muted is false + void set_mute(bool p_muted, int p_cid); + + // cid = character id, returns the cid of the currently selected character + QString get_current_char(); + QString get_current_background(); + + // updates character to p_cid and updates necessary ui elements + // Optional "char_name" is the iniswap we're using + void update_character(int p_cid, QString char_name = QString(), bool reset_emote = false); + + // properly sets up some varibles: resets user state + void enter_courtroom(); + + // helper function that populates ui_music_list with the contents of + // music_list + void list_music(); + void list_areas(); + + // Debug log (formerly master server chat log) + void debug_message_handler(QtMsgType type, const QMessageLogContext &context, const QString &msg); + + // OOC chat log + void append_server_chatmessage(QString p_name, QString p_message, QString p_color); + + // Add the message packet to the stack + void chatmessage_enqueue(QStringList p_contents); + + // Parse the chat message packet and unpack it into the m_chatmessage[ITEM] format + void unpack_chatmessage(QStringList p_contents); + + // Skip the current queue, adding all the queue messages to the logs if desynchronized logs are disabled + void skip_chatmessage_queue(); + + enum LogMode + { + IO_ONLY, + DISPLAY_ONLY, + DISPLAY_AND_IO, + QUEUED, + }; + // Log the message contents and information such as evidence presenting etc. into the log file, the IC log, or both. + void log_chatmessage(QString f_message, int f_char_id, QString f_showname = QString(), QString f_char = QString(), QString f_objection_mod = QString(), int f_evi_id = 0, int f_color = 0, LogMode f_log_mode = IO_ONLY, bool sender = false); + + // Log the message contents and information such as evidence presenting etc. into the IC logs + void handle_callwords(); + + // Handle the objection logic, if it's interrupting the currently parsing message. + // Returns true if this message has an objection, otherwise returns false. The result decides when to call handle_ic_message() + bool handle_objection(); + + // Display the evidence image box when presenting evidence in IC + void display_evidence_image(); + + // Handle the stuff that comes when the character appears on screen and starts animating (preanims etc.) + void handle_ic_message(); + + // Display the character. + void display_character(); + + // Display the character's pair if present. + void display_pair_character(QString other_charid, QString other_offset); + + // Handle the emote modifier value and proceed through the logic accordingly. + void handle_emote_mod(int emote_mod, bool p_immediate); + + // Initialize the chatbox image, showname shenanigans, custom chatboxes, etc. + void initialize_chatbox(); + + // Finally start displaying the chatbox we initialized, display the evidence, and play the talking or idle emote for the character. + // Callwords are also handled here. + void handle_ic_speaking(); + + // This function filters out the common CC inline text trickery, for appending + // to the IC chatlog. + QString filter_ic_text(QString p_text, bool colorize = false, int pos = -1, int default_color = 0); + + void log_ic_text(QString p_name, QString p_showname, QString p_message, QString p_action = QString(), int p_color = 0, bool p_selfname = false); + + // adds text to the IC chatlog. p_name first as bold then p_text then a newlin + // this function keeps the chatlog scrolled to the top unless there's text + // selected + // or the user isn't already scrolled to the top + void append_ic_text(QString p_text, QString p_name = QString(), QString action = QString(), int color = 0, bool selfname = false, QDateTime timestamp = QDateTime::currentDateTime(), bool ghost = false); + + // clear sent messages that appear on the IC log but haven't been delivered + // yet to other players + void pop_ic_ghost(); + + // prints who played the song to IC chat and plays said song(if found on local + // filesystem) takes in a list where the first element is the song name and + // the second is the char id of who played it + void handle_song(QStringList *p_contents); + + void play_preanim(bool immediate); + + // plays the witness testimony or cross examination animation based on + // argument + void handle_wtce(QString p_wtce, int variant); + + // sets the hp bar of defense(p_bar 1) or pro(p_bar 2) + // state is an number between 0 and 10 inclusive + void set_hp_bar(int p_bar, int p_state); + + // Toggles the judge buttons, whether they should appear or not. + void show_judge_controls(bool visible); + + void start_clock(int id, qint64 msecs); + void set_clock(int id, qint64 msecs); + void pause_clock(int id); + void stop_clock(int id); + void set_clock_visibility(int id, bool visible); + void skip_clocks(qint64 msecs); + + qint64 pong(); + // Truncates text so it fits within theme-specified boundaries and sets the tooltip to the full string + void truncate_label_text(QWidget *p_widget, QString p_identifier); + + void on_authentication_state_received(int p_state); + + enum JudgeState + { + POS_DEPENDENT = -1, + HIDE_CONTROLS = 0, + SHOW_CONTROLS = 1 + }; + + JudgeState get_judge_state(); + void set_judge_state(JudgeState new_state); + void set_judge_buttons(); + +private: + AOApplication *ao_app; + + // Percentage of audio that is suppressed when client is not in focus + int suppress_audio = 0; + + int m_courtroom_width = 714; + int m_courtroom_height = 668; + + int m_viewport_x = 0; + int m_viewport_y = 0; + + int m_viewport_width = 256; + int m_viewport_height = 192; + + int maximumMessages = 0; + + QParallelAnimationGroup *screenshake_animation_group = new QParallelAnimationGroup; + + bool next_character_is_not_special = false; // If true, write the + // next character as it is. + + bool message_is_centered = false; + + int current_display_speed = 3; + int text_crawl = 40; + double message_display_mult[7] = {0, 0.25, 0.65, 1, 1.25, 1.75, 2.25}; + + // The character ID of the character this user wants to appear alongside with. + int other_charid = -1; + + // The horizontal offset this user has given if they want to appear alongside someone. + int char_offset = 0; + + // The vertical offset this user has given. + int char_vert_offset = 0; + + // 0 = in front, 1 = behind + int pair_order = 0; + + QVector<char_type> char_list; + QVector<evi_type> evidence_list; + QVector<QString> music_list; + QVector<QString> area_list; + + QVector<int> arup_players; + QVector<QString> arup_statuses; + QVector<QString> arup_cms; + QVector<QString> arup_locks; + + QVector<ChatLogPiece> ic_chatlog_history; + QString last_ic_message; + + QQueue<QStringList> chatmessage_queue; + + // triggers ping_server() every 45 seconds + QTimer *keepalive_timer; + + // determines how fast messages tick onto screen + QTimer *chat_tick_timer; + + // count up timer to check how long it took for us to get a response from ping_server() + QElapsedTimer ping_timer; + bool is_pinging = false; + + // int chat_tick_interval = 60; + // which tick position(character in chat message) we are at + int tick_pos = 0; + // the actual document tick pos we gotta worry about for making the text + // scroll better + int real_tick_pos = 0; + // used to determine how often blips sound + int blip_ticker = 0; + int blip_rate = 2; + int rainbow_counter = 0; + bool rainbow_appended = false; + bool blank_blip = false; + bool chatbox_always_show = false; + + // Used for getting the current maximum blocks allowed in the IC chatlog. + int log_maximum_blocks = 0; + + // True, if the log should go downwards. + bool log_goes_downwards = true; + + // True, if log should display colors. + bool log_colors = true; + + // True, if the log should display the message like name<br>text instead of + // name: text + bool log_newline = false; + + // True, if the log should include RP actions like interjections, showing evidence, etc. + bool log_ic_actions = true; + + // Margin in pixels between log entries for the IC log. + int log_margin = 0; + + // True, if the log should have a timestamp. + bool log_timestamp = false; + + // format string for aforementioned log timestamp + QString log_timestamp_format; + + // How long in miliseconds should the objection wait before appearing. + int objection_threshold = 1500; + + // delay before chat messages starts ticking + QTimer *text_delay_timer; + + // delay before the next queue entry is going to be processed + QTimer *text_queue_timer; + + // delay before sfx plays + QTimer *sfx_delay_timer; + + // every time point in char.inis times this equals the final time + const int time_mod = 40; + + // the amount of time non-animated objection/hold it/takethat images stay + // onscreen for in ms, and the maximum amount of time any interjections are + // allowed to play + const int shout_static_time = 724; + const int shout_max_time = 1500; + + // the amount of time non-animated guilty/not guilty images stay onscreen for + // in ms, and the maximum amount of time g/ng images are allowed to play + const int verdict_static_time = 3000; + const int verdict_max_time = 4000; + + // the amount of time non-animated witness testimony/cross-examination images + // stay onscreen for in ms, and the maximum time any wt/ce image is allowed to + // play + const int wtce_static_time = 1500; + const int wtce_max_time = 4000; + + // characters we consider punctuation + const QString punctuation_chars = ".,?!:;"; + + // amount by which we multiply the delay when we parse punctuation chars + const int punctuation_modifier = 3; + + // amount of ghost blocks + int ghost_blocks = 0; + + // Minumum and maximum number of parameters in the MS packet + static const int MS_MINIMUM = 15; + static const int MS_MAXIMUM = 30; + QString m_chatmessage[MS_MAXIMUM]; + + QString previous_ic_message; + QString additive_previous; + + // char id, muted or not + QMap<int, bool> mute_map; + + // QVector<int> muted_cids; + + bool is_muted = false; + + JudgeState judge_state = POS_DEPENDENT; + + // state of animation, 0 = objecting, 1 = preanim, 2 = talking, 3 = idle, 4 = + // noniterrupting preanim, 5 = (c) animation + int anim_state = 3; + + // whether or not current color is a talking one + bool color_is_talking = true; + + // state of text ticking, 0 = not yet ticking, 1 = ticking in progress, 2 = + // ticking done + int text_state = 2; + + // character id, which index of the char_list the player is + int m_cid = -1; + // cid and this may differ in cases of ini-editing + QString current_char; + + int objection_state = 0; + QString objection_custom; + struct CustomObjection + { + QString name; + QString filename; + }; + QList<CustomObjection> custom_objections_list; + int realization_state = 0; + int screenshake_state = 0; + int text_color = 0; + + // How many unique user colors are possible + static const int max_colors = 12; + + // Text Color-related optimization: + // Current color list indexes to real color references + QVector<int> color_row_to_number; + + // List of associated RGB colors for this color index + QVector<QColor> color_rgb_list; + + // Same as above but populated from misc/default's config + QVector<QColor> default_color_rgb_list; + + // Get a color index from an arbitrary misc config + void gen_char_rgb_list(QString p_misc); + QVector<QColor> char_color_rgb_list; + + // Misc we used for the last message, and the one we're using now. Used to avoid loading assets when it's not needed + QString current_misc; + QString last_misc; + + // List of markdown start characters, their index is tied to the color index + QStringList color_markdown_start_list; + + // List of markdown end characters, their index is tied to the color index + QStringList color_markdown_end_list; + + // Whether or not we're supposed to remove this char during parsing + QVector<bool> color_markdown_remove_list; + + // Whether or not this color allows us to play the talking animation + QVector<bool> color_markdown_talking_list; + // Text Color-related optimization END + + // List of all currently available pos + QStringList pos_dropdown_list; + + // Current list file sorted line by line + QStringList sound_list; + + // Current SFX the user put in for the sfx dropdown list + QString custom_sfx; + + // is the message we're about to send supposed to present evidence? + bool is_presenting_evidence = false; + bool c_played = false; // whether we've played a (c)-style postanimation yet + + // have we already presented evidence for this message? + bool evidence_presented = false; + + QString effect; + + // Music effect flags we want to send to server when we play music + int music_flags = FADE_OUT; + + int defense_bar_state = 0; + int prosecution_bar_state = 0; + + int current_char_page = 0; + int char_columns = 10; + int char_rows = 9; + int max_chars_on_page = 90; + + const int button_width = 60; + const int button_height = 60; + + int current_emote_page = 0; + int current_emote = 0; + int emote_columns = 5; + int emote_rows = 2; + int max_emotes_on_page = 10; + + QVector<evi_type> local_evidence_list; + QVector<evi_type> private_evidence_list; + QVector<evi_type> global_evidence_list; + + // false = use private_evidence_list + bool current_evidence_global = true; + + int current_evidence_page = 0; + int current_evidence = 0; + int evidence_columns = 6; + int evidence_rows = 3; + int max_evidence_on_page = 18; + + // whether the ooc chat is server or master chat, true is server + bool server_ooc = true; + + QString current_background = "default"; + QString current_side; + + QString last_music_search; + QString last_area_search; + + QBrush free_brush; + QBrush lfp_brush; + QBrush casing_brush; + QBrush recess_brush; + QBrush rp_brush; + QBrush gaming_brush; + QBrush locked_brush; + + AOMusicPlayer *music_player; + AOSfxPlayer *sfx_player; + AOSfxPlayer *objection_player; + AOBlipPlayer *blip_player; + + AOSfxPlayer *modcall_player; + + AOImage *ui_background; + + QWidget *ui_viewport; + BackgroundLayer *ui_vp_background; + SplashLayer *ui_vp_speedlines; + CharLayer *ui_vp_player_char; + CharLayer *ui_vp_sideplayer_char; + BackgroundLayer *ui_vp_desk; + AOEvidenceDisplay *ui_vp_evidence_display; + AOImage *ui_vp_chatbox; + AOChatboxLabel *ui_vp_showname; + InterfaceLayer *ui_vp_chat_arrow; + QTextEdit *ui_vp_message; + SplashLayer *ui_vp_testimony; + SplashLayer *ui_vp_wtce; + EffectLayer *ui_vp_effect; + SplashLayer *ui_vp_objection; + + QTextEdit *ui_ic_chatlog; + + AOTextArea *ui_debug_log; + AOTextArea *ui_server_chatlog; + + QListWidget *ui_mute_list; + QTreeWidget *ui_area_list; + QTreeWidget *ui_music_list; + + ScrollText *ui_music_name; + InterfaceLayer *ui_music_display; + + StickerLayer *ui_vp_sticker; + + static const int max_clocks = 5; + AOClockLabel *ui_clock[max_clocks]; + + AOButton *ui_pair_button; + QListWidget *ui_pair_list; + QSpinBox *ui_pair_offset_spinbox; + QSpinBox *ui_pair_vert_offset_spinbox; + + QComboBox *ui_pair_order_dropdown; + + QLineEdit *ui_ic_chat_message; + AOLineEditFilter *ui_ic_chat_message_filter; + QLineEdit *ui_ic_chat_name; + + QLineEdit *ui_ooc_chat_message; + QLineEdit *ui_ooc_chat_name; + + // QLineEdit *ui_area_password; + QLineEdit *ui_music_search; + + QWidget *ui_emotes; + QVector<AOEmoteButton *> ui_emote_list; + AOButton *ui_emote_left; + AOButton *ui_emote_right; + + QMenu *emote_menu; + AOEmotePreview *emote_preview; + + QComboBox *ui_emote_dropdown; + QComboBox *ui_pos_dropdown; + AOButton *ui_pos_remove; + + QComboBox *ui_iniswap_dropdown; + AOButton *ui_iniswap_remove; + + QComboBox *ui_sfx_dropdown; + AOButton *ui_sfx_remove; + + QComboBox *ui_effects_dropdown; + + AOImage *ui_defense_bar; + AOImage *ui_prosecution_bar; + + QLabel *ui_music_label; + QLabel *ui_sfx_label; + QLabel *ui_blip_label; + + AOButton *ui_hold_it; + AOButton *ui_objection; + AOButton *ui_take_that; + + AOButton *ui_ooc_toggle; + + AOButton *ui_witness_testimony; + AOButton *ui_cross_examination; + AOButton *ui_guilty; + AOButton *ui_not_guilty; + + AOButton *ui_change_character; + AOButton *ui_reload_theme; + AOButton *ui_call_mod; + AOButton *ui_settings; + AOButton *ui_switch_area_music; + + QCheckBox *ui_pre; + QCheckBox *ui_flip; + QCheckBox *ui_additive; + QCheckBox *ui_guard; + + QCheckBox *ui_immediate; + QCheckBox *ui_showname_enable; + + AOButton *ui_custom_objection; + QMenu *custom_obj_menu; + AOButton *ui_realization; + AOButton *ui_screenshake; + AOButton *ui_mute; + + AOButton *ui_defense_plus; + AOButton *ui_defense_minus; + + AOButton *ui_prosecution_plus; + AOButton *ui_prosecution_minus; + + QComboBox *ui_text_color; + + QSlider *ui_music_slider; + QSlider *ui_sfx_slider; + QSlider *ui_blip_slider; + + AOImage *ui_muted; + + AOButton *ui_evidence_button; + AOImage *ui_evidence; + QLineEdit *ui_evidence_name; + AOLineEditFilter *ui_evidence_name_filter; + QWidget *ui_evidence_buttons; + QVector<AOEvidenceButton *> ui_evidence_list; + AOButton *ui_evidence_left; + AOButton *ui_evidence_right; + AOButton *ui_evidence_present; + AOImage *ui_evidence_overlay; + AOButton *ui_evidence_delete; + QLineEdit *ui_evidence_image_name; + AOLineEditFilter *ui_evidence_image_name_filter; + AOButton *ui_evidence_image_button; + AOButton *ui_evidence_x; + AOButton *ui_evidence_ok; + AOButton *ui_evidence_switch; + AOButton *ui_evidence_transfer; + AOButton *ui_evidence_save; + AOButton *ui_evidence_load; + QPlainTextEdit *ui_evidence_description; + + AOImage *ui_char_select_background; + + // pretty list of characters + QTreeWidget *ui_char_list; + + // abstract widget to hold char buttons + QWidget *ui_char_buttons; + + QVector<AOCharButton *> ui_char_button_list; + QVector<AOCharButton *> ui_char_button_list_filtered; + + AOButton *ui_back_to_lobby; + + QLineEdit *ui_char_password; + + AOButton *ui_char_select_left; + AOButton *ui_char_select_right; + + AOButton *ui_spectator; + + QLineEdit *ui_char_search; + QCheckBox *ui_char_passworded; + QCheckBox *ui_char_taken; + + void construct_char_select(); + void set_char_select(); + void set_char_select_page(); + void char_clicked(int n_char); + void on_char_button_context_menu_requested(const QPoint &pos); + void put_button_in_place(int starting, int chars_on_this_page); + void filter_character_list(); + + void initialize_emotes(); + void refresh_emotes(); + void set_emote_page(); + void set_emote_dropdown(); + + void initialize_evidence(); + void refresh_evidence(); + void show_evidence(int f_real_id); + void set_evidence_page(); + + void reset_ui(); + + void regenerate_ic_chatlog(); +public Q_SLOTS: + void objection_done(); + void preanim_done(); + void do_screenshake(); + void do_flash(); + void do_effect(QString fx_path, QString fx_sound, QString p_char, QString p_folder); + void play_char_sfx(QString sfx_name); + + void mod_called(QString p_ip); + + void on_reload_theme_clicked(); + + void update_ui_music_name(); + +private Q_SLOTS: + void start_chat_ticking(); + void play_sfx(); + + void chat_tick(); + + void on_mute_list_clicked(QModelIndex p_index); + void on_pair_list_clicked(QModelIndex p_index); + + void on_chat_return_pressed(); + + void on_ooc_return_pressed(); + + void on_music_search_return_pressed(); + void on_music_search_edited(QString p_text); + void on_music_list_double_clicked(QTreeWidgetItem *p_item, int column); + void on_music_list_context_menu_requested(const QPoint &pos); + void music_fade_out(bool toggle); + void music_fade_in(bool toggle); + void music_synchronize(bool toggle); + void music_random(); + void music_list_expand_all(); + void music_list_collapse_all(); + void music_stop(bool no_effects = false); + void on_area_list_double_clicked(QTreeWidgetItem *p_item, int column); + + void select_emote(int p_id); + + void on_emote_clicked(int p_id); + + void on_emote_left_clicked(); + void on_emote_right_clicked(); + + void on_emote_dropdown_changed(int p_index); + void on_pos_dropdown_changed(int p_index); + void on_pos_dropdown_changed(QString p_text); + void on_pos_dropdown_context_menu_requested(const QPoint &pos); + void on_pos_remove_clicked(); + + void on_iniswap_dropdown_changed(int p_index); + void set_iniswap_dropdown(); + void on_iniswap_context_menu_requested(const QPoint &pos); + void on_iniswap_edit_requested(); + void on_iniswap_remove_clicked(); + + void on_sfx_dropdown_changed(int p_index); + void on_sfx_dropdown_custom(QString p_sfx); + void set_sfx_dropdown(); + void on_sfx_context_menu_requested(const QPoint &pos); + void on_sfx_play_clicked(); + void on_sfx_edit_requested(); + void on_sfx_remove_clicked(); + + void set_effects_dropdown(); + void on_effects_context_menu_requested(const QPoint &pos); + void on_effects_edit_requested(); + void on_character_effects_edit_requested(); + void on_effects_dropdown_changed(int p_index); + bool effects_dropdown_find_and_set(QString effect); + + QString get_char_sfx(); + int get_char_sfx_delay(); + + void on_evidence_name_edited(); + void on_evidence_image_name_edited(); + void on_evidence_image_button_clicked(); + void on_evidence_clicked(int p_id); + void on_evidence_double_clicked(int p_id); + + void on_evidence_hover(int p_id, bool p_state); + + void on_evidence_left_clicked(); + void on_evidence_right_clicked(); + void on_evidence_present_clicked(); + + void on_hold_it_clicked(); + void on_objection_clicked(); + void on_take_that_clicked(); + void on_custom_objection_clicked(); + void show_custom_objection_menu(const QPoint &pos); + + void show_emote_menu(const QPoint &pos); + + void on_realization_clicked(); + void on_screenshake_clicked(); + + void on_mute_clicked(); + void on_pair_clicked(); + void on_pair_order_dropdown_changed(int p_index); + + void on_defense_minus_clicked(); + void on_defense_plus_clicked(); + void on_prosecution_minus_clicked(); + void on_prosecution_plus_clicked(); + + void on_text_color_changed(int p_color); + void on_text_color_context_menu_requested(const QPoint &pos); + void set_text_color_dropdown(); + + void on_music_slider_moved(int p_value); + void on_sfx_slider_moved(int p_value); + void on_blip_slider_moved(int p_value); + + void on_log_limit_changed(int value); + void on_pair_offset_changed(int value); + void on_pair_vert_offset_changed(int value); + + void on_ooc_toggle_clicked(); + + void on_witness_testimony_clicked(); + void on_cross_examination_clicked(); + void on_not_guilty_clicked(); + void on_guilty_clicked(); + + void on_change_character_clicked(); + void on_call_mod_clicked(); + void on_settings_clicked(); + + void on_pre_clicked(); + void on_flip_clicked(); + void on_additive_clicked(); + void on_guard_clicked(); + + void on_showname_enable_clicked(); + + void on_evidence_button_clicked(); + void on_evidence_context_menu_requested(const QPoint &pos); + + void on_evidence_delete_clicked(); + bool on_evidence_x_clicked(); + void on_evidence_ok_clicked(); + void on_evidence_switch_clicked(); + void on_evidence_transfer_clicked(); + + void on_evidence_edited(); + + void evidence_close(); + void evidence_switch(bool global); + void on_evidence_save_clicked(); + void on_evidence_load_clicked(); + void evidence_save(QString filename); + void evidence_load(QString filename); + bool compare_evidence_changed(evi_type evi_a, evi_type evi_b); + + void on_back_to_lobby_clicked(); + + void on_char_list_double_clicked(QTreeWidgetItem *p_item, int column); + void on_char_select_left_clicked(); + void on_char_select_right_clicked(); + void on_char_search_changed(); + void on_char_taken_clicked(); + void on_char_passworded_clicked(); + + void on_spectator_clicked(); + + void on_switch_area_music_clicked(); + + void on_application_state_changed(Qt::ApplicationState state); + + void ping_server(); + + // Proceed to parse the oldest chatmessage and remove it from the stack + void chatmessage_dequeue(); + + void preview_emote(QString emote); + void update_emote_preview(); +}; diff --git a/src/datatypes.h b/src/datatypes.h new file mode 100644 index 00000000..9b2cbcc3 --- /dev/null +++ b/src/datatypes.h @@ -0,0 +1,147 @@ +#pragma once + +#include <QMap> +#include <QString> + +enum connection_type +{ + TCP, + WEBSOCKETS, +}; + +static QMap<QString, connection_type> to_connection_type = {{"tcp", connection_type::TCP}, {"ws", connection_type::WEBSOCKETS}}; + +struct server_type +{ + QString name; + QString desc; + QString ip; + int port; + connection_type socket_type; +}; + +struct emote_type +{ + QString comment; + QString preanim; + QString anim; + int mod; + QString sfx_name; + int sfx_delay; + int sfx_duration; +}; + +struct char_type +{ + QString name; + QString description; + QString evidence_string; + bool taken; +}; + +struct evi_type +{ + QString name; + QString description; + QString image; +}; + +struct chatmessage_type +{ + QString message; + QString character; + QString side; + QString sfx_name; + QString pre_emote; + QString emote; + int emote_modifier; + int objection_modifier; + int realization; + int text_color; + int evidence; + int cid; + int sfx_delay; + int flip; +}; + +struct area_type +{ + QString name; + QString background; + bool passworded; +}; + +struct pos_type +{ + int x; + int y; +}; + +struct pos_size_type +{ + int x = 0; + int y = 0; + int width = 0; + int height = 0; +}; + +enum CHAT_MESSAGE +{ + DESK_MOD = 0, + PRE_EMOTE, + CHAR_NAME, + EMOTE, + MESSAGE, + SIDE, + SFX_NAME, + EMOTE_MOD, + CHAR_ID, + SFX_DELAY, + OBJECTION_MOD, + EVIDENCE_ID, + FLIP, + REALIZATION, + TEXT_COLOR, + SHOWNAME, + OTHER_CHARID, + OTHER_NAME, + OTHER_EMOTE, + SELF_OFFSET, + OTHER_OFFSET, + OTHER_FLIP, + IMMEDIATE, + LOOPING_SFX, + SCREENSHAKE, + FRAME_SCREENSHAKE, + FRAME_REALIZATION, + FRAME_SFX, + ADDITIVE, + EFFECTS, +}; + +enum EMOTE_MOD_TYPE +{ + IDLE = 0, + PREANIM = 1, + ZOOM = 5, + PREANIM_ZOOM = 6, +}; + +enum DESK_MOD_TYPE +{ + DESK_HIDE = 0, + DESK_SHOW, + DESK_EMOTE_ONLY, + DESK_PRE_ONLY, + DESK_EMOTE_ONLY_EX, + DESK_PRE_ONLY_EX, + //"EX" for "expanded" + // dumb, i know, but throw the first stone if you have a better idea +}; + +enum MUSIC_EFFECT +{ + FADE_IN = 1, + FADE_OUT = 2, + SYNC_POS = 4 +}; diff --git a/src/debug_functions.cpp b/src/debug_functions.cpp index f4f7b3a7..79be51b3 100644 --- a/src/debug_functions.cpp +++ b/src/debug_functions.cpp @@ -1,3 +1,5 @@ +#include "debug_functions.h" + #include <QCoreApplication> #include <QDialogButtonBox> #include <QElapsedTimer> @@ -7,17 +9,13 @@ #include <functional> -#include "debug_functions.h" - void call_error(QString p_message) { QMessageBox *msgBox = new QMessageBox; msgBox->setAttribute(Qt::WA_DeleteOnClose); - msgBox->setText(QCoreApplication::translate("debug_functions", "Error: %1") - .arg(p_message)); - msgBox->setWindowTitle( - QCoreApplication::translate("debug_functions", "Error")); + msgBox->setText(QCoreApplication::translate("debug_functions", "Error: %1").arg(p_message)); + msgBox->setWindowTitle(QCoreApplication::translate("debug_functions", "Error")); // msgBox->setWindowModality(Qt::NonModal); msgBox->exec(); @@ -29,8 +27,7 @@ void call_notice(QString p_message) msgBox->setAttribute(Qt::WA_DeleteOnClose); msgBox->setText(p_message); - msgBox->setWindowTitle( - QCoreApplication::translate("debug_functions", "Notice")); + msgBox->setWindowTitle(QCoreApplication::translate("debug_functions", "Notice")); msgBox->setStandardButtons(QMessageBox::Ok); msgBox->setDefaultButton(QMessageBox::Ok); @@ -42,9 +39,10 @@ void call_notice(QString p_message) int counter = 3; const auto updateCounter = [msgBox, &counter] { if (counter <= 0) + { return; - msgBox->defaultButton()->setText( - QString("%1 (%2)").arg(QDialogButtonBox::tr("OK")).arg(counter)); + } + msgBox->defaultButton()->setText(QString("%1 (%2)").arg(QDialogButtonBox::tr("OK")).arg(counter)); counter--; }; @@ -58,6 +56,5 @@ void call_notice(QString p_message) intervalTimer.stop(); }); - msgBox->exec(); - + msgBox->exec(); } diff --git a/src/debug_functions.h b/src/debug_functions.h new file mode 100644 index 00000000..992ad37b --- /dev/null +++ b/src/debug_functions.h @@ -0,0 +1,6 @@ +#pragma once + +#include <QString> + +void call_error(QString message); +void call_notice(QString message); diff --git a/src/demoserver.cpp b/src/demoserver.cpp index 16d2b46e..c22160da 100644 --- a/src/demoserver.cpp +++ b/src/demoserver.cpp @@ -1,452 +1,501 @@ #include "demoserver.h" -#include "lobby.h" -DemoServer::DemoServer(QObject *parent) : QObject(parent) +DemoServer::DemoServer(QObject *parent) + : QObject(parent) { - timer = new QTimer(this); - timer->setTimerType(Qt::PreciseTimer); - timer->setSingleShot(true); + timer = new QTimer(this); + timer->setTimerType(Qt::PreciseTimer); + timer->setSingleShot(true); - tcp_server = new QTcpServer(this); - connect(tcp_server, &QTcpServer::newConnection, this, &DemoServer::accept_connection); - connect(timer, &QTimer::timeout, this, &DemoServer::playback); + tcp_server = new QTcpServer(this); + connect(tcp_server, &QTcpServer::newConnection, this, &DemoServer::accept_connection); + connect(timer, &QTimer::timeout, this, &DemoServer::playback); +} + +int DemoServer::port() +{ + return m_port; } void DemoServer::set_demo_file(QString filepath) { - filename = filepath; + filename = filepath; } void DemoServer::start_server() { - if (server_started) return; - if (!tcp_server->listen(QHostAddress::LocalHost, 0)) { - qCritical() << "Could not start demo playback server..."; - qDebug() << tcp_server->errorString(); - return; - } - this->port = tcp_server->serverPort(); - qInfo() << "Demo server started at port" << port; - server_started = true; + if (m_server_started) + { + return; + } + if (!tcp_server->listen(QHostAddress::LocalHost, 0)) + { + qCritical() << "Could not start demo playback server..."; + qDebug() << tcp_server->errorString(); + return; + } + this->m_port = tcp_server->serverPort(); + qInfo() << "Demo server started at port" << m_port; + m_server_started = true; } void DemoServer::destroy_connection() { - QTcpSocket* temp_socket = tcp_server->nextPendingConnection(); - connect(temp_socket, &QAbstractSocket::disconnected, temp_socket, &QObject::deleteLater); - temp_socket->disconnectFromHost(); - return; + QTcpSocket *temp_socket = tcp_server->nextPendingConnection(); + connect(temp_socket, &QAbstractSocket::disconnected, temp_socket, &QObject::deleteLater); + temp_socket->disconnectFromHost(); + return; } void DemoServer::accept_connection() { - if (filename.isEmpty()) - { - destroy_connection(); - return; - } - load_demo(filename); + if (filename.isEmpty()) + { + destroy_connection(); + return; + } + load_demo(filename); - if (demo_data.isEmpty()) - { - destroy_connection(); - return; - } + if (demo_data.isEmpty()) + { + destroy_connection(); + return; + } - if (demo_data.head().startsWith("SC#")) - { - sc_packet = demo_data.dequeue(); - AOPacket sc(sc_packet); - num_chars = sc.get_contents().length(); - } - else - { - sc_packet = "SC#%"; - num_chars = 0; - } + if (demo_data.head().startsWith("SC#")) + { + sc_packet = demo_data.dequeue(); + AOPacket sc(sc_packet); + num_chars = sc.get_content().length(); + } + else + { + sc_packet = "SC#%"; + num_chars = 0; + } - if (client_sock) { - // Client is already connected... - qWarning() << "Multiple connections to demo server disallowed."; - QTcpSocket* temp_socket = tcp_server->nextPendingConnection(); - connect(temp_socket, &QAbstractSocket::disconnected, temp_socket, &QObject::deleteLater); - temp_socket->disconnectFromHost(); - return; - } - client_sock = tcp_server->nextPendingConnection(); - connect(client_sock, &QAbstractSocket::disconnected, this, &DemoServer::client_disconnect); - connect(client_sock, &QAbstractSocket::readyRead, this, &DemoServer::recv_data); - client_sock->write("decryptor#NOENCRYPT#%"); + if (client_sock) + { + // Client is already connected... + qWarning() << "Multiple connections to demo server disallowed."; + QTcpSocket *temp_socket = tcp_server->nextPendingConnection(); + connect(temp_socket, &QAbstractSocket::disconnected, temp_socket, &QObject::deleteLater); + temp_socket->disconnectFromHost(); + return; + } + client_sock = tcp_server->nextPendingConnection(); + connect(client_sock, &QAbstractSocket::disconnected, this, &DemoServer::client_disconnect); + connect(client_sock, &QAbstractSocket::readyRead, this, &DemoServer::recv_data); + client_sock->write("decryptor#NOENCRYPT#%"); } void DemoServer::recv_data() { - QString in_data = QString::fromUtf8(client_sock->readAll()); + QString in_data = QString::fromUtf8(client_sock->readAll()); #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) - const QStringList packet_list = in_data.split("%", QString::SplitBehavior(QString::SkipEmptyParts)); + const QStringList packet_list = in_data.split("%", QString::SplitBehavior(QString::SkipEmptyParts)); #else - const QStringList packet_list = in_data.split("%", Qt::SkipEmptyParts); + const QStringList packet_list = in_data.split("%", Qt::SkipEmptyParts); #endif - for (const QString &packet : packet_list) { - QStringList f_contents; - // Packet should *always* end with # - if (packet.endsWith("#")) { - f_contents = packet.chopped(1).split("#"); - } - // But, if it somehow doesn't, we should still be able to handle it - else { - f_contents = packet.split("#"); - } - // Empty packets are suspicious! - if (f_contents.isEmpty()) { - qWarning() << "WARNING: Empty packet received from server, skipping..."; - continue; - } - // Take the first arg as the command - QString command = f_contents.takeFirst(); - // The rest is contents of the packet - AOPacket *f_packet = new AOPacket(command, f_contents); - // Ship it to the server! - handle_packet(f_packet); + for (const QString &packet : packet_list) + { + QStringList f_contents; + // Packet should *always* end with # + if (packet.endsWith("#")) + { + f_contents = packet.chopped(1).split("#"); + } + // But, if it somehow doesn't, we should still be able to handle it + else + { + f_contents = packet.split("#"); + } + // Empty packets are suspicious! + if (f_contents.isEmpty()) + { + qWarning() << "WARNING: Empty packet received from server, skipping..."; + continue; + } + // Take the first arg as the command + QString command = f_contents.takeFirst(); + for (QString &data : f_contents) + { + data = AOPacket::decode(data); } + + // The rest is contents of the packet + AOPacket f_packet(command, f_contents); + + // Ship it to the server! + handle_packet(f_packet); + } } -void DemoServer::handle_packet(AOPacket *p_packet) +void DemoServer::handle_packet(AOPacket p_packet) { - p_packet->net_decode(); - - // This code is literally a barebones AO server - // It is wise to do it this way, because I can - // avoid touching any of this disgusting shit - // related to hardcoding this stuff in. + // This code is literally a barebones AO server + // It is wise to do it this way, because I can + // avoid touching any of this disgusting shit + // related to hardcoding this stuff in. - // Also, at some point, I will make akashit - // into a shared library. + // Also, at some point, I will make akashit + // into a shared library. - QString header = p_packet->get_header(); - QStringList contents = p_packet->get_contents(); + QString header = p_packet.get_header(); + QStringList contents = p_packet.get_content(); - if (header == "HI") { - client_sock->write("ID#0#DEMOINTERNAL#0#%"); - } - else if (header == "ID") { - QStringList feature_list = { - "noencryption", "yellowtext", "prezoom", - "flipping", "customobjections", "fastloading", - "deskmod", "evidence", "cccc_ic_support", - "arup", "casing_alerts", "modcall_reason", - "looping_sfx", "additive", "effects", - "y_offset", "expanded_desk_mods"}; - client_sock->write("PN#0#1#%"); - client_sock->write("FL#"); - client_sock->write(feature_list.join('#').toUtf8()); - client_sock->write("#%"); - } - else if (header == "askchaa") { - client_sock->write("SI#"); - client_sock->write(QString::number(num_chars).toUtf8()); - client_sock->write("#0#1#%"); - } - else if (header == "RC") { - client_sock->write(sc_packet.toUtf8()); - } - else if (header == "RM") { - client_sock->write("SM#%"); - } - else if (header == "RD") { - client_sock->write("DONE#%"); + if (header == "HI") + { + client_sock->write("ID#0#DEMOINTERNAL#0#%"); + } + else if (header == "ID") + { + QStringList feature_list = {"noencryption", "yellowtext", "prezoom", "flipping", "customobjections", "fastloading", "deskmod", "evidence", "cccc_ic_support", "arup", "casing_alerts", "modcall_reason", "looping_sfx", "additive", "effects", "y_offset", "expanded_desk_mods"}; + client_sock->write("PN#0#1#%"); + client_sock->write("FL#"); + client_sock->write(feature_list.join('#').toUtf8()); + client_sock->write("#%"); + } + else if (header == "askchaa") + { + client_sock->write("SI#"); + client_sock->write(QString::number(num_chars).toUtf8()); + client_sock->write("#0#1#%"); + } + else if (header == "RC") + { + client_sock->write(sc_packet.toUtf8()); + } + else if (header == "RM") + { + client_sock->write("SM#%"); + } + else if (header == "RD") + { + client_sock->write("DONE#%"); + } + else if (header == "CC") + { + client_sock->write("PV#0#CID#-1#%"); + QString packet = "CT#DEMO#" + tr("Demo file loaded. Send /play or > in OOC to begin playback.") + "#1#%"; + client_sock->write(packet.toUtf8()); + } + else if (header == "CT") + { + if (contents[1].startsWith("/load")) + { + QString path = QFileDialog::getOpenFileName(nullptr, tr("Load Demo"), "logs/", tr("Demo Files (*.demo)")); + if (path.isEmpty()) + { + return; + } + load_demo(path); + QString packet = "CT#DEMO#" + tr("Demo file loaded. Send /play or > in OOC to begin playback.") + "#1#%"; + client_sock->write(packet.toUtf8()); + reset_state(); } - else if (header == "CC") { - client_sock->write("PV#0#CID#-1#%"); - QString packet = "CT#DEMO#" + tr("Demo file loaded. Send /play or > in OOC to begin playback.") + "#1#%"; + else if (contents[1].startsWith("/play") || contents[1] == ">") + { + if (timer->interval() != 0 && !timer->isActive()) + { + timer->start(); + QString packet = "CT#DEMO#" + tr("Resuming playback.") + "#1#%"; client_sock->write(packet.toUtf8()); - } - else if (header == "CT") { - if (contents[1].startsWith("/load")) + } + else + { + if (demo_data.isEmpty() && p_path != "") { - QString path = QFileDialog::getOpenFileName(nullptr, tr("Load Demo"), "logs/", tr("Demo Files (*.demo)")); - if (path.isEmpty()) - return; - load_demo(path); - QString packet = "CT#DEMO#" + tr("Demo file loaded. Send /play or > in OOC to begin playback.") + "#1#%"; - client_sock->write(packet.toUtf8()); - reset_state(); + load_demo(p_path); } - else if (contents[1].startsWith("/play") || contents[1] == ">") + playback(); + } + } + else if (contents[1].startsWith("/pause") || contents[1] == "|") + { + int timeleft = timer->remainingTime(); + timer->stop(); + timer->setInterval(timeleft); + QString packet = "CT#DEMO#" + tr("Pausing playback.") + "#1#%"; + client_sock->write(packet.toUtf8()); + } + else if (contents[1].startsWith("/max_wait")) + { + QStringList args = contents[1].split(" "); + if (args.size() > 1) + { + bool ok; + int p_max_wait = args.at(1).toInt(&ok); + if (ok) { - if (timer->interval() != 0 && !timer->isActive()) - { - timer->start(); - QString packet = "CT#DEMO#" + tr("Resuming playback.") + "#1#%"; - client_sock->write(packet.toUtf8()); - } - else + if (p_max_wait < 0) { - if (demo_data.isEmpty() && p_path != "") - load_demo(p_path); - playback(); + p_max_wait = -1; } + m_max_wait = p_max_wait; + QString packet = "CT#DEMO#" + tr("Setting max_wait to") + " "; + client_sock->write(packet.toUtf8()); + client_sock->write(QString::number(m_max_wait).toUtf8()); + packet = " " + tr("milliseconds.") + "#1#%"; + client_sock->write(packet.toUtf8()); } - else if (contents[1].startsWith("/pause") || contents[1] == "|") + else { - int timeleft = timer->remainingTime(); - timer->stop(); - timer->setInterval(timeleft); - QString packet = "CT#DEMO#" + tr("Pausing playback.") + "#1#%"; + QString packet = "CT#DEMO#" + tr("Not a valid integer!") + "#1#%"; client_sock->write(packet.toUtf8()); } - else if (contents[1].startsWith("/max_wait")) + } + else + { + QString packet = "CT#DEMO#" + tr("Current max_wait is") + " "; + client_sock->write(packet.toUtf8()); + client_sock->write(QString::number(m_max_wait).toUtf8()); + packet = " " + tr("milliseconds.") + "#1#%"; + client_sock->write(packet.toUtf8()); + } + } + else if (contents[1].startsWith("/reload")) + { + load_demo(p_path); + QString packet = "CT#DEMO#" + tr("Current demo file reloaded. Send /play or > in OOC to begin playback.") + "#1#%"; + client_sock->write(packet.toUtf8()); + reset_state(); + } + else if (contents[1].startsWith("/min_wait")) + { + QString packet = "CT#DEMO#" + tr("min_wait is deprecated. Use the client Settings for minimum wait instead!") + "#1#%"; + client_sock->write(packet.toUtf8()); + } + else if (contents[1].startsWith("/debug")) + { + QStringList args = contents[1].split(" "); + if (args.size() > 1) + { + bool ok; + int toggle = args.at(1).toInt(&ok); + if (ok && (toggle == 0 || toggle == 1)) { - QStringList args = contents[1].split(" "); - if (args.size() > 1) - { - bool ok; - int p_max_wait = args.at(1).toInt(&ok); - if (ok) - { - if (p_max_wait < 0) - p_max_wait = -1; - max_wait = p_max_wait; - QString packet = "CT#DEMO#" + tr("Setting max_wait to") + " "; - client_sock->write(packet.toUtf8()); - client_sock->write(QString::number(max_wait).toUtf8()); - packet = " " + tr("milliseconds.") + "#1#%"; - client_sock->write(packet.toUtf8()); - } - else - { - QString packet = "CT#DEMO#" + tr("Not a valid integer!") + "#1#%"; - client_sock->write(packet.toUtf8()); - } - } - else + debug_mode = toggle == 1; + QString packet = "CT#DEMO#" + tr("Setting debug mode to %1").arg(static_cast<int>(debug_mode)) + "#1#%"; + client_sock->write(packet.toUtf8()); + // Debug mode disabled? + if (!debug_mode) { - - QString packet = "CT#DEMO#" + tr("Current max_wait is") + " "; - client_sock->write(packet.toUtf8()); - client_sock->write(QString::number(max_wait).toUtf8()); - packet = " " + tr("milliseconds.") + "#1#%"; - client_sock->write(packet.toUtf8()); + // Reset the timer + client_sock->write("TI#4#1#0#%"); + client_sock->write("TI#4#3#0#%"); } } - else if (contents[1].startsWith("/reload")) + else { - load_demo(p_path); - QString packet = "CT#DEMO#" + tr("Current demo file reloaded. Send /play or > in OOC to begin playback.") + "#1#%"; - client_sock->write(packet.toUtf8()); - reset_state(); - } - else if (contents[1].startsWith("/min_wait")) - { - QString packet = "CT#DEMO#" + tr("min_wait is deprecated. Use the client Settings for minimum wait instead!") + "#1#%"; - client_sock->write(packet.toUtf8()); - } - else if (contents[1].startsWith("/debug")) - { - QStringList args = contents[1].split(" "); - if (args.size() > 1) - { - bool ok; - int toggle = args.at(1).toInt(&ok); - if (ok && (toggle == 0 || toggle == 1)) { - debug_mode = toggle == 1; - QString packet = "CT#DEMO#" + tr("Setting debug mode to %1").arg(static_cast<int>(debug_mode)) + "#1#%"; - client_sock->write(packet.toUtf8()); - // Debug mode disabled? - if (!debug_mode) { - // Reset the timer - client_sock->write("TI#4#1#0#%"); - client_sock->write("TI#4#3#0#%"); - } - } - else - { - QString packet = "CT#DEMO#" + tr("Valid values are 1 or 0!") + "#1#%"; - client_sock->write(packet.toUtf8()); - } - } - else - { - QString packet = "CT#DEMO#" + tr("Set debug mode using /debug 1 to enable, and /debug 0 to disable, which will use the fifth timer (TI#4) to show the remaining time until next demo line.") + "#1#%"; - client_sock->write(packet.toUtf8()); - } - } - else if (contents[1].startsWith("/help")) - { - QString packet = "CT#DEMO#" + tr("Available commands:\nload, reload, play, pause, max_wait, debug, help") + "#1#%"; - client_sock->write(packet.toUtf8()); + QString packet = "CT#DEMO#" + tr("Valid values are 1 or 0!") + "#1#%"; + client_sock->write(packet.toUtf8()); } + } + else + { + QString packet = "CT#DEMO#" + tr("Set debug mode using /debug 1 to enable, and /debug 0 to disable, which will use the fifth timer (TI#4) to show the remaining time until next demo line.") + "#1#%"; + client_sock->write(packet.toUtf8()); + } } - - delete p_packet; + else if (contents[1].startsWith("/help")) + { + QString packet = "CT#DEMO#" + tr("Available commands:\nload, reload, play, pause, max_wait, debug, help") + "#1#%"; + client_sock->write(packet.toUtf8()); + } + } } void DemoServer::load_demo(QString filename) { - QFile demo_file(filename); - demo_file.open(QIODevice::ReadOnly); - if (!demo_file.isOpen()) - return; - // Clear demo data - demo_data.clear(); - // Set the demo filepath - p_path = filename; - // Process the demo file - QTextStream demo_stream(&demo_file); + QFile demo_file(filename); + demo_file.open(QIODevice::ReadOnly); + if (!demo_file.isOpen()) + { + return; + } + // Clear demo data + demo_data.clear(); + // Set the demo filepath + p_path = filename; + // Process the demo file + QTextStream demo_stream(&demo_file); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - demo_stream.setCodec("UTF-8"); + demo_stream.setCodec("UTF-8"); #endif - QString line = demo_stream.readLine(); - while (!line.isNull()) { - while (!line.endsWith("%")) { - line += "\n"; - line += demo_stream.readLine(); - } - demo_data.enqueue(line); - line = demo_stream.readLine(); + QString line = demo_stream.readLine(); + while (!line.isNull()) + { + while (!line.endsWith("%")) + { + line += "\n"; + line += demo_stream.readLine(); } - demo_file.flush(); - demo_file.close(); + demo_data.enqueue(line); + line = demo_stream.readLine(); + } + demo_file.flush(); + demo_file.close(); - // No-shenanigans 2.9.0 demo file with the dreaded demo desync bug detected https://github.com/AttorneyOnline/AO2-Client/pull/496 - // If we don't start with the SC packet this means user-edited weirdo shenanigans. Don't screw around with those. - if (demo_data.head().startsWith("SC#") && demo_data.last().startsWith("wait#")) { - qInfo() << "Loaded a broken pre-2.9.1 demo file, with the wait desync issue!"; - QMessageBox *msgBox = new QMessageBox; - msgBox->setAttribute(Qt::WA_DeleteOnClose); - msgBox->setTextFormat(Qt::RichText); - msgBox->setText("This appears to be a <b>broken</b> pre-2.9.1 demo file with the <a href=https://github.com/AttorneyOnline/AO2-Client/pull/496>wait desync issue</a>!<br>Do you want to correct this file? <i>If you refuse, this demo will be desynchronized!</i>"); - msgBox->setWindowTitle("Pre-2.9.1 demo detected!"); - msgBox->setStandardButtons(QMessageBox::NoButton); - QTimer::singleShot(2000, msgBox, std::bind(&QMessageBox::setStandardButtons,msgBox,QMessageBox::Yes|QMessageBox::No)); - int ret = msgBox->exec(); - QQueue <QString> p_demo_data; - switch (ret) { - case QMessageBox::Yes: - qInfo() << "Making a backup of the broken demo..."; - QFile::copy(filename, filename + ".backup"); - while (!demo_data.isEmpty()) { - QString current_packet = demo_data.dequeue(); - // TODO: faster way of doing this, maybe with QtConcurrent's MapReduce methods? - if (!current_packet.startsWith("SC#") && current_packet.startsWith("wait#")) { - p_demo_data.insert(qMax(1, p_demo_data.size()-1), current_packet); - continue; - } - p_demo_data.enqueue(current_packet); - } - if (demo_file.open(QIODevice::WriteOnly | QIODevice::Text | - QIODevice::Truncate)) { - QTextStream out(&demo_file); + // No-shenanigans 2.9.0 demo file with the dreaded demo desync bug detected https://github.com/AttorneyOnline/AO2-Client/pull/496 + // If we don't start with the SC packet this means user-edited weirdo shenanigans. Don't screw around with those. + if (demo_data.head().startsWith("SC#") && demo_data.last().startsWith("wait#")) + { + qInfo() << "Loaded a broken pre-2.9.1 demo file, with the wait desync issue!"; + QMessageBox *msgBox = new QMessageBox; + msgBox->setAttribute(Qt::WA_DeleteOnClose); + msgBox->setTextFormat(Qt::RichText); + msgBox->setText("This appears to be a <b>broken</b> pre-2.9.1 demo file with the <a href=https://github.com/AttorneyOnline/AO2-Client/pull/496>wait desync issue</a>!<br>Do you want to correct this file? <i>If you refuse, this demo will be desynchronized!</i>"); + msgBox->setWindowTitle("Pre-2.9.1 demo detected!"); + msgBox->setStandardButtons(QMessageBox::NoButton); + QTimer::singleShot(2000, msgBox, std::bind(&QMessageBox::setStandardButtons, msgBox, QMessageBox::Yes | QMessageBox::No)); + int ret = msgBox->exec(); + QQueue<QString> p_demo_data; + switch (ret) + { + case QMessageBox::Yes: + qInfo() << "Making a backup of the broken demo..."; + QFile::copy(filename, filename + ".backup"); + while (!demo_data.isEmpty()) + { + QString current_packet = demo_data.dequeue(); + // TODO: faster way of doing this, maybe with QtConcurrent's MapReduce methods? + if (!current_packet.startsWith("SC#") && current_packet.startsWith("wait#")) + { + p_demo_data.insert(qMax(1, p_demo_data.size() - 1), current_packet); + continue; + } + p_demo_data.enqueue(current_packet); + } + if (demo_file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) + { + QTextStream out(&demo_file); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - out.setCodec("UTF-8"); + out.setCodec("UTF-8"); #endif - out << p_demo_data.dequeue(); - for (const QString &line : qAsConst(p_demo_data)) { - out << "\n" << line; - } - demo_file.flush(); - demo_file.close(); - } - load_demo(filename); - break; - case QMessageBox::No: - // No was clicked - break; - default: - // should never be reached - break; + out << p_demo_data.dequeue(); + for (const QString &line : qAsConst(p_demo_data)) + { + out << "\n" << line; + } + demo_file.flush(); + demo_file.close(); } + load_demo(filename); + break; + case QMessageBox::No: + // No was clicked + break; + default: + // should never be reached + break; } + } } void DemoServer::reset_state() { - // Reset evidence list - client_sock->write("LE##%"); + // Reset evidence list + client_sock->write("LE##%"); - // Reset timers - client_sock->write("TI#0#1#0#%"); - client_sock->write("TI#0#3#0#%"); - client_sock->write("TI#1#1#0#%"); - client_sock->write("TI#1#3#0#%"); - client_sock->write("TI#2#1#0#%"); - client_sock->write("TI#2#3#0#%"); - client_sock->write("TI#3#1#0#%"); - client_sock->write("TI#3#3#0#%"); - client_sock->write("TI#4#1#0#%"); - client_sock->write("TI#4#3#0#%"); + // Reset timers + client_sock->write("TI#0#1#0#%"); + client_sock->write("TI#0#3#0#%"); + client_sock->write("TI#1#1#0#%"); + client_sock->write("TI#1#3#0#%"); + client_sock->write("TI#2#1#0#%"); + client_sock->write("TI#2#3#0#%"); + client_sock->write("TI#3#1#0#%"); + client_sock->write("TI#3#3#0#%"); + client_sock->write("TI#4#1#0#%"); + client_sock->write("TI#4#3#0#%"); - // Set the BG to default (also breaks up the message queue) - client_sock->write("BN#default#wit#%"); + // Set the BG to default (also breaks up the message queue) + client_sock->write("BN#default#wit#%"); - // Stop the wait packet timer - timer->stop(); + // Stop the wait packet timer + timer->stop(); } void DemoServer::playback() { - if (demo_data.isEmpty()) - return; + if (demo_data.isEmpty()) + { + return; + } - QString current_packet = demo_data.dequeue(); - // We reset the elapsed time with this packet - if (current_packet.startsWith("MS#")) - elapsed_time = 0; + QString current_packet = demo_data.dequeue(); + // We reset the elapsed time with this packet + if (current_packet.startsWith("MS#")) + { + elapsed_time = 0; + } - while (!current_packet.startsWith("wait#")) { - client_sock->write(current_packet.toUtf8()); - if (demo_data.isEmpty()) - break; - current_packet = demo_data.dequeue(); + while (!current_packet.startsWith("wait#")) + { + client_sock->write(current_packet.toUtf8()); + if (demo_data.isEmpty()) + { + break; } - if (!demo_data.isEmpty()) { - QStringList f_contents; - // Packet should *always* end with # - if (current_packet.endsWith("#")) { - f_contents = current_packet.chopped(1).split("#"); - } - // But, if it somehow doesn't, we should still be able to handle it - else { - f_contents = current_packet.split("#"); - } - // Take the first arg as the command - QString command = f_contents.takeFirst(); - int duration = 0; - if (!f_contents.isEmpty()) { - duration = f_contents.at(0).toInt(); - } - // Max wait reached - if (max_wait != -1 && duration + elapsed_time > max_wait) { - int prev_duration = duration; - duration = qMax(0, max_wait - elapsed_time); - qDebug() << "Max_wait of " << max_wait << " reached. Forcing duration to " << duration << "ms"; - // Skip the difference on the timers - emit skip_timers(prev_duration - duration); - } - // Manual user skip, such as with > - else if (timer->remainingTime() > 0) { - qDebug() << "Timer of interval " << timer->interval() << " is being skipped. Forcing to skip " << timer->remainingTime() << "ms on TI# clocks"; - emit skip_timers(timer->remainingTime()); - } - elapsed_time += duration; - timer->start(duration); - if (debug_mode) { - client_sock->write("TI#4#2#%"); - QString debug_timer = "TI#4#0#" + QString::number(duration) + "#%"; - client_sock->write(debug_timer.toUtf8()); - } + current_packet = demo_data.dequeue(); + } + if (!demo_data.isEmpty()) + { + QStringList f_contents; + // Packet should *always* end with # + if (current_packet.endsWith("#")) + { + f_contents = current_packet.chopped(1).split("#"); + } + // But, if it somehow doesn't, we should still be able to handle it + else + { + f_contents = current_packet.split("#"); } - else { - QString end_packet = "CT#DEMO#" + tr("Reached the end of the demo file. Send /play or > in OOC to restart, or /load to open a new file.") + "#1#%"; - client_sock->write(end_packet.toUtf8()); - timer->setInterval(0); + // Take the first arg as the command + QString command = f_contents.takeFirst(); + int duration = 0; + if (!f_contents.isEmpty()) + { + duration = f_contents.at(0).toInt(); + } + // Max wait reached + if (m_max_wait != -1 && duration + elapsed_time > m_max_wait) + { + int prev_duration = duration; + duration = qMax(0, m_max_wait - elapsed_time); + qDebug() << "Max_wait of " << m_max_wait << " reached. Forcing duration to " << duration << "ms"; + // Skip the difference on the timers + Q_EMIT skip_timers(prev_duration - duration); + } + // Manual user skip, such as with > + else if (timer->remainingTime() > 0) + { + qDebug() << "Timer of interval " << timer->interval() << " is being skipped. Forcing to skip " << timer->remainingTime() << "ms on TI# clocks"; + Q_EMIT skip_timers(timer->remainingTime()); + } + elapsed_time += duration; + timer->start(duration); + if (debug_mode) + { + client_sock->write("TI#4#2#%"); + QString debug_timer = "TI#4#0#" + QString::number(duration) + "#%"; + client_sock->write(debug_timer.toUtf8()); } + } + else + { + QString end_packet = "CT#DEMO#" + tr("Reached the end of the demo file. Send /play or > in OOC to restart, or /load to open a new file.") + "#1#%"; + client_sock->write(end_packet.toUtf8()); + timer->setInterval(0); + } } void DemoServer::client_disconnect() { - client_sock->deleteLater(); - client_sock = nullptr; + client_sock->deleteLater(); + client_sock = nullptr; } diff --git a/src/demoserver.h b/src/demoserver.h new file mode 100644 index 00000000..f52fbc7e --- /dev/null +++ b/src/demoserver.h @@ -0,0 +1,60 @@ +#pragma once + +#include "aopacket.h" + +#include <QDebug> +#include <QFileDialog> +#include <QMessageBox> +#include <QObject> +#include <QQueue> +#include <QTcpServer> +#include <QTcpSocket> +#include <QTimer> + +class DemoServer : public QObject +{ + Q_OBJECT + +public: + explicit DemoServer(QObject *parent = nullptr); + + int port(); + + void set_demo_file(QString filepath); + +private: + bool m_server_started = false; + int m_port = 0; + int m_max_wait = -1; + + QTcpServer *tcp_server; + QTcpSocket *client_sock = nullptr; + bool client_connected = false; + bool partial_packet = false; + bool debug_mode = false; + QString temp_packet; + QQueue<QString> demo_data; + QString sc_packet; + int num_chars = 0; + QString p_path; + QTimer *timer; + int elapsed_time = 0; + QString filename; + + void handle_packet(AOPacket packet); + void load_demo(QString filename); + void reset_state(); + +private Q_SLOTS: + void accept_connection(); + void destroy_connection(); + void recv_data(); + void client_disconnect(); + void playback(); + +public Q_SLOTS: + void start_server(); + +Q_SIGNALS: + void skip_timers(qint64 msecs); +}; diff --git a/src/discord_rich_presence.cpp b/src/discord_rich_presence.cpp index 81e5a86c..6969334f 100644 --- a/src/discord_rich_presence.cpp +++ b/src/discord_rich_presence.cpp @@ -1,14 +1,17 @@ #include "discord_rich_presence.h" -namespace AttorneyOnline { +namespace AttorneyOnline +{ -#if defined(DISCORD) && !defined(ANDROID) +#if defined(AO_ENABLE_DISCORD_RPC) && !defined(ANDROID) Discord::Discord() { DiscordEventHandlers handlers; std::memset(&handlers, 0, sizeof(handlers)); handlers = {}; - handlers.ready = [] { qInfo() << "Discord RPC ready"; }; + handlers.ready = [](const DiscordUser *user) { + qInfo() << "Discord RPC ready"; + }; handlers.disconnected = [](int errorCode, const char *message) { qInfo() << "Discord RPC disconnected! " << message << errorCode; }; @@ -19,7 +22,10 @@ Discord::Discord() Discord_Initialize(APPLICATION_ID, &handlers, 1, nullptr); } -Discord::~Discord() { Discord_Shutdown(); } +Discord::~Discord() +{ + Discord_Shutdown(); +} void Discord::state_lobby() { @@ -59,12 +65,10 @@ void Discord::state_server(std::string name, std::string server_id) void Discord::state_character(std::string name) { - auto name_internal = - QString(name.c_str()).toLower().replace(' ', '_').toStdString(); + auto name_internal = QString(name.c_str()).toLower().replace(' ', '_').toStdString(); auto name_friendly = QString(name.c_str()).replace('_', ' ').toStdString(); const std::string playing_as = "Playing as " + name_friendly; - qDebug().nospace() << "Discord RPC: Setting character state (\"" << playing_as.c_str() - << "\")"; + qDebug().nospace() << "Discord RPC: Setting character state (\"" << playing_as.c_str() << "\")"; DiscordRichPresence presence; std::memset(&presence, 0, sizeof(presence)); @@ -98,11 +102,14 @@ void Discord::state_spectate() Discord_UpdatePresence(&presence); } #else -Discord::Discord() {} +Discord::Discord() +{} -Discord::~Discord() {} +Discord::~Discord() +{} -void Discord::state_lobby() {} +void Discord::state_lobby() +{} void Discord::state_server(std::string name, std::string server_id) { diff --git a/src/discord_rich_presence.h b/src/discord_rich_presence.h new file mode 100644 index 00000000..4d390c06 --- /dev/null +++ b/src/discord_rich_presence.h @@ -0,0 +1,34 @@ +#pragma once + +#include <QCoreApplication> +#include <QDebug> + +#include <discord_rpc.h> + +#include <cstring> +#include <ctime> +#include <string> + +namespace AttorneyOnline +{ + +class Discord +{ + Q_DECLARE_TR_FUNCTIONS(Discord) + +private: + const char *APPLICATION_ID = "399779271737868288"; + std::string server_name, server_id; + int64_t timestamp; + +public: + Discord(); + ~Discord(); + + void state_lobby(); + void state_server(std::string name, std::string server_id); + void state_character(std::string name); + void state_spectate(); +}; + +} // namespace AttorneyOnline diff --git a/src/emotes.cpp b/src/emotes.cpp index 899ae4e9..b16b9893 100644 --- a/src/emotes.cpp +++ b/src/emotes.cpp @@ -8,9 +8,9 @@ void Courtroom::initialize_emotes() ui_emotes = new QWidget(this); ui_emotes->setObjectName("ui_emotes"); - ui_emote_left = new AOButton(this, ao_app); + ui_emote_left = new AOButton(ao_app, this); ui_emote_left->setObjectName("ui_emote_left"); - ui_emote_right = new AOButton(this, ao_app); + ui_emote_right = new AOButton(ao_app, this); ui_emote_right->setObjectName("ui_emote_right"); ui_emote_dropdown = new QComboBox(this); @@ -20,26 +20,19 @@ void Courtroom::initialize_emotes() emote_menu = new QMenu(this); emote_menu->setObjectName("ui_emote_menu"); - emote_preview = new AOEmotePreview(this, ao_app); + emote_preview = new AOEmotePreview(ao_app, this); emote_preview->setObjectName("ui_emote_preview"); - 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_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, QOverload<int>::of(&QComboBox::activated), this, - &Courtroom::on_emote_dropdown_changed); - connect(ui_emote_dropdown, - &AOEmoteButton::customContextMenuRequested, this, - &Courtroom::show_emote_menu); + connect(ui_emote_dropdown, QOverload<int>::of(&QComboBox::activated), this, &Courtroom::on_emote_dropdown_changed); + connect(ui_emote_dropdown, &AOEmoteButton::customContextMenuRequested, this, &Courtroom::show_emote_menu); connect(ui_pre, QOverload<int>::of(&QCheckBox::stateChanged), this, &Courtroom::update_emote_preview); connect(ui_flip, &AOButton::clicked, this, &Courtroom::update_emote_preview); - connect(ui_pair_offset_spinbox, QOverload<int>::of(&QSpinBox::valueChanged), this, - &Courtroom::update_emote_preview); - connect(ui_pair_vert_offset_spinbox, QOverload<int>::of(&QSpinBox::valueChanged), this, - &Courtroom::update_emote_preview); + connect(ui_pair_offset_spinbox, QOverload<int>::of(&QSpinBox::valueChanged), this, &Courtroom::update_emote_preview); + connect(ui_pair_vert_offset_spinbox, QOverload<int>::of(&QSpinBox::valueChanged), this, &Courtroom::update_emote_preview); } void Courtroom::refresh_emotes() @@ -56,12 +49,11 @@ void Courtroom::refresh_emotes() set_size_and_pos(ui_emote_right, "emote_right"); ui_emote_right->set_image("arrow_right"); - QPoint f_spacing = ao_app->get_button_spacing("emote_button_spacing", - "courtroom_design.ini"); - QPoint p_point = - ao_app->get_button_spacing("emote_button_size", "courtroom_design.ini"); + QPoint f_spacing = ao_app->get_button_spacing("emote_button_spacing", "courtroom_design.ini"); + QPoint p_point = ao_app->get_button_spacing("emote_button_size", "courtroom_design.ini"); - if (ui_emotes->width() == 0 || ui_emotes->height() == 0) { // Workaround for a nasty crash + if (ui_emotes->width() == 0 || ui_emotes->height() == 0) + { // Workaround for a nasty crash ui_emotes->hide(); return; } @@ -74,37 +66,33 @@ void Courtroom::refresh_emotes() int y_spacing = f_spacing.y(); int y_mod_count = 0; - emote_columns = - ((ui_emotes->width() - button_width) / (x_spacing + button_width)) + 1; - emote_rows = - ((ui_emotes->height() - button_height) / (y_spacing + button_height)) + 1; + emote_columns = ((ui_emotes->width() - button_width) / (x_spacing + button_width)) + 1; + emote_rows = ((ui_emotes->height() - button_height) / (y_spacing + button_height)) + 1; max_emotes_on_page = emote_columns * emote_rows; QString selected_image = ao_app->get_image_suffix(ao_app->get_theme_path("emote_selected", ""), true); - for (int n = 0; n < max_emotes_on_page; ++n) { + for (int n = 0; n < max_emotes_on_page; ++n) + { int x_pos = (button_width + x_spacing) * x_mod_count; int y_pos = (button_height + y_spacing) * y_mod_count; - AOEmoteButton *f_emote = new AOEmoteButton(ui_emotes, ao_app, x_pos, y_pos, - button_width, button_height); + AOEmoteButton *f_emote = new AOEmoteButton(ao_app, x_pos, y_pos, button_width, button_height, ui_emotes); f_emote->set_selected_image(selected_image); ui_emote_list.append(f_emote); f_emote->set_id(n); f_emote->setContextMenuPolicy(Qt::CustomContextMenu); - connect(f_emote, &AOEmoteButton::emote_clicked, this, - &Courtroom::on_emote_clicked); + connect(f_emote, &AOEmoteButton::emote_clicked, this, &Courtroom::on_emote_clicked); - connect(f_emote, - &AOEmoteButton::customContextMenuRequested, this, - &Courtroom::show_emote_menu); + connect(f_emote, &AOEmoteButton::customContextMenuRequested, this, &Courtroom::show_emote_menu); ++x_mod_count; - if (x_mod_count == emote_columns) { + if (x_mod_count == emote_columns) + { ++y_mod_count; x_mod_count = 0; } @@ -114,50 +102,67 @@ void Courtroom::refresh_emotes() void Courtroom::set_emote_page() { if (m_cid == -1) + { return; + } int total_emotes = ao_app->get_emote_number(current_char); ui_emote_left->hide(); ui_emote_right->hide(); - for (AOEmoteButton *i_button : qAsConst(ui_emote_list)) { + for (AOEmoteButton *i_button : qAsConst(ui_emote_list)) + { i_button->hide(); } int total_pages = total_emotes / max_emotes_on_page; int emotes_on_page = 0; - if (total_emotes % max_emotes_on_page != 0) { + if (total_emotes % max_emotes_on_page != 0) + { ++total_pages; // i. e. not on the last page if (total_pages > current_emote_page + 1) + { emotes_on_page = max_emotes_on_page; + } else + { emotes_on_page = total_emotes % max_emotes_on_page; + } } else + { emotes_on_page = max_emotes_on_page; + } if (total_pages > current_emote_page + 1) + { ui_emote_right->show(); + } if (current_emote_page > 0) + { ui_emote_left->show(); + } - for (int n_emote = 0; - n_emote < emotes_on_page && n_emote < ui_emote_list.size(); ++n_emote) { + for (int n_emote = 0; n_emote < emotes_on_page && n_emote < ui_emote_list.size(); ++n_emote) + { int n_real_emote = n_emote + current_emote_page * max_emotes_on_page; AOEmoteButton *f_emote = ui_emote_list.at(n_emote); if (n_real_emote == current_emote) + { f_emote->set_char_image(current_char, n_real_emote, true); + } else + { f_emote->set_char_image(current_char, n_real_emote, false); + } f_emote->show(); - f_emote->setToolTip(QString::number(n_real_emote + 1) + ": " + - ao_app->get_emote_comment(current_char, n_real_emote)); + f_emote->setToolTip(QString::number(n_real_emote + 1) + ": " + ao_app->get_emote_comment(current_char, n_real_emote)); } } @@ -167,14 +172,14 @@ void Courtroom::set_emote_dropdown() int total_emotes = ao_app->get_emote_number(current_char); - for (int n = 0; n < total_emotes; ++n) { - ui_emote_dropdown->addItem(QString::number(n + 1) + ": " + - ao_app->get_emote_comment(current_char, n)); - QString icon_path = ao_app->get_image_suffix(ao_app->get_character_path( - current_char, "emotions/button" + QString::number(n + 1) + "_off")); + for (int n = 0; n < total_emotes; ++n) + { + ui_emote_dropdown->addItem(QString::number(n + 1) + ": " + ao_app->get_emote_comment(current_char, n)); + QString icon_path = ao_app->get_image_suffix(ao_app->get_character_path(current_char, "emotions/button" + QString::number(n + 1) + "_off")); ui_emote_dropdown->setItemIcon(n, QIcon(icon_path)); } - if (current_emote > -1 && current_emote < ui_emote_dropdown->count()) { + if (current_emote > -1 && current_emote < ui_emote_dropdown->count()) + { ui_emote_dropdown->setCurrentIndex(current_emote); } } @@ -185,27 +190,33 @@ void Courtroom::select_emote(int p_id) int max = (max_emotes_on_page - 1) + current_emote_page * max_emotes_on_page; if (current_emote >= min && current_emote <= max) - ui_emote_list.at(current_emote % max_emotes_on_page) - ->set_char_image(current_char, current_emote, false); + { + ui_emote_list.at(current_emote % max_emotes_on_page)->set_char_image(current_char, current_emote, false); + } int old_emote = current_emote; current_emote = p_id; if (current_emote >= min && current_emote <= max) - ui_emote_list.at(current_emote % max_emotes_on_page) - ->set_char_image(current_char, current_emote, true); + { + ui_emote_list.at(current_emote % max_emotes_on_page)->set_char_image(current_char, current_emote, true); + } int emote_mod = ao_app->get_emote_mod(current_char, current_emote); - if (old_emote == current_emote) { + if (old_emote == current_emote) + { ui_pre->setChecked(!ui_pre->isChecked()); } - else if (!Options::getInstance().clearPreOnPlayEnabled()) { - if (emote_mod == PREANIM || emote_mod == PREANIM_ZOOM) { + else if (!Options::getInstance().clearPreOnPlayEnabled()) + { + if (emote_mod == PREANIM || emote_mod == PREANIM_ZOOM) + { ui_pre->setChecked(true); } - else { + else + { ui_pre->setChecked(false); } } @@ -215,16 +226,20 @@ void Courtroom::select_emote(int p_id) ui_ic_chat_message->setFocus(); } -void Courtroom::update_emote_preview() { - if (!emote_preview->isVisible()) { +void Courtroom::update_emote_preview() +{ + if (!emote_preview->isVisible()) + { return; } QString emote; QString pre = ao_app->get_pre_emote(current_char, current_emote); - if (ui_pre->isChecked() && !pre.isEmpty() && pre != "-") { + if (ui_pre->isChecked() && !pre.isEmpty() && pre != "-") + { emote = pre; } - else { + else + { emote = "(b)" + ao_app->get_emote(current_char, current_emote); } preview_emote(emote); @@ -237,38 +252,38 @@ void Courtroom::on_emote_clicked(int p_id) void Courtroom::show_emote_menu(const QPoint &pos) { - QWidget* button = qobject_cast<QWidget*>(sender()); + QWidget *button = qobject_cast<QWidget *>(sender()); int id = current_emote; - if (qobject_cast<AOEmoteButton*>(button)) { - AOEmoteButton* emote_button = qobject_cast<AOEmoteButton*>(sender()); + if (qobject_cast<AOEmoteButton *>(button)) + { + AOEmoteButton *emote_button = qobject_cast<AOEmoteButton *>(sender()); id = emote_button->get_id(); } int emote_num = id + max_emotes_on_page * current_emote_page; emote_menu->clear(); - emote_menu->setDefaultAction(emote_menu->addAction("Preview Selected", this, [=]{ + emote_menu->setDefaultAction(emote_menu->addAction("Preview Selected", this, [=] { emote_preview->show(); emote_preview->raise(); emote_preview->set_widgets(); update_emote_preview(); - } - )); - QString prefix = ""; + })); + QString prefix; QString f_pre = ao_app->get_pre_emote(current_char, emote_num); - if (!f_pre.isEmpty() && f_pre != "-") { - emote_menu->addAction("Preview pre: " + f_pre, this, [=]{ preview_emote(f_pre); }); + if (!f_pre.isEmpty() && f_pre != "-") + { + emote_menu->addAction("Preview pre: " + f_pre, this, [=] { preview_emote(f_pre); }); } QString f_emote = ao_app->get_emote(current_char, emote_num); - if (!f_emote.isEmpty()) { - emote_menu->addAction("Preview idle: " + f_emote, this, [=]{ preview_emote("(a)" + f_emote); }); - emote_menu->addAction("Preview talk: " + f_emote, this, [=]{ preview_emote("(b)" + f_emote); }); - QStringList c_paths = { - ao_app->get_image_suffix(ao_app->get_character_path(current_char, "(c)" + f_emote)), - ao_app->get_image_suffix(ao_app->get_character_path(current_char, "(c)/" + f_emote)) - }; + if (!f_emote.isEmpty()) + { + emote_menu->addAction("Preview idle: " + f_emote, this, [=] { preview_emote("(a)" + f_emote); }); + emote_menu->addAction("Preview talk: " + f_emote, this, [=] { preview_emote("(b)" + f_emote); }); + QStringList c_paths = {ao_app->get_image_suffix(ao_app->get_character_path(current_char, "(c)" + f_emote)), ao_app->get_image_suffix(ao_app->get_character_path(current_char, "(c)/" + f_emote))}; // if there is a (c) animation - if (file_exists(ui_vp_player_char->find_image(c_paths))) { - emote_menu->addAction("Preview segway: " + f_emote, this, [=]{ preview_emote("(c)" + f_emote); }); + if (file_exists(ui_vp_player_char->find_image(c_paths))) + { + emote_menu->addAction("Preview segway: " + f_emote, this, [=] { preview_emote("(c)" + f_emote); }); } } emote_menu->popup(button->mapToGlobal(pos)); diff --git a/src/eventfilters.cpp b/src/eventfilters.cpp new file mode 100644 index 00000000..2e11b587 --- /dev/null +++ b/src/eventfilters.cpp @@ -0,0 +1,21 @@ +#include "eventfilters.h" + +bool AOLineEditFilter::eventFilter(QObject *obj, QEvent *event) +{ + QLineEdit *lineEdit = qobject_cast<QLineEdit *>(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; +} diff --git a/src/eventfilters.h b/src/eventfilters.h new file mode 100644 index 00000000..3eb98147 --- /dev/null +++ b/src/eventfilters.h @@ -0,0 +1,18 @@ +#pragma once + +#include <QEvent> +#include <QLineEdit> + +class AOLineEditFilter : public QObject +{ + Q_OBJECT + +public: + bool preserve_selection = false; + +Q_SIGNALS: + void double_clicked(); + +protected: + bool eventFilter(QObject *obj, QEvent *event) override; +}; diff --git a/src/evidence.cpp b/src/evidence.cpp index 752ca47d..4377b257 100644 --- a/src/evidence.cpp +++ b/src/evidence.cpp @@ -3,7 +3,7 @@ void Courtroom::initialize_evidence() { - ui_evidence = new AOImage(this, ao_app); + ui_evidence = new AOImage(ao_app, this); ui_evidence->setObjectName("ui_evidence"); // ui_evidence_name = new QLabel(ui_evidence); @@ -18,90 +18,72 @@ void Courtroom::initialize_evidence() ui_evidence_buttons = new QWidget(ui_evidence); ui_evidence_buttons->setObjectName("ui_evidence_buttons"); - ui_evidence_left = new AOButton(ui_evidence, ao_app); + ui_evidence_left = new AOButton(ao_app, ui_evidence); ui_evidence_left->setObjectName("ui_evidence_left"); - ui_evidence_right = new AOButton(ui_evidence, ao_app); + ui_evidence_right = new AOButton(ao_app, ui_evidence); ui_evidence_right->setObjectName("ui_evidence_right"); - ui_evidence_present = new AOButton(ui_evidence, ao_app); + ui_evidence_present = new AOButton(ao_app, ui_evidence); ui_evidence_present->setToolTip(tr("Present this piece of evidence to " "everyone on your next spoken message")); ui_evidence_present->setObjectName("ui_evidence_present"); - ui_evidence_switch = new AOButton(ui_evidence, ao_app); + ui_evidence_switch = new AOButton(ao_app, ui_evidence); ui_evidence_switch->setObjectName("ui_evidence_switch"); - ui_evidence_transfer = new AOButton(ui_evidence, ao_app); + ui_evidence_transfer = new AOButton(ao_app, ui_evidence); ui_evidence_transfer->setObjectName("ui_evidence_transfer"); - ui_evidence_save = new AOButton(ui_evidence, ao_app); + ui_evidence_save = new AOButton(ao_app, ui_evidence); ui_evidence_save->setToolTip(tr("Save evidence to an .ini file.")); ui_evidence_save->setObjectName("ui_evidence_save"); - ui_evidence_load = new AOButton(ui_evidence, ao_app); + ui_evidence_load = new AOButton(ao_app, ui_evidence); ui_evidence_load->setToolTip(tr("Load evidence from an .ini file.")); ui_evidence_load->setObjectName("ui_evidence_load"); - ui_evidence_overlay = new AOImage(ui_evidence, ao_app); + ui_evidence_overlay = new AOImage(ao_app, ui_evidence); ui_evidence_overlay->setObjectName("ui_evidence_overlay"); - ui_evidence_delete = new AOButton(ui_evidence_overlay, ao_app); + ui_evidence_delete = new AOButton(ao_app, ui_evidence_overlay); ui_evidence_delete->setToolTip(tr("Destroy this piece of evidence")); ui_evidence_delete->setObjectName("ui_evidence_delete"); 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 = new AOButton(ao_app, ui_evidence_overlay); ui_evidence_image_button->setText(tr("Choose..")); ui_evidence_image_button->setObjectName("ui_evidence_image_button"); - ui_evidence_x = new AOButton(ui_evidence_overlay, ao_app); - ui_evidence_x->setToolTip( - tr("Close the evidence display/editing overlay.\n" - "You will be prompted if there's any unsaved changes.")); + ui_evidence_x = new AOButton(ao_app, ui_evidence_overlay); + ui_evidence_x->setToolTip(tr("Close the evidence display/editing overlay.\n" + "You will be prompted if there's any unsaved changes.")); ui_evidence_x->setObjectName("ui_evidence_x"); - ui_evidence_ok = new AOButton(ui_evidence_overlay, ao_app); + ui_evidence_ok = new AOButton(ao_app, ui_evidence_overlay); ui_evidence_ok->setToolTip(tr("Save any changes made to this piece of " "evidence and send them to server.")); ui_evidence_ok->setObjectName("ui_evidence_ok"); ui_evidence_description = new QPlainTextEdit(ui_evidence_overlay); ui_evidence_description->setFrameStyle(QFrame::NoFrame); - ui_evidence_description->setToolTip( - tr("Click to edit. Press [X] to update your changes.")); + ui_evidence_description->setToolTip(tr("Click to edit. Press [X] to update your changes.")); ui_evidence_description->setObjectName("ui_evidence_description"); - 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_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_edited); - connect(ui_evidence_description, &QPlainTextEdit::textChanged, this, - &Courtroom::on_evidence_edited); + 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_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_edited); + connect(ui_evidence_description, &QPlainTextEdit::textChanged, this, &Courtroom::on_evidence_edited); ui_evidence->hide(); evidence_load("inventories/autosave.ini"); @@ -123,9 +105,13 @@ void Courtroom::refresh_evidence() set_size_and_pos(ui_evidence, "evidence_background"); if (current_evidence_global) + { ui_evidence->set_image("evidence_background"); + } else + { ui_evidence->set_image("evidence_background_private"); + } set_size_and_pos(ui_evidence_name, "evidence_name"); @@ -142,9 +128,13 @@ void Courtroom::refresh_evidence() set_size_and_pos(ui_evidence_overlay, "evidence_overlay"); if (current_evidence_global) + { ui_evidence_overlay->set_image("evidence_overlay"); + } else + { ui_evidence_overlay->set_image("evidence_overlay_private"); + } set_size_and_pos(ui_evidence_delete, "evidence_delete"); ui_evidence_delete->set_image("evidence_delete"); @@ -160,47 +150,55 @@ void Courtroom::refresh_evidence() ui_evidence_ok->set_image("evidence_ok"); set_size_and_pos(ui_evidence_switch, "evidence_switch"); - if (current_evidence_global) { + if (current_evidence_global) + { ui_evidence_switch->set_image("evidence_global"); ui_evidence_switch->setToolTip(tr("Switch evidence to private inventory.")); } - else { + else + { ui_evidence_switch->set_image("evidence_private"); ui_evidence_switch->setToolTip(tr("Switch evidence to global inventory.")); } set_size_and_pos(ui_evidence_transfer, "evidence_transfer"); - if (current_evidence_global) { + if (current_evidence_global) + { ui_evidence_transfer->set_image("evidence_transfer"); - ui_evidence_transfer->setToolTip( - tr("Transfer evidence to private inventory.")); + ui_evidence_transfer->setToolTip(tr("Transfer evidence to private inventory.")); } - else { + else + { ui_evidence_transfer->set_image("evidence_transfer_private"); - ui_evidence_transfer->setToolTip( - tr("Transfer evidence to global inventory.")); + ui_evidence_transfer->setToolTip(tr("Transfer evidence to global inventory.")); } set_size_and_pos(ui_evidence_save, "evidence_save"); ui_evidence_save->set_image("evidence_save"); if (current_evidence_global) + { ui_evidence_save->hide(); + } else + { ui_evidence_save->show(); + } set_size_and_pos(ui_evidence_load, "evidence_load"); ui_evidence_load->set_image("evidence_load"); if (current_evidence_global) + { ui_evidence_load->hide(); + } else + { ui_evidence_load->show(); + } set_size_and_pos(ui_evidence_description, "evidence_description"); - QPoint f_spacing = ao_app->get_button_spacing("evidence_button_spacing", - "courtroom_design.ini"); - QPoint p_point = ao_app->get_button_spacing("evidence_button_size", - "courtroom_design.ini"); + QPoint f_spacing = ao_app->get_button_spacing("evidence_button_spacing", "courtroom_design.ini"); + QPoint p_point = ao_app->get_button_spacing("evidence_button_size", "courtroom_design.ini"); const int button_width = p_point.x(); int x_spacing = f_spacing.x(); @@ -210,36 +208,30 @@ void Courtroom::refresh_evidence() int y_spacing = f_spacing.y(); int y_mod_count = 0; - evidence_columns = ((ui_evidence_buttons->width() - button_width) / - (x_spacing + button_width)) + - 1; - evidence_rows = ((ui_evidence_buttons->height() - button_height) / - (y_spacing + button_height)) + - 1; + evidence_columns = ((ui_evidence_buttons->width() - button_width) / qMax(1, x_spacing + button_width)) + 1; + evidence_rows = ((ui_evidence_buttons->height() - button_height) / qMax(1, y_spacing + button_height)) + 1; max_evidence_on_page = evidence_columns * evidence_rows; - for (int n = 0; n < max_evidence_on_page; ++n) { + for (int n = 0; n < max_evidence_on_page; ++n) + { int x_pos = (button_width + x_spacing) * x_mod_count; int y_pos = (button_height + y_spacing) * y_mod_count; - AOEvidenceButton *f_evidence = new AOEvidenceButton( - ui_evidence_buttons, ao_app, x_pos, y_pos, button_width, button_height); + AOEvidenceButton *f_evidence = new AOEvidenceButton(ao_app, x_pos, y_pos, button_width, button_height, ui_evidence_buttons); ui_evidence_list.append(f_evidence); f_evidence->set_id(n); - 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); + 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; - if (x_mod_count == evidence_columns) { + if (x_mod_count == evidence_columns) + { ++y_mod_count; x_mod_count = 0; } @@ -250,8 +242,10 @@ void Courtroom::set_evidence_list(QVector<evi_type> &p_evi_list) { global_evidence_list = p_evi_list; if (!current_evidence_global) + { return; // We're on private evidence editing, wait for user to do their // thing + } QVector<evi_type> old_list = local_evidence_list; local_evidence_list.clear(); @@ -259,11 +253,11 @@ void Courtroom::set_evidence_list(QVector<evi_type> &p_evi_list) set_evidence_page(); - if (ui_evidence_overlay - ->isVisible()) // Update the currently edited evidence for this user + if (ui_evidence_overlay->isVisible()) // Update the currently edited evidence for this user { int p_id = current_evidence - (max_evidence_on_page * current_evidence_page); - if (current_evidence >= local_evidence_list.size()) { + if (current_evidence >= local_evidence_list.size()) + { evidence_close(); ui_evidence_name->setText(""); } @@ -273,27 +267,23 @@ void Courtroom::set_evidence_list(QVector<evi_type> &p_evi_list) } // Todo: make a function that compares two pieces of evidence for any // differences - else if (compare_evidence_changed( - old_list.at(current_evidence), - local_evidence_list.at(current_evidence))) { + else if (compare_evidence_changed(old_list.at(current_evidence), local_evidence_list.at(current_evidence))) + { QMessageBox *msgBox = new QMessageBox; msgBox->setAttribute(Qt::WA_DeleteOnClose); msgBox->setText(tr("The piece of evidence you've been editing has changed.")); msgBox->setInformativeText(tr("Do you wish to keep your changes?")); - msgBox->setDetailedText(tr( - "Name: %1\n" - "Image: %2\n" - "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->setDetailedText(tr("Name: %1\n" + "Image: %2\n" + "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); int ret = msgBox->exec(); - switch (ret) { + switch (ret) + { case QMessageBox::Yes: // "Keep changes" ui_evidence_ok->hide(); @@ -317,7 +307,8 @@ void Courtroom::set_evidence_page() ui_evidence_left->hide(); ui_evidence_right->hide(); - for (AOEvidenceButton *i_button : qAsConst(ui_evidence_list)) { + for (AOEvidenceButton *i_button : qAsConst(ui_evidence_list)) + { i_button->hide(); } @@ -327,48 +318,60 @@ void Courtroom::set_evidence_page() int total_pages = total_evidence / max_evidence_on_page; int evidence_on_page = 0; - if ((total_evidence % max_evidence_on_page) != 0) { + if ((total_evidence % max_evidence_on_page) != 0) + { ++total_pages; // i. e. not on the last page if (total_pages > current_evidence_page + 1) + { evidence_on_page = max_evidence_on_page; + } else + { evidence_on_page = total_evidence % max_evidence_on_page; + } } else + { evidence_on_page = max_evidence_on_page; + } if (total_pages > current_evidence_page + 1) + { ui_evidence_right->show(); + } if (current_evidence_page > 0) + { ui_evidence_left->show(); + } - for (int n_evidence_button = 0; n_evidence_button < evidence_on_page; - ++n_evidence_button) { - int n_real_evidence = - n_evidence_button + current_evidence_page * max_evidence_on_page; - AOEvidenceButton *f_evidence_button = - ui_evidence_list.at(n_evidence_button); + for (int n_evidence_button = 0; n_evidence_button < evidence_on_page; ++n_evidence_button) + { + int n_real_evidence = n_evidence_button + current_evidence_page * max_evidence_on_page; + AOEvidenceButton *f_evidence_button = ui_evidence_list.at(n_evidence_button); f_evidence_button->set_selected(false); f_evidence_button->setToolTip(""); - if (n_real_evidence == (total_evidence - 1)) { + if (n_real_evidence == (total_evidence - 1)) + { f_evidence_button->set_theme_image("addevidence.png"); } - else if (n_real_evidence < (total_evidence - 1)) { - f_evidence_button->set_image( - local_evidence_list.at(n_real_evidence).image); + else if (n_real_evidence < (total_evidence - 1)) + { + f_evidence_button->set_image(local_evidence_list.at(n_real_evidence).image); if (n_real_evidence == current_evidence) + { f_evidence_button->set_selected(true); + } - f_evidence_button->setToolTip( - QString::number(n_real_evidence + 1) + ": " + - local_evidence_list.at(n_real_evidence).name); + f_evidence_button->setToolTip(QString::number(n_real_evidence + 1) + ": " + local_evidence_list.at(n_real_evidence).name); } else + { f_evidence_button->set_image(""); + } f_evidence_button->show(); } @@ -386,17 +389,20 @@ void Courtroom::show_evidence(int f_real_id) on_evidence_double_clicked(p_id); } - void Courtroom::on_evidence_name_edited() { if (current_evidence >= local_evidence_list.size()) + { return; + } } void Courtroom::on_evidence_image_name_edited() { if (current_evidence >= local_evidence_list.size()) + { return; + } } void Courtroom::on_evidence_image_button_clicked() @@ -411,17 +417,23 @@ void Courtroom::on_evidence_image_button_clicked() QStringList filenames; if (dialog.exec()) + { filenames = dialog.selectedFiles(); + } if (filenames.size() != 1) + { return; + } QString filename = filenames.at(0); QStringList bases = Options::getInstance().mountPaths(); bases.prepend(get_base_path()); - for (const QString &base : bases) { + for (const QString &base : bases) + { QDir baseDir(base); - if (filename.startsWith(baseDir.absolutePath() + "/")) { + if (filename.startsWith(baseDir.absolutePath() + "/")) + { dir.setPath(baseDir.absolutePath() + "/evidence"); break; } @@ -435,11 +447,14 @@ void Courtroom::on_evidence_clicked(int p_id) { int f_real_id = p_id + max_evidence_on_page * current_evidence_page; - if (f_real_id == local_evidence_list.size()) { + if (f_real_id == local_evidence_list.size()) + { if (current_evidence_global) - ao_app->send_server_packet( - new AOPacket("PE", {"<name>", "<description>", "empty.png"})); - else { + { + ao_app->send_server_packet(AOPacket("PE", {"<name>", "<description>", "empty.png"})); + } + else + { evi_type f_evi; f_evi.name = "<name>"; f_evi.description = "<description>"; @@ -452,20 +467,26 @@ void Courtroom::on_evidence_clicked(int p_id) return; } else if (f_real_id > local_evidence_list.size()) + { return; - - if (!Options::getInstance().evidenceDoubleClickEdit()){ + } + + if (!Options::getInstance().evidenceDoubleClickEdit()) + { on_evidence_double_clicked(p_id); return; } - if (ui_evidence_overlay->isVisible()) { + if (ui_evidence_overlay->isVisible()) + { return; } ui_evidence_name->setText(local_evidence_list.at(f_real_id).name); for (AOEvidenceButton *i_button : qAsConst(ui_evidence_list)) + { i_button->set_selected(false); + } ui_evidence_list.at(p_id)->set_selected(true); current_evidence = f_real_id; @@ -476,21 +497,28 @@ void Courtroom::on_evidence_double_clicked(int p_id) int f_real_id = p_id + max_evidence_on_page * current_evidence_page; if (f_real_id >= local_evidence_list.size()) + { return; + } - if (ui_evidence_overlay->isVisible()) { - if (!on_evidence_x_clicked()) { + if (ui_evidence_overlay->isVisible()) + { + if (!on_evidence_x_clicked()) + { // We're told not to switch over to the other evidence ("cancel" clicked) return; } } for (AOEvidenceButton *i_button : qAsConst(ui_evidence_list)) + { i_button->set_selected(false); + } // We have to check if the ID is on the currently displayed page. // This is because SOMEONE allowed the switching of pages while evidence is still being edited. - if (p_id < ui_evidence_list.count()) { + if (p_id < ui_evidence_list.count()) + { ui_evidence_list.at(p_id)->set_selected(true); } current_evidence = f_real_id; @@ -518,23 +546,33 @@ void Courtroom::on_evidence_double_clicked(int p_id) void Courtroom::on_evidence_hover(int p_id, bool p_state) { - if (ui_evidence_overlay->isVisible()) { + if (ui_evidence_overlay->isVisible()) + { // Ignore hovering behavior if we're in the process of viewing a piece of evidence return; } int final_id = p_id + max_evidence_on_page * current_evidence_page; - if (p_state) { + if (p_state) + { if (final_id == local_evidence_list.size()) + { ui_evidence_name->setText(tr("Add new evidence...")); + } else if (final_id < local_evidence_list.size()) + { ui_evidence_name->setText(local_evidence_list.at(final_id).name); + } } else if (current_evidence < local_evidence_list.size()) + { ui_evidence_name->setText(local_evidence_list.at(current_evidence).name); + } else + { ui_evidence_name->setText(""); + } } void Courtroom::on_evidence_left_clicked() @@ -553,15 +591,20 @@ void Courtroom::on_evidence_right_clicked() void Courtroom::on_evidence_present_clicked() { - if (!current_evidence_global) { + if (!current_evidence_global) + { ui_evidence_present->hide(); is_presenting_evidence = false; return; // otherwise we get force-disconnected } if (is_presenting_evidence) + { ui_evidence_present->set_image("present"); + } else + { ui_evidence_present->set_image("present_disabled"); + } is_presenting_evidence = !is_presenting_evidence; @@ -572,9 +615,11 @@ void Courtroom::on_evidence_delete_clicked() { evidence_close(); if (current_evidence_global) - ao_app->send_server_packet( - new AOPacket("DE", {QString::number(current_evidence)})); - else { + { + ao_app->send_server_packet(AOPacket("DE", {QString::number(current_evidence)})); + } + else + { local_evidence_list.remove(current_evidence); private_evidence_list = local_evidence_list; set_evidence_page(); @@ -588,11 +633,13 @@ void Courtroom::on_evidence_delete_clicked() bool Courtroom::on_evidence_x_clicked() { - if (current_evidence >= - local_evidence_list.size()) // Should never happen but you never know. + if (current_evidence >= local_evidence_list.size()) // Should never happen but you never know. + { return true; + } - if (ui_evidence_ok->isHidden()) { + if (ui_evidence_ok->isHidden()) + { // Nothing was modified evidence_close(); return true; @@ -601,11 +648,11 @@ bool Courtroom::on_evidence_x_clicked() msgBox->setAttribute(Qt::WA_DeleteOnClose); msgBox->setText(tr("Evidence has been modified.")); msgBox->setInformativeText(tr("Do you want to save your changes?")); - msgBox->setStandardButtons(QMessageBox::Save | QMessageBox::Discard | - QMessageBox::Cancel); + msgBox->setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); msgBox->setDefaultButton(QMessageBox::Save); int ret = msgBox->exec(); - switch (ret) { + switch (ret) + { case QMessageBox::Save: evidence_close(); on_evidence_ok_clicked(); @@ -623,18 +670,21 @@ bool Courtroom::on_evidence_x_clicked() void Courtroom::on_evidence_ok_clicked() { ui_evidence_ok->hide(); - if (current_evidence < local_evidence_list.size()) { + if (current_evidence < local_evidence_list.size()) + { evi_type f_evi = local_evidence_list.at(current_evidence); - if (current_evidence_global) { + if (current_evidence_global) + { QStringList f_contents; f_contents.append(QString::number(current_evidence)); f_contents.append(ui_evidence_name->text()); f_contents.append(ui_evidence_description->toPlainText()); f_contents.append(ui_evidence_image_name->text()); - ao_app->send_server_packet(new AOPacket("EE", f_contents)); + ao_app->send_server_packet(AOPacket("EE", f_contents)); } - else { + else + { f_evi.name = ui_evidence_name->text(); f_evi.description = ui_evidence_description->toPlainText(); f_evi.image = ui_evidence_image_name->text(); @@ -646,7 +696,8 @@ void Courtroom::on_evidence_ok_clicked() } // Autosave private evidence - if (!current_evidence_global) { + if (!current_evidence_global) + { evidence_save("inventories/autosave.ini"); } } @@ -659,7 +710,9 @@ void Courtroom::on_evidence_switch_clicked() void Courtroom::on_evidence_transfer_clicked() { if (current_evidence >= local_evidence_list.size()) + { return; + } QString name; if (!current_evidence_global) // Transfer private evidence to global @@ -672,7 +725,7 @@ void Courtroom::on_evidence_transfer_clicked() f_contents.append(f_evi.image); name = f_evi.name; - ao_app->send_server_packet(new AOPacket("PE", f_contents)); + ao_app->send_server_packet(AOPacket("PE", f_contents)); } else // Transfer global evidence to private { @@ -694,18 +747,22 @@ void Courtroom::on_evidence_transfer_clicked() void Courtroom::on_evidence_edited() { - if (current_evidence >= - local_evidence_list.size()) // Should never happen but you never know. + if (current_evidence >= local_evidence_list.size()) // Should never happen but you never know. + { return; + } evi_type fake_evidence; fake_evidence.name = ui_evidence_name->text(); fake_evidence.description = ui_evidence_description->toPlainText(); fake_evidence.image = ui_evidence_image_name->text(); - if (compare_evidence_changed(fake_evidence, - local_evidence_list.at(current_evidence))) + if (compare_evidence_changed(fake_evidence, local_evidence_list.at(current_evidence))) + { ui_evidence_ok->show(); + } else + { ui_evidence_ok->hide(); + } } void Courtroom::evidence_close() @@ -723,7 +780,8 @@ void Courtroom::evidence_switch(bool global) is_presenting_evidence = false; ui_evidence_present->set_image("present"); local_evidence_list.clear(); - if (current_evidence_global) { + if (current_evidence_global) + { local_evidence_list = global_evidence_list; ui_evidence_present->show(); ui_evidence_save->hide(); @@ -732,12 +790,11 @@ void Courtroom::evidence_switch(bool global) ui_evidence->set_image("evidence_background"); ui_evidence_overlay->set_image("evidence_overlay"); ui_evidence_transfer->set_image("evidence_transfer"); - ui_evidence_transfer->setToolTip( - tr("Transfer evidence to private inventory.")); - ui_evidence_switch->setToolTip( - tr("Current evidence is global. Click to switch to private.")); + ui_evidence_transfer->setToolTip(tr("Transfer evidence to private inventory.")); + ui_evidence_switch->setToolTip(tr("Current evidence is global. Click to switch to private.")); } - else { + else + { local_evidence_list = private_evidence_list; ui_evidence_present->hide(); ui_evidence_save->show(); @@ -746,10 +803,8 @@ void Courtroom::evidence_switch(bool global) ui_evidence->set_image("evidence_background_private"); ui_evidence_overlay->set_image("evidence_overlay_private"); ui_evidence_transfer->set_image("evidence_transfer_private"); - ui_evidence_transfer->setToolTip( - tr("Transfer evidence to global inventory.")); - ui_evidence_switch->setToolTip( - tr("Current evidence is private. Click to switch to global.")); + ui_evidence_transfer->setToolTip(tr("Transfer evidence to global inventory.")); + ui_evidence_switch->setToolTip(tr("Current evidence is private. Click to switch to global.")); } current_evidence_page = 0; set_evidence_page(); @@ -758,17 +813,19 @@ void Courtroom::evidence_switch(bool global) void Courtroom::on_evidence_save_clicked() { if (current_evidence_global) + { return; // Don't allow saving/loading operations when in global inventory // mode for now + } // "Inventories" dir keeps our private evidence data - if (!dir_exists("inventories")) { + if (!dir_exists("inventories")) + { // Create one if it doesn't yet exist QDir("inventories").mkdir("inventories"); } - QString p_path = QFileDialog::getSaveFileName( - this, tr("Save Inventory"), "inventories/", tr("Ini Files (*.ini)")); + QString p_path = QFileDialog::getSaveFileName(this, tr("Save Inventory"), "inventories/", tr("Ini Files (*.ini)")); evidence_close(); ui_evidence_name->setText(""); @@ -779,13 +836,16 @@ void Courtroom::on_evidence_save_clicked() void Courtroom::on_evidence_load_clicked() { if (current_evidence_global) + { return; // Don't allow saving/loading operations when in global inventory // mode for now + } - QString p_path = QFileDialog::getOpenFileName( - this, tr("Open Inventory"), "inventories/", tr("Ini Files (*.ini)")); + QString p_path = QFileDialog::getOpenFileName(this, tr("Open Inventory"), "inventories/", tr("Ini Files (*.ini)")); if (p_path.isEmpty()) + { return; + } evidence_close(); ui_evidence_name->setText(""); @@ -796,7 +856,8 @@ void Courtroom::on_evidence_load_clicked() void Courtroom::evidence_load(QString filename) { - if (!file_exists(filename)) { + if (!file_exists(filename)) + { qWarning() << "Trying to load a non-existant evidence save file:" << filename; return; } @@ -805,16 +866,17 @@ void Courtroom::evidence_load(QString filename) inventory.setIniCodec("UTF-8"); #endif private_evidence_list.clear(); - foreach (QString evi, inventory.childGroups()) { + foreach (QString evi, inventory.childGroups()) + { if (evi == "General") + { continue; + } evi_type f_evi; f_evi.name = inventory.value(evi + "/name", "<name>").value<QString>(); - f_evi.description = - inventory.value(evi + "/description", "<description>").value<QString>(); - f_evi.image = - inventory.value(evi + "/image", "empty.png").value<QString>(); + f_evi.description = inventory.value(evi + "/description", "<description>").value<QString>(); + f_evi.image = inventory.value(evi + "/image", "empty.png").value<QString>(); private_evidence_list.append(f_evi); } } @@ -822,7 +884,8 @@ void Courtroom::evidence_load(QString filename) void Courtroom::evidence_save(QString filename) { // "Inventories" dir keeps our private evidence data - if (!dir_exists("inventories")) { + if (!dir_exists("inventories")) + { // Create one if it doesn't yet exist QDir("inventories").mkdir("inventories"); } @@ -832,7 +895,8 @@ void Courtroom::evidence_save(QString filename) inventory.setIniCodec("UTF-8"); #endif inventory.clear(); - for (int i = 0; i < private_evidence_list.size(); i++) { + for (int i = 0; i < private_evidence_list.size(); i++) + { inventory.beginGroup(QString::number(i)); inventory.setValue("name", private_evidence_list[i].name); inventory.setValue("description", private_evidence_list[i].description); @@ -844,6 +908,5 @@ void Courtroom::evidence_save(QString filename) bool Courtroom::compare_evidence_changed(evi_type evi_a, evi_type evi_b) { - return evi_a.name != evi_b.name || evi_a.image != evi_b.image || - evi_a.description != evi_b.description; + return evi_a.name != evi_b.name || evi_a.image != evi_b.image || evi_a.description != evi_b.description; } diff --git a/src/file_functions.cpp b/src/file_functions.cpp index 92e598f8..fef34f54 100644 --- a/src/file_functions.cpp +++ b/src/file_functions.cpp @@ -3,7 +3,9 @@ bool file_exists(QString file_path) { if (file_path.isEmpty()) + { return false; + } QFileInfo check_file(file_path); @@ -13,7 +15,9 @@ bool file_exists(QString file_path) bool dir_exists(QString dir_path) { if (dir_path == "") - return false; + { + return false; + } QDir check_dir(dir_path); @@ -29,13 +33,15 @@ bool exists(QString p_path) QString get_base_path() { - QString base_path = ""; + QString base_path; #ifdef ANDROID QString sdcard_storage = getenv("SECONDARY_STORAGE"); - if (dir_exists(sdcard_storage + "/base/")) { + if (dir_exists(sdcard_storage + "/base/")) + { base_path = sdcard_storage + "/base/"; } - else { + else + { QString external_storage = getenv("EXTERNAL_STORAGE"); base_path = external_storage + "/base/"; } diff --git a/src/file_functions.h b/src/file_functions.h new file mode 100644 index 00000000..ca1eeb5e --- /dev/null +++ b/src/file_functions.h @@ -0,0 +1,11 @@ +#pragma once + +#include <QCoreApplication> +#include <QDir> +#include <QFileInfo> +#include <QString> + +bool file_exists(QString file_path); +bool dir_exists(QString file_path); +bool exists(QString p_path); +QString get_base_path(); diff --git a/src/gui_utils.h b/src/gui_utils.h new file mode 100644 index 00000000..b43fe5da --- /dev/null +++ b/src/gui_utils.h @@ -0,0 +1,3 @@ +#pragma once + +#define FROM_UI(type, name) ui_##name = findChild<type *>(#name) diff --git a/src/hardware_functions.cpp b/src/hardware_functions.cpp index 14296803..67b5cafa 100644 --- a/src/hardware_functions.cpp +++ b/src/hardware_functions.cpp @@ -3,50 +3,54 @@ #include <QDebug> #include <QtGlobal> +#include <stdio.h> + #if (defined(_WIN32) || defined(_WIN64)) +// clang-format off #include <windows.h> #include <sddl.h> +// clang-format on QString get_hdid() { - HANDLE hToken; - HANDLE pHandle; - PTOKEN_USER pToken; - DWORD uSize = 0; - LPWSTR HDIDParam; - - pHandle = GetCurrentProcess(); - OpenProcessToken(pHandle, TOKEN_QUERY, &hToken); - if (!GetTokenInformation(hToken, (TOKEN_INFORMATION_CLASS)1, NULL, 0, &uSize)) + HANDLE hToken; + HANDLE pHandle; + PTOKEN_USER pToken; + DWORD uSize = 0; + LPWSTR HDIDParam; + + pHandle = GetCurrentProcess(); + OpenProcessToken(pHandle, TOKEN_QUERY, &hToken); + if (!GetTokenInformation(hToken, (TOKEN_INFORMATION_CLASS)1, NULL, 0, &uSize)) + { + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { - if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { - CloseHandle(hToken); - return "gxsps32sa9fnwic92mfbs1"; - } + CloseHandle(hToken); + return "gxsps32sa9fnwic92mfbs1"; } + } - pToken = (PTOKEN_USER)GlobalAlloc(GPTR, uSize); - - if (!GetTokenInformation(hToken, (TOKEN_INFORMATION_CLASS)1, pToken, uSize, &uSize)) - { - CloseHandle(hToken); - return "gxsps32sa9fnwic92mfbs2"; - } + pToken = (PTOKEN_USER)GlobalAlloc(GPTR, uSize); - ConvertSidToStringSidW(pToken->User.Sid, &HDIDParam); - QString returnHDID = QString::fromWCharArray(HDIDParam); + if (!GetTokenInformation(hToken, (TOKEN_INFORMATION_CLASS)1, pToken, uSize, &uSize)) + { CloseHandle(hToken); - return returnHDID; + return "gxsps32sa9fnwic92mfbs2"; + } + + ConvertSidToStringSidW(pToken->User.Sid, &HDIDParam); + QString returnHDID = QString::fromWCharArray(HDIDParam); + CloseHandle(hToken); + return returnHDID; } #elif defined(ANDROID) +#include <QtAndroidExtras/QtAndroid> + QString get_hdid() { - QAndroidJniObject appctx = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;").callObjectMethod("getApplicationContext","()Landroid/content/Context;"); - QAndroidJniObject androidId = QAndroidJniObject::callStaticObjectMethod("android/provider/Settings$Secure","getString", - "(Landroid/content/ContentResolver;Ljava/lang/String;)Ljava/lang/String;", - appctx.callObjectMethod("getContentResolver", "()Landroid/content/ContentResolver;").object<jobject>(), - QAndroidJniObject::fromString("android_id").object<jstring>()); - return androidId.toString(); + QAndroidJniObject appctx = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;").callObjectMethod("getApplicationContext", "()Landroid/content/Context;"); + QAndroidJniObject androidId = QAndroidJniObject::callStaticObjectMethod("android/provider/Settings$Secure", "getString", "(Landroid/content/ContentResolver;Ljava/lang/String;)Ljava/lang/String;", appctx.callObjectMethod("getContentResolver", "()Landroid/content/ContentResolver;").object<jobject>(), QAndroidJniObject::fromString("android_id").object<jstring>()); + return androidId.toString(); } #elif QT_VERSION < QT_VERSION_CHECK(5, 11, 0) #if (defined(LINUX) || defined(__linux__)) @@ -58,7 +62,8 @@ QString get_hdid() { machineId = QSysInfo::machineUniqueId(); - if (machineId.isEmpty()) { + if (machineId.isEmpty()) + { return "gxsps32sa9fnwic92mfbs2"; } return QString(machineId); @@ -74,16 +79,16 @@ QString get_hdid() CFStringRef serial; char buffer[64] = {0}; QString hdid; - io_service_t platformExpert = IOServiceGetMatchingService( - kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice")); - if (platformExpert) { - CFTypeRef serialNumberAsCFString = IORegistryEntryCreateCFProperty( - platformExpert, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, - 0); - if (serialNumberAsCFString) { + io_service_t platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice")); + if (platformExpert) + { + CFTypeRef serialNumberAsCFString = IORegistryEntryCreateCFProperty(platformExpert, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0); + if (serialNumberAsCFString) + { serial = (CFStringRef)serialNumberAsCFString; } - if (CFStringGetCString(serial, buffer, 64, kCFStringEncodingUTF8)) { + if (CFStringGetCString(serial, buffer, 64, kCFStringEncodingUTF8)) + { hdid = buffer; } diff --git a/src/hardware_functions.h b/src/hardware_functions.h new file mode 100644 index 00000000..65e5bc68 --- /dev/null +++ b/src/hardware_functions.h @@ -0,0 +1,5 @@ +#pragma once + +#include <QString> + +QString get_hdid(); diff --git a/src/interfaces/server_dialog.h b/src/interfaces/server_dialog.h new file mode 100644 index 00000000..98c57fee --- /dev/null +++ b/src/interfaces/server_dialog.h @@ -0,0 +1,20 @@ +#pragma once + +#include <QDialog> + +namespace AttorneyOnline +{ +namespace UI +{ +class FavoriteServerDialog : public QDialog +{ +public: + const QString DEFAULT_UI = "favorite_server_dialog.ui"; + const int TCP_INDEX = 0; + +private Q_SLOTS: + virtual void onSavePressed() = 0; + virtual void onCancelPressed() = 0; +}; +} // namespace UI +} // namespace AttorneyOnline diff --git a/src/lobby.cpp b/src/lobby.cpp index 85cc7449..6c64804d 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -2,44 +2,28 @@ #include "aoapplication.h" #include "demoserver.h" +#include "gui_utils.h" #include "networkmanager.h" #include "widgets/add_server_dialog.h" #include "widgets/direct_connect_dialog.h" #include "widgets/edit_server_dialog.h" #include <QImageReader> -#include <QLabel> -#include <QLineEdit> -#include <QPushButton> -#include <QTreeWidget> - #include <QUiLoader> -#define FROM_UI(type, name) \ - ; \ - ui_##name = findChild<type *>(#name); - -#define COMBO_RELOAD() \ - list_servers(); \ - list_favorites(); \ - list_demos(); \ - get_motd(); \ - check_for_updates(); \ - reset_selection(); - Lobby::Lobby(AOApplication *p_ao_app, NetworkManager *p_net_manager) : QMainWindow() { ao_app = p_ao_app; net_manager = p_net_manager; - loadUI(); - COMBO_RELOAD() + reloadUi(); } void Lobby::on_tab_changed(int index) { - switch (index) { + switch (index) + { case SERVER: current_page = SERVER; ui_add_to_favorite_button->setVisible(true); @@ -74,14 +58,17 @@ void Lobby::on_tab_changed(int index) int Lobby::get_selected_server() { - switch (ui_connections_tabview->currentIndex()) { + switch (ui_connections_tabview->currentIndex()) + { case SERVER: - if (auto item = ui_serverlist_tree->currentItem()) { + if (auto item = ui_serverlist_tree->currentItem()) + { return item->text(0).toInt(); } break; case FAVORITES: - if (auto item = ui_favorites_tree->currentItem()) { + if (auto item = ui_favorites_tree->currentItem()) + { return item->text(0).toInt(); } break; @@ -91,7 +78,10 @@ int Lobby::get_selected_server() return -1; } -int Lobby::pageSelected() { return current_page; } +int Lobby::pageSelected() +{ + return current_page; +} void Lobby::reset_selection() { @@ -106,14 +96,14 @@ void Lobby::reset_selection() void Lobby::loadUI() { - this->setWindowTitle( - tr("Attorney Online %1").arg(ao_app->applicationVersion())); + this->setWindowTitle(tr("Attorney Online %1").arg(ao_app->applicationVersion())); this->setWindowIcon(QIcon(":/logo.png")); this->setWindowFlags((this->windowFlags() | Qt::CustomizeWindowHint)); QUiLoader l_loader(this); QFile l_uiFile(Options::getInstance().getUIAsset(DEFAULT_UI)); - if (!l_uiFile.open(QFile::ReadOnly)) { + if (!l_uiFile.open(QFile::ReadOnly)) + { qCritical() << "Unable to open file " << l_uiFile.fileName(); return; } @@ -121,95 +111,75 @@ void Lobby::loadUI() l_loader.load(&l_uiFile, this); FROM_UI(QLabel, game_version_lbl); - ui_game_version_lbl->setText( - tr("Version: %1").arg(ao_app->get_version_string())); + ui_game_version_lbl->setText(tr("Version: %1").arg(ao_app->get_version_string())); FROM_UI(QPushButton, settings_button); - connect(ui_settings_button, &QPushButton::clicked, this, - &Lobby::onSettingsRequested); + connect(ui_settings_button, &QPushButton::clicked, this, &Lobby::onSettingsRequested); FROM_UI(QPushButton, about_button); - connect(ui_about_button, &QPushButton::clicked, this, - &Lobby::on_about_clicked); + connect(ui_about_button, &QPushButton::clicked, this, &Lobby::on_about_clicked); // Serverlist elements FROM_UI(QTabWidget, connections_tabview); ui_connections_tabview->tabBar()->setExpanding(true); - connect(ui_connections_tabview, &QTabWidget::currentChanged, this, - &Lobby::on_tab_changed); + connect(ui_connections_tabview, &QTabWidget::currentChanged, this, &Lobby::on_tab_changed); FROM_UI(QTreeWidget, serverlist_tree); FROM_UI(QLineEdit, serverlist_search); - connect(ui_serverlist_tree, &QTreeWidget::itemClicked, this, - &Lobby::on_server_list_clicked); - connect(ui_serverlist_tree, &QTreeWidget::itemDoubleClicked, this, - &Lobby::on_list_doubleclicked); - connect(ui_serverlist_search, &QLineEdit::textChanged, this, - &Lobby::on_server_search_edited); + connect(ui_serverlist_tree, &QTreeWidget::itemClicked, this, &Lobby::on_server_list_clicked); + connect(ui_serverlist_tree, &QTreeWidget::itemDoubleClicked, this, &Lobby::on_list_doubleclicked); + connect(ui_serverlist_search, &QLineEdit::textChanged, this, &Lobby::on_server_search_edited); FROM_UI(QTreeWidget, favorites_tree); - connect(ui_favorites_tree, &QTreeWidget::itemClicked, this, - &Lobby::on_favorite_tree_clicked); - connect(ui_favorites_tree, &QTreeWidget::itemDoubleClicked, this, - &Lobby::on_list_doubleclicked); + connect(ui_favorites_tree, &QTreeWidget::itemClicked, this, &Lobby::on_favorite_tree_clicked); + connect(ui_favorites_tree, &QTreeWidget::itemDoubleClicked, this, &Lobby::on_list_doubleclicked); FROM_UI(QTreeWidget, demo_tree); - connect(ui_demo_tree, &QTreeWidget::itemClicked, this, - &Lobby::on_demo_clicked); - connect(ui_demo_tree, &QTreeWidget::itemDoubleClicked, this, - &Lobby::on_list_doubleclicked); + connect(ui_demo_tree, &QTreeWidget::itemClicked, this, &Lobby::on_demo_clicked); + connect(ui_demo_tree, &QTreeWidget::itemDoubleClicked, this, &Lobby::on_list_doubleclicked); FROM_UI(QPushButton, refresh_button); - connect(ui_refresh_button, &QPushButton::released, this, - &Lobby::on_refresh_released); + connect(ui_refresh_button, &QPushButton::released, this, &Lobby::on_refresh_released); FROM_UI(QPushButton, direct_connect_button); - connect(ui_direct_connect_button, &QPushButton::released, this, - &Lobby::on_direct_connect_released); + connect(ui_direct_connect_button, &QPushButton::released, this, &Lobby::on_direct_connect_released); - FROM_UI(QPushButton, add_to_favorite_button) - connect(ui_add_to_favorite_button, &QPushButton::released, this, - &Lobby::on_add_to_fav_released); + FROM_UI(QPushButton, add_to_favorite_button); + connect(ui_add_to_favorite_button, &QPushButton::released, this, &Lobby::on_add_to_fav_released); - FROM_UI(QPushButton, add_server_button) + FROM_UI(QPushButton, add_server_button); ui_add_server_button->setVisible(false); - connect(ui_add_server_button, &QPushButton::released, this, - &Lobby::on_add_server_to_fave_released); + connect(ui_add_server_button, &QPushButton::released, this, &Lobby::on_add_server_to_fave_released); - FROM_UI(QPushButton, edit_favorite_button) + FROM_UI(QPushButton, edit_favorite_button); ui_edit_favorite_button->setVisible(false); - connect(ui_edit_favorite_button, &QPushButton::released, this, - &Lobby::on_edit_favorite_released) + connect(ui_edit_favorite_button, &QPushButton::released, this, &Lobby::on_edit_favorite_released); - FROM_UI(QPushButton, remove_from_favorites_button) - ui_remove_from_favorites_button->setVisible(false); - connect(ui_remove_from_favorites_button, &QPushButton::released, this, - &Lobby::on_remove_from_fav_released); + FROM_UI(QPushButton, remove_from_favorites_button); + ui_remove_from_favorites_button->setVisible(false); + connect(ui_remove_from_favorites_button, &QPushButton::released, this, &Lobby::on_remove_from_fav_released); - FROM_UI(QLabel, server_player_count_lbl) - FROM_UI(QTextBrowser, server_description_text) + FROM_UI(QLabel, server_player_count_lbl); + FROM_UI(QTextBrowser, server_description_text); FROM_UI(QPushButton, connect_button); - connect(ui_connect_button, &QPushButton::released, net_manager, - &NetworkManager::join_to_server); - connect(ui_connect_button, &QPushButton::released, this, [=] { - ui_server_player_count_lbl->setText(tr("Joining Server...")); - }); - connect(net_manager, &NetworkManager::server_connected, ui_connect_button, - &QPushButton::setEnabled); + connect(ui_connect_button, &QPushButton::released, net_manager, &NetworkManager::join_to_server); + connect(ui_connect_button, &QPushButton::released, this, [=] { ui_server_player_count_lbl->setText(tr("Joining Server...")); }); + connect(net_manager, &NetworkManager::server_connected, ui_connect_button, &QPushButton::setEnabled); FROM_UI(QTextBrowser, motd_text); - FROM_UI(QTextBrowser, game_changelog_text) - if (ui_game_changelog_text != nullptr) { + FROM_UI(QTextBrowser, game_changelog_text); + if (ui_game_changelog_text != nullptr) + { QString l_changelog_text = "No changelog found."; QFile l_changelog(get_base_path() + "changelog.md"); - if (!l_changelog.open(QFile::ReadOnly)) { + if (!l_changelog.open(QFile::ReadOnly)) + { qDebug() << "Unable to locate changelog file. Does it even exist?"; #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) ui_game_changelog_text->setMarkdown(l_changelog_text); #else - ui_game_changelog_text->setPlainText( - l_changelog_text); // imperfect solution, but implementing Markdown - // ourselves for this edge case is out of scope + ui_game_changelog_text->setPlainText(l_changelog_text); // imperfect solution, but implementing Markdown + // ourselves for this edge case is out of scope #endif return; } @@ -221,12 +191,24 @@ void Lobby::loadUI() l_changelog.close(); QTabWidget *l_tabbar = findChild<QTabWidget *>("motd_changelog_tab"); - if (l_tabbar != nullptr) { + if (l_tabbar != nullptr) + { l_tabbar->tabBar()->setExpanding(true); } } } +void Lobby::reloadUi() +{ + loadUI(); + list_servers(); + list_favorites(); + list_demos(); + get_motd(); + check_for_updates(); + reset_selection(); +} + void Lobby::on_refresh_released() { net_manager->get_server_list(); @@ -243,7 +225,8 @@ void Lobby::on_direct_connect_released() void Lobby::on_add_to_fav_released() { int selection = get_selected_server(); - if (selection > -1) { + if (selection > -1) + { Options::getInstance().addFavorite(ao_app->get_server_list().at(selection)); list_favorites(); } @@ -268,7 +251,8 @@ void Lobby::on_edit_favorite_released() void Lobby::on_remove_from_fav_released() { int selection = get_selected_server(); - if (selection >= 0) { + if (selection >= 0) + { Options::getInstance().removeFavorite(selection); list_favorites(); } @@ -277,47 +261,46 @@ void Lobby::on_remove_from_fav_released() void Lobby::on_about_clicked() { const bool hasApng = QImageReader::supportedImageFormats().contains("apng"); - QString msg = - tr("<h2>Attorney Online %1</h2>" - "The courtroom drama simulator." - "<p><b>Source code:</b> " - "<a href='https://github.com/AttorneyOnline/AO2-Client'>" - "https://github.com/AttorneyOnline/AO2-Client</a>" - "<p><b>Major development:</b><br>" - "OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, " - "Crystalwarrior, Iamgoofball, in1tiate" - "<p><b>Client development:</b><br>" - "Cents02, windrammer, skyedeving, TrickyLeifa, Salanto, lambdcalculus" - "<p><b>QA testing:</b><br>" - "CaseyCazy, CedricDewitt, Chewable Tablets, CrazyJC, Fantos, " - "Fury McFlurry, Geck, Gin-Gi, Jamania, Minx, Pandae, " - "Robotic Overlord, Shadowlions (aka Shali), Sierra, SomeGuy, " - "Veritas, Wiso" - "<p><b>Translations:</b><br>" - "k-emiko (Русский), Pyraq (Polski), scatterflower (日本語), vintprox " - "(Русский), " - "windrammer (Español, Português)" - "<p><b>Special thanks:</b><br>" - "Wiso, dyviacat (2.10 release); " - "CrazyJC (2.8 release director) and MaximumVolty (2.8 release " - "promotion); " - "Remy, Hibiki, court-records.net (sprites); Qubrick (webAO); " - "Rue (website); Draxirch (UI design); " - "Lewdton and Argoneus (tsuserver); " - "Fiercy, Noevain, Cronnicossy, and FanatSors (AO1); " - "server hosts, game masters, case makers, content creators, " - "and the whole AO2 community!" - "<p>The Attorney Online networked visual novel project " - "is copyright (c) 2016-2022 Attorney Online developers. Open-source " - "licenses apply. All other assets are the property of their " - "respective owners." - "<p>Running on Qt version %2 with the BASS audio engine.<br>" - "APNG plugin loaded: %3" - "<p>Built on %4") - .arg(ao_app->get_version_string()) - .arg(QLatin1String(QT_VERSION_STR)) - .arg(hasApng ? tr("Yes") : tr("No")) - .arg(QLatin1String(__DATE__)); + QString msg = tr("<h2>Attorney Online %1</h2>" + "The courtroom drama simulator." + "<p><b>Source code:</b> " + "<a href='https://github.com/AttorneyOnline/AO2-Client'>" + "https://github.com/AttorneyOnline/AO2-Client</a>" + "<p><b>Major development:</b><br>" + "OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, " + "Crystalwarrior, Iamgoofball, in1tiate" + "<p><b>Client development:</b><br>" + "Cents02, windrammer, skyedeving, TrickyLeifa, Salanto, lambdcalculus" + "<p><b>QA testing:</b><br>" + "CaseyCazy, CedricDewitt, Chewable Tablets, CrazyJC, Fantos, " + "Fury McFlurry, Geck, Gin-Gi, Jamania, Minx, Pandae, " + "Robotic Overlord, Shadowlions (aka Shali), Sierra, SomeGuy, " + "Veritas, Wiso" + "<p><b>Translations:</b><br>" + "k-emiko (Русский), Pyraq (Polski), scatterflower (日本語), vintprox " + "(Русский), " + "windrammer (Español, Português)" + "<p><b>Special thanks:</b><br>" + "Wiso, dyviacat (2.10 release); " + "CrazyJC (2.8 release director) and MaximumVolty (2.8 release " + "promotion); " + "Remy, Hibiki, court-records.net (sprites); Qubrick (webAO); " + "Rue (website); Draxirch (UI design); " + "Lewdton and Argoneus (tsuserver); " + "Fiercy, Noevain, Cronnicossy, and FanatSors (AO1); " + "server hosts, game masters, case makers, content creators, " + "and the whole AO2 community!" + "<p>The Attorney Online networked visual novel project " + "is copyright (c) 2016-2022 Attorney Online developers. Open-source " + "licenses apply. All other assets are the property of their " + "respective owners." + "<p>Running on Qt version %2 with the BASS audio engine.<br>" + "APNG plugin loaded: %3" + "<p>Built on %4") + .arg(ao_app->get_version_string()) + .arg(QLatin1String(QT_VERSION_STR)) + .arg(hasApng ? tr("Yes") : tr("No")) + .arg(QLatin1String(__DATE__)); QMessageBox::about(this, tr("About"), msg); } @@ -328,16 +311,23 @@ void Lobby::on_server_list_clicked(QTreeWidgetItem *p_item, int column) server_type f_server; int n_server = p_item->text(column).toInt(); - if (n_server == last_index) { + if (n_server == last_index) + { return; } last_index = n_server; - if (n_server < 0) return; + if (n_server < 0) + { + return; + } QVector<server_type> f_server_list = ao_app->get_server_list(); - if (n_server >= f_server_list.size()) return; + if (n_server >= f_server_list.size()) + { + return; + } f_server = f_server_list.at(n_server); @@ -367,12 +357,16 @@ void Lobby::on_favorite_tree_clicked(QTreeWidgetItem *p_item, int column) server_type f_server; int n_server = p_item->text(column).toInt(); - if (n_server == last_index) { + if (n_server == last_index) + { return; } last_index = n_server; - if (n_server < 0) return; + if (n_server < 0) + { + return; + } ui_add_server_button->setEnabled(true); ui_edit_favorite_button->setEnabled(true); @@ -380,7 +374,10 @@ void Lobby::on_favorite_tree_clicked(QTreeWidgetItem *p_item, int column) QVector<server_type> f_server_list = Options::getInstance().favorites(); - if (n_server >= f_server_list.size()) return; + if (n_server >= f_server_list.size()) + { + return; + } f_server = f_server_list.at(n_server); @@ -398,19 +395,22 @@ void Lobby::on_server_search_edited(QString p_text) { // Iterate through all QTreeWidgetItem items QTreeWidgetItemIterator it(ui_serverlist_tree); - while (*it) { + while (*it) + { (*it)->setHidden(p_text != ""); ++it; } - if (p_text != "") { + if (p_text != "") + { // Search in metadata - QList<QTreeWidgetItem *> clist = ui_serverlist_tree->findItems( - ui_serverlist_search->text(), Qt::MatchContains | Qt::MatchRecursive, - 1); - foreach (QTreeWidgetItem *item, clist) { + QList<QTreeWidgetItem *> clist = ui_serverlist_tree->findItems(ui_serverlist_search->text(), Qt::MatchContains | Qt::MatchRecursive, 1); + foreach (QTreeWidgetItem *item, clist) + { if (item->parent() != nullptr) // So the category shows up too + { item->parent()->setHidden(false); + } item->setHidden(false); } } @@ -420,17 +420,16 @@ void Lobby::on_demo_clicked(QTreeWidgetItem *item, int column) { Q_UNUSED(column) - if (item == nullptr) { + if (item == nullptr) + { return; } - QString l_filepath = (QApplication::applicationDirPath() + "/logs/%1/%2") - .arg(item->data(0, Qt::DisplayRole).toString(), - item->data(1, Qt::DisplayRole).toString()); + QString l_filepath = (QApplication::applicationDirPath() + "/logs/%1/%2").arg(item->data(0, Qt::DisplayRole).toString(), item->data(1, Qt::DisplayRole).toString()); ao_app->demo_server->start_server(); server_type demo_server; demo_server.ip = "127.0.0.1"; - demo_server.port = ao_app->demo_server->port; + demo_server.port = ao_app->demo_server->port(); ao_app->demo_server->set_demo_file(l_filepath); net_manager->connect_to_server(demo_server); } @@ -440,15 +439,14 @@ void Lobby::onReloadThemeRequested() // This is destructive to the active widget data. // Whatever, this is lobby. Nothing here is worth saving. delete centralWidget(); - loadUI(); - COMBO_RELOAD() + + reloadUi(); } void Lobby::onSettingsRequested() { - AOOptionsDialog options(nullptr, ao_app); - connect(&options, &AOOptionsDialog::reloadThemeRequest, this, - &Lobby::onReloadThemeRequested); + AOOptionsDialog options(ao_app); + connect(&options, &AOOptionsDialog::reloadThemeRequest, this, &Lobby::onReloadThemeRequested); options.exec(); } @@ -460,7 +458,8 @@ void Lobby::list_servers() ui_serverlist_search->setText(""); int i = 0; - for (const server_type &i_server : qAsConst(ao_app->get_server_list())) { + for (const server_type &i_server : qAsConst(ao_app->get_server_list())) + { QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_serverlist_tree); treeItem->setData(0, Qt::DisplayRole, i); treeItem->setText(1, i_server.name); @@ -477,7 +476,8 @@ void Lobby::list_favorites() ui_favorites_tree->clear(); int i = 0; - for (const server_type &i_server : Options::getInstance().favorites()) { + for (const server_type &i_server : Options::getInstance().favorites()) + { QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_favorites_tree); treeItem->setData(0, Qt::DisplayRole, i); treeItem->setText(1, i_server.name); @@ -494,8 +494,10 @@ void Lobby::list_demos() ui_demo_tree->clear(); QMultiMap<QString, QString> m_demo_entries = ao_app->load_demo_logs_list(); - for (auto &l_key : m_demo_entries.uniqueKeys()) { - for (const QString &l_entry : m_demo_entries.values(l_key)) { + for (auto &l_key : m_demo_entries.uniqueKeys()) + { + for (const QString &l_entry : m_demo_entries.values(l_key)) + { QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_demo_tree); treeItem->setData(0, Qt::DisplayRole, l_key); treeItem->setData(1, Qt::DisplayRole, l_entry); @@ -509,7 +511,8 @@ void Lobby::list_demos() void Lobby::get_motd() { net_manager->request_document(MSDocumentType::Motd, [this](QString document) { - if (document.isEmpty()) { + if (document.isEmpty()) + { document = tr("Couldn't get the message of the day."); } ui_motd_text->setHtml(document); @@ -518,35 +521,28 @@ void Lobby::get_motd() void Lobby::check_for_updates() { - net_manager->request_document( - MSDocumentType::ClientVersion, [this](QString version) { - const QString current_version = ao_app->get_version_string(); - if (!version.isEmpty() && version != current_version) { - ui_game_version_lbl->setText( - tr("Version: %1 (!)").arg(current_version)); - ui_game_version_lbl->setToolTip( - tr("New version available: %1").arg(version)); - } - }); + net_manager->request_document(MSDocumentType::ClientVersion, [this](QString version) { + const QString current_version = ao_app->get_version_string(); + if (!version.isEmpty() && version != current_version) + { + ui_game_version_lbl->setText(tr("Version: %1 (!)").arg(current_version)); + ui_game_version_lbl->setToolTip(tr("New version available: %1").arg(version)); + } + }); } void Lobby::set_player_count(int players_online, int max_players) { - QString f_string = - tr("Online: %1/%2") - .arg(QString::number(players_online), QString::number(max_players)); + QString f_string = tr("Online: %1/%2").arg(QString::number(players_online), QString::number(max_players)); ui_server_player_count_lbl->setText(f_string); } void Lobby::set_server_description(const QString &server_description) { ui_server_description_text->clear(); - QString result = - server_description.toHtmlEscaped() - .replace("\n", "<br>") - .replace(QRegularExpression("\\b(https?://\\S+\\.\\S+)\\b"), - "<a href='\\1'>\\1</a>"); + QString result = server_description.toHtmlEscaped().replace("\n", "<br>").replace(QRegularExpression("\\b(https?://\\S+\\.\\S+)\\b"), "<a href='\\1'>\\1</a>"); ui_server_description_text->insertHtml(result); } -Lobby::~Lobby() {} +Lobby::~Lobby() +{} diff --git a/src/lobby.h b/src/lobby.h new file mode 100644 index 00000000..4b4d6240 --- /dev/null +++ b/src/lobby.h @@ -0,0 +1,112 @@ +#pragma once + +#include <QLabel> +#include <QLineEdit> +#include <QPushButton> +#include <QTextBrowser> +#include <QTreeWidget> +#include <QTreeWidgetItem> + +#include "file_functions.h" +#include "networkmanager.h" +#include <QMainWindow> + +#ifdef ANDROID +#include <QtAndroidExtras/QtAndroid> +#endif + +class AOApplication; + +class Lobby : public QMainWindow +{ + Q_OBJECT + +public: + Lobby(AOApplication *p_ao_app, NetworkManager *p_net_man = nullptr); + ~Lobby(); + + void set_player_count(int players_online, int max_players); + void set_server_description(const QString &server_description); + void list_servers(); + int get_selected_server(); + int pageSelected(); + +private: + AOApplication *ao_app; + NetworkManager *net_manager; + + const QString DEFAULT_UI = "lobby.ui"; + + void list_favorites(); + void list_demos(); + void get_motd(); + void check_for_updates(); + void reset_selection(); + + int last_index = -1; + + enum TabPage + { + SERVER, + FAVORITES, + DEMOS + }; + + // UI-file Lobby + + // Top Row + QLabel *ui_game_version_lbl; + QPushButton *ui_settings_button; + QPushButton *ui_about_button; + + // Server, Favs and Demo lists + QTabWidget *ui_connections_tabview; + + QTreeWidget *ui_serverlist_tree; + QLineEdit *ui_serverlist_search; + + QTreeWidget *ui_favorites_tree; + QLineEdit *ui_favorites_search; + + QTreeWidget *ui_demo_tree; + QLineEdit *ui_demo_search; + + QPushButton *ui_add_to_favorite_button; + QPushButton *ui_add_server_button; + QPushButton *ui_remove_from_favorites_button; + QPushButton *ui_edit_favorite_button; + QPushButton *ui_direct_connect_button; + QPushButton *ui_refresh_button; + + // Serverinfo / MOTD Horizontal Row + QTextBrowser *ui_motd_text; + + QLabel *ui_server_player_count_lbl; + QTextBrowser *ui_server_description_text; + QPushButton *ui_connect_button; + + // Optional Widget + QTextBrowser *ui_game_changelog_text; + + void loadUI(); + void reloadUi(); + + TabPage current_page = SERVER; + +private Q_SLOTS: + void on_tab_changed(int index); + void on_refresh_released(); + void on_direct_connect_released(); + void on_add_to_fav_released(); + void on_add_server_to_fave_released(); + void on_edit_favorite_released(); + void on_remove_from_fav_released(); + void on_about_clicked(); + void on_server_list_clicked(QTreeWidgetItem *p_item, int column); + void on_list_doubleclicked(QTreeWidgetItem *p_item, int column); + void on_favorite_tree_clicked(QTreeWidgetItem *p_item, int column); + void on_server_search_edited(QString p_text); + void on_demo_clicked(QTreeWidgetItem *item, int column); + void onReloadThemeRequested(); // Oh boy. + void onSettingsRequested(); +}; diff --git a/src/main.cpp b/src/main.cpp index 2c36c53c..d582eb7b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,11 +5,13 @@ #include "datatypes.h" #include "lobby.h" #include "networkmanager.h" + #include <QDebug> +#include <QDirIterator> #include <QLibraryInfo> #include <QPluginLoader> -#include <QTranslator> #include <QResource> +#include <QTranslator> int main(int argc, char *argv[]) { @@ -17,11 +19,12 @@ int main(int argc, char *argv[]) AOApplication main_app(argc, argv); - #ifdef ANDROID - if(QtAndroid::checkPermission("android.permission.READ_EXTERNAL_STORAGE")==QtAndroid::PermissionResult::Denied) { - QtAndroid::requestPermissionsSync({"android.permission.READ_EXTERNAL_STORAGE","android.permission.WRITE_EXTERNAL_STORAGE"}); +#ifdef ANDROID + if (QtAndroid::checkPermission("android.permission.READ_EXTERNAL_STORAGE") == QtAndroid::PermissionResult::Denied) + { + QtAndroid::requestPermissionsSync({"android.permission.READ_EXTERNAL_STORAGE", "android.permission.WRITE_EXTERNAL_STORAGE"}); } - #endif +#endif AOApplication::addLibraryPath(AOApplication::applicationDirPath() + "/lib"); QResource::registerResource(main_app.get_asset("themes/" + Options::getInstance().theme() + ".rcc")); @@ -35,32 +38,37 @@ int main(int argc, char *argv[]) main_app.setFont(new_font); QFontDatabase fontDatabase; - QDirIterator it(get_base_path() + "fonts", - QDirIterator::Subdirectories); + QDirIterator it(get_base_path() + "fonts", QDirIterator::Subdirectories); while (it.hasNext()) + { fontDatabase.addApplicationFont(it.next()); + } QPluginLoader apngPlugin("qapng"); if (!apngPlugin.load()) + { qCritical() << "QApng plugin could not be loaded"; + } QPluginLoader webpPlugin("qwebp"); if (!webpPlugin.load()) + { qCritical() << "QWebp plugin could not be loaded"; + } - QString p_language = - Options::getInstance().language(); - if (p_language == " " || p_language == "") + QString p_language = Options::getInstance().language(); + if (p_language.trimmed().isEmpty()) + { p_language = QLocale::system().name(); + } QTranslator qtTranslator; - qtTranslator.load("qt_" + p_language, - QLibraryInfo::location(QLibraryInfo::TranslationsPath)); + qtTranslator.load("qt_" + p_language, QLibraryInfo::location(QLibraryInfo::TranslationsPath)); main_app.installTranslator(&qtTranslator); QTranslator appTranslator; - qDebug() << ":/resource/translations/ao_" + p_language; - appTranslator.load("ao_" + p_language, ":/resource/translations/"); + qDebug() << ":/data/translations/ao_" + p_language; + appTranslator.load("ao_" + p_language, ":/data/translations/"); main_app.installTranslator(&appTranslator); main_app.construct_lobby(); diff --git a/src/misc_functions.cpp b/src/misc_functions.cpp deleted file mode 100644 index cc144153..00000000 --- a/src/misc_functions.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "misc_functions.h" - -void delay(int p_milliseconds) -{ - QTime dieTime = QTime::currentTime().addMSecs(p_milliseconds); - - while (QTime::currentTime() < dieTime) - QCoreApplication::processEvents(QEventLoop::AllEvents, 100); -} diff --git a/src/networkmanager.cpp b/src/networkmanager.cpp index b7e2810c..a0b95d8c 100644 --- a/src/networkmanager.cpp +++ b/src/networkmanager.cpp @@ -11,16 +11,17 @@ #include <QJsonObject> #include <QNetworkReply> -NetworkManager::NetworkManager(AOApplication *parent) : QObject(parent) +NetworkManager::NetworkManager(AOApplication *parent) + : QObject(parent) { ao_app = parent; http = new QNetworkAccessManager(this); heartbeat_timer = new QTimer(this); - QString master_config = - Options::getInstance().alternativeMasterserver(); - if (!master_config.isEmpty() && QUrl(master_config).scheme().startsWith("http")) { + QString master_config = Options::getInstance().alternativeMasterserver(); + if (!master_config.isEmpty() && QUrl(master_config).scheme().startsWith("http")) + { qInfo() << "using alternate master server" << master_config; ms_baseurl = master_config; } @@ -35,14 +36,14 @@ void NetworkManager::get_server_list() req.setRawHeader("User-Agent", get_user_agent().toUtf8()); QNetworkReply *reply = http->get(req); - connect(reply, &QNetworkReply::finished, - this, std::bind(&NetworkManager::ms_request_finished, this, reply)); + connect(reply, &QNetworkReply::finished, this, std::bind(&NetworkManager::ms_request_finished, this, reply)); } void NetworkManager::ms_request_finished(QNetworkReply *reply) { QJsonDocument json = QJsonDocument::fromJson(reply->readAll()); - if (json.isNull()) { + if (json.isNull()) + { qCritical().noquote() << "Invalid JSON response from" << reply->url(); reply->deleteLater(); return; @@ -52,27 +53,33 @@ void NetworkManager::ms_request_finished(QNetworkReply *reply) QVector<server_type> server_list; const auto jsonEntries = json.array(); - for (const auto &entryRef : jsonEntries) { + for (const auto &entryRef : jsonEntries) + { const auto entry = entryRef.toObject(); server_type server; server.ip = entry["ip"].toString(); server.name = entry["name"].toString(); server.desc = entry["description"].toString(tr("No description provided.")); - if (entry["ws_port"].isDouble()) { + if (entry["ws_port"].isDouble()) + { server.socket_type = WEBSOCKETS; server.port = entry["ws_port"].toInt(); - } else { + } + else + { server.socket_type = TCP; server.port = entry["port"].toInt(); } - if (server.port != 0) { - server_list.append(server); + if (server.port != 0) + { + server_list.append(server); } } ao_app->set_server_list(server_list); - if (ao_app->lobby_constructed) { - ao_app->w_lobby->list_servers(); + if (ao_app->lobby_constructed) + { + ao_app->w_lobby->list_servers(); } reply->deleteLater(); } @@ -84,7 +91,9 @@ void NetworkManager::send_heartbeat() // that time period can be counted and an accurate player count be displayed. // What do I care about your personal information, I really don't want it. if (Options::getInstance().playerCountOptout()) + { return; + } QNetworkRequest req(QUrl(ms_baseurl + "/playing")); req.setRawHeader("User-Agent", get_user_agent().toUtf8()); @@ -92,38 +101,35 @@ void NetworkManager::send_heartbeat() http->post(req, QByteArray()); } -void NetworkManager::request_document(MSDocumentType document_type, - const std::function<void(QString)> &cb) +void NetworkManager::request_document(MSDocumentType document_type, const std::function<void(QString)> &cb) { - const QMap<MSDocumentType, QString> endpoints { - // I have to balance an evil with a good - { MSDocumentType::PrivacyPolicy, "/privacy" }, - { MSDocumentType::Motd, "/motd" }, - { MSDocumentType::ClientVersion, "/version" } - }; + const QMap<MSDocumentType, QString> endpoints{// I have to balance an evil with a good + {MSDocumentType::PrivacyPolicy, "/privacy"}, + {MSDocumentType::Motd, "/motd"}, + {MSDocumentType::ClientVersion, "/version"}}; const QString &endpoint = endpoints[document_type]; QNetworkRequest req(QUrl(ms_baseurl + endpoint)); req.setRawHeader("User-Agent", get_user_agent().toUtf8()); - QString language = - Options::getInstance().language(); + QString language = Options::getInstance().language(); if (language.trimmed().isEmpty()) + { language = QLocale::system().name(); + } req.setRawHeader("Accept-Language", language.toUtf8()); - qDebug().noquote().nospace() - << "Getting " << endpoint << ", Accept-Language: " << language; + qDebug().noquote().nospace() << "Getting " << endpoint << ", Accept-Language: " << language; QNetworkReply *reply = http->get(req); connect(reply, &QNetworkReply::finished, this, [endpoint, cb, reply] { QString content = QString::fromUtf8(reply->readAll()); int http_status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - if (content.isEmpty() || http_status != 200) { - qDebug().noquote().nospace() - << "Failed to get " << endpoint << " (" << reply->errorString() << ") " - << "(http status " << http_status << ")"; + if (content.isEmpty() || http_status != 200) + { + qDebug().noquote().nospace() << "Failed to get " << endpoint << " (" << reply->errorString() << ") " + << "(http status " << http_status << ")"; content = QString(); } cb(content); @@ -135,10 +141,10 @@ void NetworkManager::connect_to_server(server_type p_server) { disconnect_from_server(); - qInfo().nospace().noquote() << "connecting to " << p_server.ip << ":" - << p_server.port; + qInfo().nospace().noquote() << "connecting to " << p_server.ip << ":" << p_server.port; - switch (p_server.socket_type) { + switch (p_server.socket_type) + { default: p_server.socket_type = TCP; [[fallthrough]]; @@ -146,14 +152,9 @@ void NetworkManager::connect_to_server(server_type p_server) qInfo() << "using TCP backend"; server_socket.tcp = new QTcpSocket(this); - connect(server_socket.tcp, &QAbstractSocket::connected, this, [] { - qDebug() << "established connection to server"; - }); - connect(server_socket.tcp, &QIODevice::readyRead, this, [this] { - handle_server_packet(QString::fromUtf8(server_socket.tcp->readAll())); - }); - connect(server_socket.tcp, &QAbstractSocket::disconnected, ao_app, - &AOApplication::server_disconnected); + connect(server_socket.tcp, &QAbstractSocket::connected, this, [] { qDebug() << "established connection to server"; }); + connect(server_socket.tcp, &QIODevice::readyRead, this, [this] { handle_server_packet(QString::fromUtf8(server_socket.tcp->readAll())); }); + connect(server_socket.tcp, &QAbstractSocket::disconnected, ao_app, &AOApplication::server_disconnected); #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) connect(server_socket.tcp, QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::error), this, [this] { #else @@ -168,17 +169,10 @@ void NetworkManager::connect_to_server(server_type p_server) qInfo() << "using WebSockets backend"; server_socket.ws = new QWebSocket(QString(), QWebSocketProtocol::VersionLatest, this); - connect(server_socket.ws, &QWebSocket::connected, this, [] { - qDebug() << "established connection to server"; - }); - connect(server_socket.ws, &QWebSocket::textMessageReceived, this, - &NetworkManager::handle_server_packet); - connect(server_socket.ws, &QWebSocket::disconnected, ao_app, - &AOApplication::server_disconnected); - connect(server_socket.ws, QOverload<QAbstractSocket::SocketError>::of(&QWebSocket::error), - this, [this] { - qCritical() << "WebSockets error:" << server_socket.ws->errorString(); - }); + connect(server_socket.ws, &QWebSocket::connected, this, [] { qDebug() << "established connection to server"; }); + connect(server_socket.ws, &QWebSocket::textMessageReceived, this, &NetworkManager::handle_server_packet); + connect(server_socket.ws, &QWebSocket::disconnected, ao_app, &AOApplication::server_disconnected); + connect(server_socket.ws, QOverload<QAbstractSocket::SocketError>::of(&QWebSocket::error), this, [this] { qCritical() << "WebSockets error:" << server_socket.ws->errorString(); }); QUrl url; url.setScheme("ws"); @@ -196,15 +190,18 @@ void NetworkManager::connect_to_server(server_type p_server) void NetworkManager::join_to_server() { - ship_server_packet(AOPacket("askchaa").to_string()); + ship_server_packet(AOPacket("askchaa").to_string()); } void NetworkManager::disconnect_from_server() { if (!connected) + { return; + } - switch (active_connection_type) { + switch (active_connection_type) + { case TCP: server_socket.tcp->close(); server_socket.tcp->deleteLater(); @@ -218,30 +215,36 @@ void NetworkManager::disconnect_from_server() connected = false; } -void NetworkManager::ship_server_packet(QString p_packet) +void NetworkManager::ship_server_packet(AOPacket p_packet) { - switch (active_connection_type) { + QString message = p_packet.to_string(true); + switch (active_connection_type) + { case TCP: - server_socket.tcp->write(p_packet.toUtf8()); + server_socket.tcp->write(message.toUtf8()); break; + case WEBSOCKETS: - server_socket.ws->sendTextMessage(p_packet); + server_socket.ws->sendTextMessage(message); break; } } -void NetworkManager::handle_server_packet(const QString& p_data) +void NetworkManager::handle_server_packet(const QString &p_data) { QString in_data = p_data; - if (!p_data.endsWith("%")) { + if (!p_data.endsWith("%")) + { partial_packet = true; temp_packet += in_data; return; } - else { - if (partial_packet) { + else + { + if (partial_packet) + { in_data = temp_packet + in_data; temp_packet = ""; partial_packet = false; @@ -253,25 +256,34 @@ void NetworkManager::handle_server_packet(const QString& p_data) const QStringList packet_list = in_data.split("%", Qt::SkipEmptyParts); #endif - for (const QString &packet : packet_list) { + for (const QString &packet : packet_list) + { QStringList f_contents; // Packet should *always* end with # - if (packet.endsWith("#")) { + if (packet.endsWith("#")) + { f_contents = packet.chopped(1).split("#"); } // But, if it somehow doesn't, we should still be able to handle it - else { + else + { f_contents = packet.split("#"); } // Empty packets are suspicious! - if (f_contents.isEmpty()) { + if (f_contents.isEmpty()) + { qWarning() << "WARNING: Empty packet received from server, skipping..."; continue; } // Take the first arg as the command QString command = f_contents.takeFirst(); + for (QString &data : f_contents) + { + data = AOPacket::decode(data); + } + // The rest is contents of the packet - AOPacket *f_packet = new AOPacket(command, f_contents); + AOPacket f_packet(command, f_contents); // Ship it to the server! ao_app->server_packet_received(f_packet); } diff --git a/src/networkmanager.h b/src/networkmanager.h new file mode 100644 index 00000000..984f30f8 --- /dev/null +++ b/src/networkmanager.h @@ -0,0 +1,72 @@ +#pragma once + +#include "aoapplication.h" +#include "aopacket.h" + +#include <QDnsLookup> +#include <QNetworkAccessManager> +#include <QTime> +#include <QTimer> +#include <QtWebSockets/QWebSocket> + +#include <cstring> + +enum MSDocumentType +{ + PrivacyPolicy, + Motd, + ClientVersion +}; + +class NetworkManager : public QObject +{ + Q_OBJECT + +public: + explicit NetworkManager(AOApplication *parent); + ~NetworkManager() = default; + + void connect_to_server(server_type p_server); + void disconnect_from_server(); + +public Q_SLOTS: + void get_server_list(); + void ship_server_packet(AOPacket p_packet); + void join_to_server(); + void handle_server_packet(const QString &p_data); + + void request_document(MSDocumentType document_type, const std::function<void(QString)> &cb); + void send_heartbeat(); + +Q_SIGNALS: + void server_connected(bool state); + +private Q_SLOTS: + void ms_request_finished(QNetworkReply *reply); + +private: + AOApplication *ao_app; + QNetworkAccessManager *http; + + union + { + QWebSocket *ws; + QTcpSocket *tcp; + } server_socket; + connection_type active_connection_type; + bool connected = false; + + QTimer *heartbeat_timer; + + const QString DEFAULT_MS_BASEURL = "http://servers.aceattorneyonline.com"; + QString ms_baseurl = DEFAULT_MS_BASEURL; + + const int heartbeat_interval = 60 * 5 * 1000; + + bool partial_packet = false; + QString temp_packet; + + unsigned int s_decryptor = 5; + + QString get_user_agent() const { return QStringLiteral("AttorneyOnline/%1 (Desktop)").arg(ao_app->get_version_string()); } +}; diff --git a/src/options.cpp b/src/options.cpp index d1822eec..8aec7fd4 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -17,7 +17,8 @@ void Options::migrateCallwords() QFile l_file; l_file.setFileName(get_base_path() + "callwords.ini"); - if (!l_file.open(QIODevice::ReadOnly)) { + if (!l_file.open(QIODevice::ReadOnly)) + { qWarning() << "Unable to migrate callwords : File not open."; return; } @@ -27,7 +28,8 @@ void Options::migrateCallwords() in.setCodec("UTF-8"); #endif - while (!in.atEnd()) { + while (!in.atEnd()) + { QString line = in.readLine(); l_callwords.append(line); } @@ -38,9 +40,8 @@ void Options::migrateCallwords() } Options::Options() - : config(get_base_path() + "config.ini", QSettings::IniFormat, nullptr), - favorite(get_base_path() + "favorite_servers.ini", QSettings::IniFormat, - nullptr) + : config(get_base_path() + "config.ini", QSettings::IniFormat, nullptr) + , favorite(get_base_path() + "favorite_servers.ini", QSettings::IniFormat, nullptr) { #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) config.setIniCodec("UTF-8"); @@ -55,20 +56,25 @@ Options::Options() /*! Migrate old configuration keys/values to a relevant format. */ void Options::migrate() { - if (config.contains("show_custom_shownames")) { + if (config.contains("show_custom_shownames")) + { config.remove("show_custom_shownames"); } - if (QFile::exists(get_base_path() + "callwords.ini")) { + if (QFile::exists(get_base_path() + "callwords.ini")) + { migrateCallwords(); } - if (config.contains("ooc_name")) { - if (username().isEmpty()) { + if (config.contains("ooc_name")) + { + if (username().isEmpty()) + { config.setValue("default_username", config.value("ooc_name")); } config.remove("ooc_name"); } - if (config.contains("casing_enabled")) { + if (config.contains("casing_enabled")) + { config.remove("casing_enabled"); config.remove("casing_defence_enabled"); config.remove("casing_prosecution_enabled"); @@ -85,22 +91,35 @@ QString Options::theme() const return config.value("theme", "default").toString(); } -void Options::setTheme(QString value) { config.setValue("theme", value); } +void Options::setTheme(QString value) +{ + config.setValue("theme", value); +} int Options::themeScalingFactor() const { int value = config.value("theme_scaling_factor", "1").toInt(); - if (value <= 0) { + if (value <= 0) + { value = 1; } return value; } -void Options::setThemeScalingFactor(int value) { config.setValue("theme_scaling_factor", value); } +void Options::setThemeScalingFactor(int value) +{ + config.setValue("theme_scaling_factor", value); +} -int Options::blipRate() const { return config.value("blip_rate", 2).toInt(); } +int Options::blipRate() const +{ + return config.value("blip_rate", 2).toInt(); +} -void Options::setBlipRate(int value) { config.setValue("blip_rate", value); } +void Options::setBlipRate(int value) +{ + config.setValue("blip_rate", value); +} int Options::musicVolume() const { @@ -117,7 +136,10 @@ int Options::sfxVolume() const return config.value("default_sfx", 50).toInt(); } -void Options::setSfxVolume(int value) { config.setValue("default_sfx", value); } +void Options::setSfxVolume(int value) +{ + config.setValue("default_sfx", value); +} int Options::blipVolume() const { @@ -199,9 +221,15 @@ void Options::setLogNewline(bool value) config.setValue("log_newline", value); } -int Options::logMargin() const { return config.value("log_margin", 0).toInt(); } +int Options::logMargin() const +{ + return config.value("log_margin", 0).toInt(); +} -void Options::setLogMargin(int value) { config.setValue("log_margin", value); } +void Options::setLogMargin(int value) +{ + config.setValue("log_margin", value); +} bool Options::logTimestampEnabled() const { @@ -278,7 +306,10 @@ bool Options::blankBlip() const return config.value("blank_blip", false).toBool(); } -void Options::setBlankBlip(bool value) { config.setValue("blank_blip", value); } +void Options::setBlankBlip(bool value) +{ + config.setValue("blank_blip", value); +} bool Options::loopingSfx() const { @@ -345,7 +376,10 @@ bool Options::shakeEnabled() const return config.value("shake", true).toBool(); } -void Options::setShakeEnabled(bool value) { config.setValue("shake", value); } +void Options::setShakeEnabled(bool value) +{ + config.setValue("shake", value); +} bool Options::effectsEnabled() const { @@ -469,7 +503,8 @@ void Options::setLogToDemoFileEnabled(bool value) QString Options::subTheme() const { - if (settingsSubTheme() == "server" && !m_server_subtheme.isEmpty()) { + if (settingsSubTheme() == "server" && !m_server_subtheme.isEmpty()) + { return m_server_subtheme; } return settingsSubTheme(); @@ -485,9 +520,15 @@ void Options::setSettingsSubTheme(QString value) config.setValue("subtheme", value); } -QString Options::serverSubTheme() const { return m_server_subtheme; } +QString Options::serverSubTheme() const +{ + return m_server_subtheme; +} -void Options::setServerSubTheme(QString value) { m_server_subtheme = value; } +void Options::setServerSubTheme(QString value) +{ + m_server_subtheme = value; +} bool Options::animatedThemeEnabled() const { @@ -564,17 +605,21 @@ QString Options::language() const return config.value("language", QLocale::system().name()).toString(); } -void Options::setLanguage(QString value) { config.setValue("language", value); } +void Options::setLanguage(QString value) +{ + config.setValue("language", value); +} QStringList Options::callwords() const { - QStringList l_callwords = - config.value("callwords", QStringList{}).toStringList(); + QStringList l_callwords = config.value("callwords", QStringList{}).toStringList(); // Please someone explain to me how tf I am supposed to create an empty // QStringList using QSetting defaults. if (l_callwords.size() == 1 && l_callwords.at(0).isEmpty()) + { l_callwords.clear(); + } return l_callwords; } @@ -583,7 +628,10 @@ void Options::setCallwords(QStringList value) config.setValue("callwords", value); } -void Options::clearConfig() { config.clear(); } +void Options::clearConfig() +{ + config.clear(); +} QVector<server_type> Options::favorites() { @@ -592,30 +640,29 @@ QVector<server_type> Options::favorites() auto grouplist = favorite.childGroups(); { // remove all negative and non-numbers auto filtered_grouplist = grouplist; - for (const QString &group : qAsConst(grouplist)) { + for (const QString &group : qAsConst(grouplist)) + { bool ok = false; const int l_num = group.toInt(&ok); - if (ok && l_num >= 0) { + if (ok && l_num >= 0) + { continue; } filtered_grouplist.append(group); } - std::sort(filtered_grouplist.begin(), filtered_grouplist.end(), - [](const auto &a, const auto &b) -> bool { - return a.toInt() < b.toInt(); - }); + std::sort(filtered_grouplist.begin(), filtered_grouplist.end(), [](const auto &a, const auto &b) -> bool { return a.toInt() < b.toInt(); }); grouplist = std::move(filtered_grouplist); } - for (const QString &group : qAsConst(grouplist)) { + for (const QString &group : qAsConst(grouplist)) + { server_type f_server; favorite.beginGroup(group); f_server.ip = favorite.value("address", "127.0.0.1").toString(); f_server.port = favorite.value("port", 27016).toInt(); f_server.name = favorite.value("name", "Missing Name").toString(); f_server.desc = favorite.value("desc", "No description").toString(); - f_server.socket_type = - to_connection_type.value(favorite.value("protocol", "tcp").toString()); + f_server.socket_type = to_connection_type.value(favorite.value("protocol", "tcp").toString()); serverlist.append(std::move(f_server)); favorite.endGroup(); } @@ -626,7 +673,8 @@ QVector<server_type> Options::favorites() void Options::setFavorites(QVector<server_type> value) { favorite.clear(); - for (int i = 0; i < value.size(); ++i) { + for (int i = 0; i < value.size(); ++i) + { auto fav_server = value.at(i); favorite.beginGroup(QString::number(i)); favorite.setValue("name", fav_server.name); @@ -634,10 +682,12 @@ void Options::setFavorites(QVector<server_type> value) favorite.setValue("port", fav_server.port); favorite.setValue("desc", fav_server.desc); - if (fav_server.socket_type == TCP) { + if (fav_server.socket_type == TCP) + { favorite.setValue("protocol", "tcp"); } - else { + else + { favorite.setValue("protocol", "ws"); } favorite.endGroup(); @@ -660,10 +710,12 @@ void Options::addFavorite(server_type server) favorite.setValue("address", server.ip); favorite.setValue("port", server.port); favorite.setValue("desc", server.desc); - if (server.socket_type == TCP) { + if (server.socket_type == TCP) + { favorite.setValue("protocol", "tcp"); } - else { + else + { favorite.setValue("protocol", "ws"); } favorite.endGroup(); @@ -677,10 +729,12 @@ void Options::updateFavorite(server_type server, int index) favorite.setValue("address", server.ip); favorite.setValue("port", server.port); favorite.setValue("desc", server.desc); - if (server.socket_type == TCP) { + if (server.socket_type == TCP) + { favorite.setValue("protocol", "tcp"); } - else { + else + { favorite.setValue("protocol", "ws"); } favorite.endGroup(); @@ -689,26 +743,27 @@ void Options::updateFavorite(server_type server, int index) QString Options::getUIAsset(QString f_asset_name) { - QStringList l_paths{":/base/themes/" + Options::getInstance().theme() + "/" + - f_asset_name}; + QStringList l_paths{":/base/themes/" + Options::getInstance().theme() + "/" + f_asset_name}; - if (subTheme() == "server") { - if (serverSubTheme().isEmpty()) { - l_paths.prepend(":/base/themes/" + theme() + "/" + serverSubTheme() + - "/" + f_asset_name); + if (subTheme() == "server") + { + if (serverSubTheme().isEmpty()) + { + l_paths.prepend(":/base/themes/" + theme() + "/" + serverSubTheme() + "/" + f_asset_name); } } - else { - l_paths.prepend(":/base/themes/" + theme() + "/" + subTheme() + "/" + - f_asset_name); + else + { + l_paths.prepend(":/base/themes/" + theme() + "/" + subTheme() + "/" + f_asset_name); } - for (const QString &l_path : qAsConst(l_paths)) { - if (QFile::exists(l_path)) { + for (const QString &l_path : qAsConst(l_paths)) + { + if (QFile::exists(l_path)) + { return l_path; } } - qWarning() << "Unable to locate ui-asset" << f_asset_name << "in theme" - << theme() << "Defaulting to embeeded asset."; - return QString(":/resource/ui/" + f_asset_name); + qWarning() << "Unable to locate ui-asset" << f_asset_name << "in theme" << theme() << "Defaulting to embeeded asset."; + return QString(":/data/ui/" + f_asset_name); } diff --git a/src/options.h b/src/options.h new file mode 100644 index 00000000..07075557 --- /dev/null +++ b/src/options.h @@ -0,0 +1,285 @@ +#pragma once + +#include <QCoreApplication> +#include <QSettings> +#include <datatypes.h> + +class Options +{ +public: + Options(const Options &) = delete; + void operator=(const Options &) = delete; + + static Options &getInstance() + { + static Options instance; + return instance; + } + + /** + * @brief Migrates old configuration files to the most recent format. + */ + void migrate(); + + // Reads the theme from config.ini and loads it into the currenttheme + // variable + QString theme() const; + void setTheme(QString value); + + int themeScalingFactor() const; + void setThemeScalingFactor(int value); + + // Returns the blip rate from config.ini (once per X symbols) + int blipRate() const; + void setBlipRate(int value); + + // Returns true if blank blips is enabled in config.ini and false otherwise + bool blankBlip() const; + void setBlankBlip(bool value); + + // Returns true if looping sound effects are enabled in the config.ini + bool loopingSfx() const; + void setLoopingSfx(bool value); + + // Returns true if stop music on objection is enabled in the config.ini + bool objectionStopMusic() const; + void setObjectionStopMusic(bool value); + + // Returns true if streaming is enabled in the config.ini + bool streamingEnabled() const; + void setStreamingEnabled(bool value); + + // Returns the value of defaultmusic in config.ini + int musicVolume() const; + void setMusicVolume(int value); + + // Returns the value of defaultsfx in config.ini + int sfxVolume() const; + void setSfxVolume(int value); + + // Returns the value of defaultblip in config.ini + int blipVolume() const; + void setBlipVolume(int value); + + // Returns the value of suppressaudio in config.ini + int defaultSuppressAudio() const; + void setDefaultSupressedAudio(int value); + + // Returns the value if objections interrupt and skip the message queue + // from the config.ini. + bool objectionSkipQueueEnabled() const; + void setObjectionSkipQueueEnabled(bool value); + + // returns if log will show messages as-received, while viewport will parse + // according to the queue (Text Stay Time) from the config.ini + bool desynchronisedLogsEnabled() const; + void setDesynchronisedLogsEnabled(bool value); + + // Returns the value of whether Discord should be enabled on startup + // from the config.ini. + bool discordEnabled() const; + void setDiscordEnabled(bool value); + + // Returns the value of whether shaking should be enabled. + // from the config.ini. + bool shakeEnabled() const; + void setShakeEnabled(bool value); + + // Returns the value of whether effects should be Enabled. + // from the config.ini. + bool effectsEnabled() const; + void setEffectsEnabled(bool value); + + // Returns the value of whether frame-specific effects defined in char.ini + // should be sent/received over the network. from the config.ini. + bool networkedFrameSfxEnabled() const; + void setNetworkedFrameSfxEnabled(bool value); + + // Returns the value of whether colored ic log should be a thing. + // from the config.ini. + bool colorLogEnabled() const; + void setColorLogEnabled(bool value); + + // Returns the value of whether sticky sounds should be a thing. + // from the config.ini. + bool clearSoundsDropdownOnPlayEnabled() const; + void setClearSoundsDropdownOnPlayEnabled(bool value); + + // Returns the value of whether sticky effects should be a thing. + // from the config.ini. + bool clearEffectsDropdownOnPlayEnabled() const; + void setClearEffectsDropdownOnPlayEnabled(bool value); + + // Returns the value of whether sticky preanims should be a thing. + // from the config.ini. + bool clearPreOnPlayEnabled() const; + void setClearPreOnPlayEnabled(bool value); + + // Returns the value of whether custom chatboxes should be a thing. + // from the config.ini. + // I am increasingly maddened by the lack of dynamic auto-generation system + // for settings. + bool customChatboxEnabled() const; + void setCustomChatboxEnabled(bool value); + + // Returns the value of characer sticker (avatar) setting + bool characterStickerEnabled() const; + void setCharacterStickerEnabled(bool value); + + // Returns the value of whether continuous playback should be used + // from the config.ini. + bool continuousPlaybackEnabled() const; + void setContinuousPlaybackEnabled(bool value); + + // Returns the value of whether stopping music by double clicking category + // should be used from the config.ini. + bool stopMusicOnCategoryEnabled() const; + void setStopMusicOnCategoryEnabled(bool value); + + // Returns the value of the maximum amount of lines the IC chatlog + // may contain, from config.ini. + int maxLogSize() const; + void setMaxLogSize(int value); + + // Current wait time between messages for the queue system + int textStayTime() const; + void setTextStayTime(int value); + + // Returns the letter display speed during text crawl in in-character messages + int textCrawlSpeed() const; + void setTextCrawlSpeed(int value); + + // Returns Minimum amount of time (in miliseconds) that must pass before the + // next Enter key press will send your IC message. (new behaviour) + int chatRateLimit() const; + void setChatRateLimit(int value); + + // Returns whether the log should go upwards (new behaviour) + // or downwards (vanilla behaviour). + bool logDirectionDownwards() const; + void setLogDirectionDownwards(bool value); + + // Returns whether the log should separate name from text via newline or : + bool logNewline() const; + void setLogNewline(bool value); + + // Get spacing between IC log entries. + int logMargin() const; + void setLogMargin(int value); + + // Returns whether the log should have a timestamp. + bool logTimestampEnabled() const; + void setLogTimestampEnabled(bool value); + + // Returns the format string for the log timestamp + QString logTimestampFormat() const; + void setLogTimestampFormat(QString value); + + // Returns whether to log IC actions. + bool logIcActions() const; + void setLogIcActions(bool value); + + // Returns the username the user may have set in config.ini. + QString username() const; + void setUsername(QString value); + + // Returns the audio device used for the client. + QString audioOutputDevice() const; + void setAudioOutputDevice(QString value); + + // Returns whether the user would like to have custom shownames on by default. + bool customShownameEnabled() const; + void setCustomShownameEnabled(bool value); + + // Returns the showname the user may have set in config.ini. + QString shownameOnJoin() const; + void setShownameOnJoin(QString value); + + // Get if text file logging is Enabled + bool logToTextFileEnabled() const; + void setLogToTextFileEnabled(bool value); + + // Get if demo logging is Enabled + bool logToDemoFileEnabled() const; + void setLogToDemoFileEnabled(bool value); + + // Get the subtheme from settings + QString subTheme() const; + QString settingsSubTheme() const; + void setSettingsSubTheme(QString value); + + // Returns the server- + QString serverSubTheme() const; + void setServerSubTheme(QString value); + + // Get if the theme is animated + bool animatedThemeEnabled() const; + void setAnimatedThemeEnabled(bool value); + + // Get the default scaling method + QString defaultScalingMode() const; + void setDefaultScalingMode(QString value); + + // Get a list of custom mount paths + QStringList mountPaths() const; + void setMountPaths(QStringList value); + + // Get whether to opt out of player count metrics sent to the master server + bool playerCountOptout() const; + void setPlayerCountOptout(bool value); + + // Get if sfx can be sent to play on idle + bool playSelectedSFXOnIdle() const; + void setPlaySelectedSFXOnIdle(bool value); + + // Whether opening evidence requires a single or double click + bool evidenceDoubleClickEdit() const; + void setEvidenceDoubleClickEdit(bool value); + + // Supplies an alternative masterserver URL + QString alternativeMasterserver() const; + void setAlternativeMasterserver(QString value); + + // Language the client loads on start. + QString language() const; + void setLanguage(QString value); + + // Callwords notify the user when the word/words are used in a game message. + QStringList callwords() const; + void setCallwords(QStringList value); + + // Clears the configuration file. Essentially restoring it to default. + void clearConfig(); + + // Loads the favorite servers + QVector<server_type> favorites(); + void setFavorites(QVector<server_type> value); + + // Interactions with favorite servers + void removeFavorite(int index); + void addFavorite(server_type server); + void updateFavorite(server_type server, int index); + + // Theming Nonesense! + QString getUIAsset(QString f_asset_name); + +private: + /** + * @brief QSettings object for config.ini + */ + QSettings config; + + /** + * @brief QSettings object for favorite_servers.ini + */ + QSettings favorite; + + void migrateCallwords(); + + /** + * @brief Constructor for options class. + */ + Options(); + + QString m_server_subtheme; +}; diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index 9bd4d8f6..011a4623 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -9,37 +9,45 @@ void AOApplication::append_to_demofile(QString packet_string) { - if (Options::getInstance().logToDemoFileEnabled() && !log_filename.isEmpty()) + if (Options::getInstance().logToDemoFileEnabled() && !log_filename.isEmpty()) + { + QString path = log_filename.left(log_filename.size()).replace(".log", ".demo"); + if (!demo_timer.isValid()) { - QString path = log_filename.left(log_filename.size()).replace(".log", ".demo"); - if (!demo_timer.isValid()) - demo_timer.start(); - else - append_to_file("wait#"+ QString::number(demo_timer.restart()) + "#%", path, true); - append_to_file(packet_string, path, true); + demo_timer.start(); + } + else + { + append_to_file("wait#" + QString::number(demo_timer.restart()) + "#%", path, true); } + append_to_file(packet_string, path, true); + } } -void AOApplication::server_packet_received(AOPacket *p_packet) +void AOApplication::server_packet_received(AOPacket p_packet) { - QStringList f_contents_encoded = p_packet->get_contents(); - QString f_packet_encoded = p_packet->to_string(); - p_packet->net_decode(); + QStringList f_contents_encoded = p_packet.get_content(); + QString f_packet_encoded = p_packet.to_string(); - QString header = p_packet->get_header(); - QStringList f_contents = p_packet->get_contents(); - QString f_packet = p_packet->to_string(); + QString header = p_packet.get_header(); + QStringList f_contents = p_packet.get_content(); + QString f_packet = p_packet.to_string(); bool log_to_demo = true; #ifdef DEBUG_NETWORK if (header != "checkconnection") + { qDebug() << "R:" << f_packet; + } #endif - if (header == "decryptor") { + if (header == "decryptor") + { if (f_contents.size() == 0) - goto end; + { + return; + } // default(legacy) values yellow_text_supported = false; @@ -61,13 +69,16 @@ void AOApplication::server_packet_received(AOPacket *p_packet) f_hdid = get_hdid(); QStringList f_contents = {f_hdid}; - AOPacket *hi_packet = new AOPacket("HI", f_contents); + AOPacket hi_packet("HI", f_contents); send_server_packet(hi_packet); log_to_demo = false; } - else if (header == "ID") { + else if (header == "ID") + { if (f_contents.size() < 2) - goto end; + { + return; + } client_id = f_contents.at(0).toInt(); server_software = f_contents.at(1); @@ -75,21 +86,26 @@ void AOApplication::server_packet_received(AOPacket *p_packet) net_manager->server_connected(true); QStringList f_contents = {"AO2", get_version_string()}; - send_server_packet(new AOPacket("ID", f_contents)); + send_server_packet(AOPacket("ID", f_contents)); } - else if (header == "CT") { - if (!courtroom_constructed || f_contents.size() < 2) { - goto end; -} + else if (header == "CT") + { + if (!courtroom_constructed || f_contents.size() < 2) + { + return; + } if (f_contents.size() == 3) - w_courtroom->append_server_chatmessage( - f_contents.at(0), f_contents.at(1), f_contents.at(2)); + { + w_courtroom->append_server_chatmessage(f_contents.at(0), f_contents.at(1), f_contents.at(2)); + } else - w_courtroom->append_server_chatmessage(f_contents.at(0), - f_contents.at(1), "0"); + { + w_courtroom->append_server_chatmessage(f_contents.at(0), f_contents.at(1), "0"); + } } - else if (header == "FL") { + else if (header == "FL") + { yellow_text_supported = false; prezoom_supported = false; flipping_supported = false; @@ -106,63 +122,102 @@ void AOApplication::server_packet_received(AOPacket *p_packet) expanded_desk_mods_supported = false; auth_packet_supported = false; if (f_packet.contains("yellowtext", Qt::CaseInsensitive)) + { yellow_text_supported = true; + } if (f_packet.contains("prezoom", Qt::CaseInsensitive)) + { prezoom_supported = true; + } if (f_packet.contains("flipping", Qt::CaseInsensitive)) + { flipping_supported = true; + } if (f_packet.contains("customobjections", Qt::CaseInsensitive)) + { custom_objection_supported = true; + } if (f_packet.contains("deskmod", Qt::CaseInsensitive)) + { desk_mod_supported = true; + } if (f_packet.contains("evidence", Qt::CaseInsensitive)) + { evidence_supported = true; + } if (f_packet.contains("cccc_ic_support", Qt::CaseInsensitive)) + { cccc_ic_supported = true; + } if (f_packet.contains("arup", Qt::CaseInsensitive)) + { arup_supported = true; + } if (f_packet.contains("casing_alerts", Qt::CaseInsensitive)) + { casing_alerts_supported = true; + } if (f_packet.contains("modcall_reason", Qt::CaseInsensitive)) + { modcall_reason_supported = true; + } if (f_packet.contains("looping_sfx", Qt::CaseInsensitive)) + { looping_sfx_supported = true; + } if (f_packet.contains("additive", Qt::CaseInsensitive)) + { additive_text_supported = true; + } if (f_packet.contains("effects", Qt::CaseInsensitive)) + { effects_supported = true; + } if (f_packet.contains("y_offset", Qt::CaseInsensitive)) - y_offset_supported = true; + { + y_offset_supported = true; + } if (f_packet.contains("expanded_desk_mods", Qt::CaseInsensitive)) + { expanded_desk_mods_supported = true; + } if (f_packet.contains("auth_packet", Qt::CaseInsensitive)) + { auth_packet_supported = true; + } log_to_demo = false; } - else if (header == "PN") { + else if (header == "PN") + { if (!lobby_constructed || f_contents.size() < 2) - goto end; + { + return; + } - w_lobby->set_player_count(f_contents.at(0).toInt(), - f_contents.at(1).toInt()); + w_lobby->set_player_count(f_contents.at(0).toInt(), f_contents.at(1).toInt()); - if (f_contents.size() >= 3) { - w_lobby->set_server_description(f_contents.at(2)); + if (f_contents.size() >= 3) + { + w_lobby->set_server_description(f_contents.at(2)); } log_to_demo = false; } - else if (header == "SI") { - if (!lobby_constructed || f_contents.size() != 3) { - goto end; -} + else if (header == "SI") + { + if (!lobby_constructed || f_contents.size() != 3) + { + return; + } char_list_size = f_contents.at(0).toInt(); evidence_list_size = f_contents.at(1).toInt(); music_list_size = f_contents.at(2).toInt(); if (char_list_size < 0 || evidence_list_size < 0 || music_list_size < 0) - goto end; + { + return; + } loaded_chars = 0; loaded_evidence = 0; @@ -175,91 +230,107 @@ void AOApplication::server_packet_received(AOPacket *p_packet) courtroom_loaded = false; int selected_server = w_lobby->get_selected_server(); - QString server_address = "", server_name = ""; - switch (w_lobby->pageSelected()) { + QString server_address; + QString server_name; + switch (w_lobby->pageSelected()) + { case 0: - if (selected_server >= 0 && selected_server < server_list.size()) { - auto info = server_list.at(selected_server); - server_name = info.name; - server_address = - QString("%1:%2").arg(info.ip, QString::number(info.port)); - window_title = server_name; - } - break; + if (selected_server >= 0 && selected_server < server_list.size()) + { + auto info = server_list.at(selected_server); + server_name = info.name; + server_address = QString("%1:%2").arg(info.ip, QString::number(info.port)); + window_title = server_name; + } + break; case 1: { - QVector<server_type> favorite_list = Options::getInstance().favorites(); - if (selected_server >= 0 && selected_server < favorite_list.size()) { - auto info = favorite_list.at(selected_server); - server_name = info.name; - server_address = - QString("%1:%2").arg(info.ip, QString::number(info.port)); - window_title = server_name; - } + QVector<server_type> favorite_list = Options::getInstance().favorites(); + if (selected_server >= 0 && selected_server < favorite_list.size()) + { + auto info = favorite_list.at(selected_server); + server_name = info.name; + server_address = QString("%1:%2").arg(info.ip, QString::number(info.port)); + window_title = server_name; + } } - break; + break; case 2: - window_title = "Local Demo Recording"; - break; + window_title = "Local Demo Recording"; + break; default: - break; + break; } if (courtroom_constructed) + { w_courtroom->set_window_title(window_title); + } - AOPacket *f_packet; - - f_packet = new AOPacket("RC"); - send_server_packet(f_packet); + send_server_packet(AOPacket("RC")); // Remove any characters not accepted in folder names for the server_name // here - if (Options::getInstance().logToDemoFileEnabled() && server_name != "Demo playback") { - this->log_filename = QDateTime::currentDateTime().toUTC().toString( - "'logs/" + server_name.remove(QRegularExpression("[\\\\/:*?\"<>|\']")) + - "/'yyyy-MM-dd hh-mm-ss t'.log'"); - this->write_to_file("Joined server " + server_name + " hosted on address " + - server_address + " on " + - QDateTime::currentDateTime().toUTC().toString(), - log_filename, true); + if (Options::getInstance().logToDemoFileEnabled() && server_name != "Demo playback") + { + this->log_filename = QDateTime::currentDateTime().toUTC().toString("'logs/" + server_name.remove(QRegularExpression("[\\\\/:*?\"<>|\']")) + "/'yyyy-MM-dd hh-mm-ss t'.log'"); + this->write_to_file("Joined server " + server_name + " hosted on address " + server_address + " on " + QDateTime::currentDateTime().toUTC().toString(), log_filename, true); } else + { this->log_filename = ""; + } QCryptographicHash hash(QCryptographicHash::Algorithm::Sha256); hash.addData(server_address.toUtf8()); if (Options::getInstance().discordEnabled()) - discord->state_server(server_name.toStdString(), - hash.result().toBase64().toStdString()); + { + discord->state_server(server_name.toStdString(), hash.result().toBase64().toStdString()); + } log_to_demo = false; } - else if (header == "CharsCheck") { + else if (header == "CharsCheck") + { if (!courtroom_constructed) - goto end; + { + return; + } - for (int n_char = 0; n_char < f_contents.size(); ++n_char) { + for (int n_char = 0; n_char < f_contents.size(); ++n_char) + { if (f_contents.at(n_char) == "-1") + { w_courtroom->set_taken(n_char, true); + } else + { w_courtroom->set_taken(n_char, false); + } } log_to_demo = false; } - else if (header == "SC") { + else if (header == "SC") + { if (!courtroom_constructed) - goto end; + { + return; + } w_courtroom->clear_chars(); - for (int n_element = 0; n_element < f_contents.size(); ++n_element) { + for (int n_element = 0; n_element < f_contents.size(); ++n_element) + { QStringList sub_elements = f_contents.at(n_element).split("&"); - - AOPacket::unescape(sub_elements); + for (QString &sub_element : sub_elements) + { + sub_element = AOPacket::decode(sub_element); + } char_type f_char; f_char.name = sub_elements.at(0); if (sub_elements.size() >= 2) + { f_char.description = sub_elements.at(1); + } // temporary. the CharsCheck packet sets this properly f_char.taken = false; @@ -268,55 +339,67 @@ void AOApplication::server_packet_received(AOPacket *p_packet) } if (!courtroom_loaded) - send_server_packet(new AOPacket("RM")); + { + send_server_packet(AOPacket("RM")); + } else + { w_courtroom->character_loading_finished(); + } } - else if (header == "SM") { + else if (header == "SM") + { if (!courtroom_constructed || courtroom_loaded) - goto end; + { + return; + } bool musics_time = false; int areas = 0; - for (int n_element = 0; n_element < f_contents.size(); ++n_element) { + for (int n_element = 0; n_element < f_contents.size(); ++n_element) + { ++loaded_music; - if (musics_time) { + if (musics_time) + { w_courtroom->append_music(f_contents.at(n_element)); } - else { - if (f_contents.at(n_element).endsWith(".wav") || - f_contents.at(n_element).endsWith(".mp3") || - f_contents.at(n_element).endsWith(".mp4") || - f_contents.at(n_element).endsWith(".ogg") || - f_contents.at(n_element).endsWith(".opus")) { + else + { + if (f_contents.at(n_element).endsWith(".wav") || f_contents.at(n_element).endsWith(".mp3") || f_contents.at(n_element).endsWith(".mp4") || f_contents.at(n_element).endsWith(".ogg") || f_contents.at(n_element).endsWith(".opus")) + { musics_time = true; w_courtroom->fix_last_area(); w_courtroom->append_music(f_contents.at(n_element)); areas--; } - else { + else + { w_courtroom->append_area(f_contents.at(n_element)); areas++; } } } - for (int area_n = 0; area_n < areas; area_n++) { + for (int area_n = 0; area_n < areas; area_n++) + { w_courtroom->arup_append(0, "Unknown", "Unknown", "Unknown"); } - send_server_packet(new AOPacket("RD")); + send_server_packet(AOPacket("RD")); log_to_demo = false; } else if (header == "FM") // Fetch music ONLY { if (!courtroom_constructed) - goto end; + { + return; + } w_courtroom->clear_music(); - for (int n_element = 0; n_element < f_contents.size(); ++n_element) { + for (int n_element = 0; n_element < f_contents.size(); ++n_element) + { w_courtroom->append_music(f_contents.at(n_element)); } @@ -326,12 +409,15 @@ void AOApplication::server_packet_received(AOPacket *p_packet) else if (header == "FA") // Fetch areas ONLY { if (!courtroom_constructed) - goto end; + { + return; + } w_courtroom->clear_areas(); w_courtroom->arup_clear(); - for (int n_element = 0; n_element < f_contents.size(); ++n_element) { + for (int n_element = 0; n_element < f_contents.size(); ++n_element) + { w_courtroom->append_area(f_contents.at(n_element)); w_courtroom->arup_append(0, "Unknown", "Unknown", "Unknown"); } @@ -339,9 +425,12 @@ void AOApplication::server_packet_received(AOPacket *p_packet) w_courtroom->list_areas(); log_to_demo = false; } - else if (header == "DONE") { + else if (header == "DONE") + { if (!courtroom_constructed) - goto end; + { + return; + } w_courtroom->character_loading_finished(); w_courtroom->done_received(); @@ -351,21 +440,30 @@ void AOApplication::server_packet_received(AOPacket *p_packet) destruct_lobby(); log_to_demo = false; } - else if (header == "BN") { + else if (header == "BN") + { if (!courtroom_constructed || f_contents.isEmpty()) - goto end; + { + return; + } - if (f_contents.size() >= 2) { + if (f_contents.size() >= 2) + { // We have a pos included in the background packet! - if (!f_contents.at(1).isEmpty()) - //Not touching it when its empty. - w_courtroom->set_side(f_contents.at(1)); + if (!f_contents.at(1).isEmpty()) + { + // Not touching it when its empty. + w_courtroom->set_side(f_contents.at(1)); + } } w_courtroom->set_background(f_contents.at(0), f_contents.size() >= 2); } - else if (header == "SP") { + else if (header == "SP") + { if (!courtroom_constructed || f_contents.isEmpty()) - goto end; + { + return; + } // We were sent a "set position" packet w_courtroom->set_side(f_contents.at(0)); @@ -373,61 +471,83 @@ void AOApplication::server_packet_received(AOPacket *p_packet) else if (header == "SD") // Send pos dropdown { if (!courtroom_constructed || f_contents.isEmpty()) - goto end; + { + return; + } w_courtroom->set_pos_dropdown(f_contents.at(0).split("*")); } // server accepting char request(CC) packet - else if (header == "PV") { + else if (header == "PV") + { if (!courtroom_constructed || f_contents.size() < 3) - goto end; + { + return; + } // For some reason, args 0 and 1 are not used (from tsu3 they're client ID and a string "CID") w_courtroom->enter_courtroom(); w_courtroom->set_courtroom_size(); w_courtroom->update_character(f_contents.at(2).toInt()); } - else if (header == "MS") { + else if (header == "MS") + { if (courtroom_constructed && courtroom_loaded) { - w_courtroom->chatmessage_enqueue(p_packet->get_contents()); + w_courtroom->chatmessage_enqueue(p_packet.get_content()); } } - else if (header == "MC") { + else if (header == "MC") + { if (courtroom_constructed && courtroom_loaded) { - w_courtroom->handle_song(&p_packet->get_contents()); + w_courtroom->handle_song(&p_packet.get_content()); } } - else if (header == "RT") { + else if (header == "RT") + { if (f_contents.isEmpty()) - goto end; - if (courtroom_constructed) { + { + return; + } + if (courtroom_constructed) + { if (f_contents.size() == 1) + { w_courtroom->handle_wtce(f_contents.at(0), 0); + } else if (f_contents.size() >= 2) + { w_courtroom->handle_wtce(f_contents.at(0), f_contents.at(1).toInt()); + } } } - else if (header == "HP") { + else if (header == "HP") + { if (courtroom_constructed && f_contents.size() >= 2) { - w_courtroom->set_hp_bar(f_contents.at(0).toInt(), - f_contents.at(1).toInt()); + w_courtroom->set_hp_bar(f_contents.at(0).toInt(), f_contents.at(1).toInt()); } } - else if (header == "LE") { - if (courtroom_constructed) { + else if (header == "LE") + { + if (courtroom_constructed) + { QVector<evi_type> f_evi_list; - for (QString f_string : f_contents_encoded) { + for (QString f_string : f_contents_encoded) + { QStringList sub_contents = f_string.split("&"); - if (sub_contents.size() < 3) + { continue; + } // decoding has to be done here instead of on reception // because this packet uses & as a delimiter for some reason - AOPacket::unescape(sub_contents); + for (QString &data : sub_contents) + { + data = AOPacket::decode(data); + } evi_type f_evi; f_evi.name = sub_contents.at(0); @@ -440,72 +560,93 @@ void AOApplication::server_packet_received(AOPacket *p_packet) w_courtroom->set_evidence_list(f_evi_list); } } - else if (header == "ARUP") { - if (courtroom_constructed && !f_contents.isEmpty()) { + else if (header == "ARUP") + { + if (courtroom_constructed && !f_contents.isEmpty()) + { int arup_type = f_contents.at(0).toInt(); - for (int n_element = 1; n_element < f_contents.size(); n_element++) { - w_courtroom->arup_modify(arup_type, n_element - 1, - f_contents.at(n_element)); + for (int n_element = 1; n_element < f_contents.size(); n_element++) + { + w_courtroom->arup_modify(arup_type, n_element - 1, f_contents.at(n_element)); } w_courtroom->list_areas(); } log_to_demo = false; } - else if (header == "IL") { + else if (header == "IL") + { if (courtroom_constructed && !f_contents.isEmpty()) + { w_courtroom->set_ip_list(f_contents.at(0)); + } log_to_demo = false; } - else if (header == "MU") { + else if (header == "MU") + { if (courtroom_constructed && !f_contents.isEmpty()) + { w_courtroom->set_mute(true, f_contents.at(0).toInt()); + } log_to_demo = false; } - else if (header == "UM") { - if (courtroom_constructed && !f_contents.isEmpty()) { + else if (header == "UM") + { + if (courtroom_constructed && !f_contents.isEmpty()) + { w_courtroom->set_mute(false, f_contents.at(0).toInt()); - log_to_demo = false; -} + log_to_demo = false; + } } - else if (header == "BB") { - if (courtroom_constructed && !f_contents.isEmpty()) { + else if (header == "BB") + { + if (courtroom_constructed && !f_contents.isEmpty()) + { call_notice(f_contents.at(0)); } log_to_demo = false; } - else if (header == "KK") { - if (courtroom_constructed && !f_contents.isEmpty()) { - call_notice(tr("You have been kicked from the server.\nReason: %1") - .arg(f_contents.at(0))); + else if (header == "KK") + { + if (courtroom_constructed && !f_contents.isEmpty()) + { + call_notice(tr("You have been kicked from the server.\nReason: %1").arg(f_contents.at(0))); construct_lobby(); destruct_courtroom(); } log_to_demo = false; } - else if (header == "KB") { - if (courtroom_constructed && !f_contents.isEmpty()) { - call_notice(tr("You have been banned from the server.\nReason: %1") - .arg(f_contents.at(0))); + else if (header == "KB") + { + if (courtroom_constructed && !f_contents.isEmpty()) + { + call_notice(tr("You have been banned from the server.\nReason: %1").arg(f_contents.at(0))); construct_lobby(); destruct_courtroom(); } log_to_demo = false; } - else if (header == "BD") { - if (f_contents.isEmpty()) { - goto end; + else if (header == "BD") + { + if (f_contents.isEmpty()) + { + return; } - call_notice( - tr("You are banned on this server.\nReason: %1").arg(f_contents.at(0))); + call_notice(tr("You are banned on this server.\nReason: %1").arg(f_contents.at(0))); log_to_demo = false; } - else if (header == "ZZ") { + else if (header == "ZZ") + { if (courtroom_constructed && !f_contents.isEmpty()) + { w_courtroom->mod_called(f_contents.at(0)); + } } - else if (header == "TI") { // Timer packet + else if (header == "TI") + { // Timer packet if (!courtroom_constructed || f_contents.size() < 2) - goto end; + { + return; + } // Timer ID is reserved as argument 0 int id = f_contents.at(0).toInt(); @@ -519,7 +660,9 @@ void AOApplication::server_packet_received(AOPacket *p_packet) if (type == 0 || type == 1) { if (f_contents.size() < 3) - goto end; + { + return; + } // The time as displayed on the clock, in milliseconds. // If the number received is negative, stop the timer. @@ -543,99 +686,118 @@ void AOApplication::server_packet_received(AOPacket *p_packet) } } else if (type == 2) + { w_courtroom->set_clock_visibility(id, true); + } else if (type == 3) + { w_courtroom->set_clock_visibility(id, false); + } } - else if (header == "CHECK") { + else if (header == "CHECK") + { if (!courtroom_constructed) - goto end; + { + return; + } qint64 ping_time = w_courtroom->pong(); qDebug() << "ping:" << ping_time; if (ping_time != -1) + { latency = ping_time; + } log_to_demo = false; } // Subtheme packet - else if (header == "ST") { + else if (header == "ST") + { if (!courtroom_constructed || f_contents.isEmpty()) - goto end; + { + return; + } // Subtheme reserved as argument 0 subtheme = f_contents.at(0); // Check if we have subthemes set to "server" if (Options::getInstance().settingsSubTheme().toLower() != "server") + { // We don't. Simply acknowledge the subtheme sent by the server, but don't do anything else. return; + } // Reload theme request - if (f_contents.size() > 1 && f_contents.at(1) == "1") { + if (f_contents.size() > 1 && f_contents.at(1) == "1") + { Options::getInstance().setServerSubTheme(subtheme); w_courtroom->on_reload_theme_clicked(); } } // Auth packet - else if (header == "AUTH") { - if (!courtroom_constructed || !auth_packet_supported || f_contents.isEmpty()) { - goto end; -} + else if (header == "AUTH") + { + if (!courtroom_constructed || !auth_packet_supported || f_contents.isEmpty()) + { + return; + } bool ok; int authenticated = f_contents.at(0).toInt(&ok); - if (!ok) { + if (!ok) + { qWarning() << "Malformed AUTH packet! Contents:" << f_contents.at(0); } w_courtroom->on_authentication_state_received(authenticated); log_to_demo = false; } - else if (header == "JD") { - if (!courtroom_constructed || f_contents.isEmpty()) { - goto end; + else if (header == "JD") + { + if (!courtroom_constructed || f_contents.isEmpty()) + { + return; } bool ok; Courtroom::JudgeState state = static_cast<Courtroom::JudgeState>(f_contents.at(0).toInt(&ok)); - if (!ok) { - goto end; // ignore malformed packet + if (!ok) + { + return; // ignore malformed packet } w_courtroom->set_judge_state(state); - if (w_courtroom->get_judge_state() != Courtroom::POS_DEPENDENT) { // If we receive JD -1, it means the server asks us to fall back to client-side judge buttons behavior + if (w_courtroom->get_judge_state() != Courtroom::POS_DEPENDENT) + { // If we receive JD -1, it means the server asks us to fall back to client-side judge buttons behavior w_courtroom->show_judge_controls(w_courtroom->get_judge_state() == Courtroom::SHOW_CONTROLS); } - else { + else + { w_courtroom->set_judge_buttons(); // client-side judge behavior } } - //AssetURL Packet - else if (header == "ASS") { - if (f_contents.size() > 1 || f_contents.isEmpty()) { // This can never be more than one link. - goto end; + // AssetURL Packet + else if (header == "ASS") + { + if (f_contents.size() > 1 || f_contents.isEmpty()) + { // This can never be more than one link. + return; } QUrl t_asset_url = QUrl::fromPercentEncoding(f_contents.at(0).toUtf8()); if (t_asset_url.isValid()) - asset_url = t_asset_url.toString(); + { + asset_url = t_asset_url.toString(); + } } - if (log_to_demo) { + if (log_to_demo) + { append_to_demofile(f_packet_encoded); } - -end: - - delete p_packet; } -void AOApplication::send_server_packet(AOPacket *p_packet) +void AOApplication::send_server_packet(AOPacket p_packet) { - // ***NEVER*** send an unencoded packet. - p_packet->net_encode(); - - QString f_packet = p_packet->to_string(); + QString f_packet = p_packet.to_string(); #ifdef DEBUG_NETWORK - qDebug() << "S:" << f_packet; + qDebug() << "S:" << p_packet.to_string(); #endif - net_manager->ship_server_packet(f_packet); - - delete p_packet; + net_manager->ship_server_packet(p_packet); } diff --git a/src/path_functions.cpp b/src/path_functions.cpp index df76383d..7953d921 100644 --- a/src/path_functions.cpp +++ b/src/path_functions.cpp @@ -20,9 +20,11 @@ #define CASE_SENSITIVE_FILESYSTEM #endif -static bool is_power_2(unsigned int n) { +static bool is_power_2(unsigned int n) +{ unsigned int r = 0; - while (n) { + while (n) + { r += n & 1; n >>= 1; } @@ -32,7 +34,9 @@ static bool is_power_2(unsigned int n) { VPath AOApplication::get_theme_path(QString p_file, QString p_theme) { if (p_theme == "") - p_theme = Options::getInstance().theme(); + { + p_theme = Options::getInstance().theme(); + } return VPath("themes/" + p_theme + "/" + p_file); } @@ -53,7 +57,8 @@ VPath AOApplication::get_sounds_path(QString p_file) VPath AOApplication::get_music_path(QString p_song) { - if (p_song.startsWith("http")) { + if (p_song.startsWith("http")) + { return VPath(p_song); // url } return VPath("sounds/music/" + p_song); @@ -61,7 +66,8 @@ VPath AOApplication::get_music_path(QString p_song) VPath AOApplication::get_background_path(QString p_file) { - if (courtroom_constructed) { + if (courtroom_constructed) + { return VPath("background/" + w_courtroom->get_current_background() + "/" + p_file); } return get_default_background_path(p_file); @@ -72,72 +78,71 @@ VPath AOApplication::get_default_background_path(QString p_file) return VPath("background/default/" + p_file); } -QString AOApplication::get_pos_path(const QString& pos, const bool desk) +QString AOApplication::get_pos_path(const QString &pos, const bool desk) { // witness is default if pos is invalid QString f_background; QString f_desk_image; - if (file_exists(get_image_suffix(get_background_path("witnessempty")))) { + if (file_exists(get_image_suffix(get_background_path("witnessempty")))) + { f_background = "witnessempty"; f_desk_image = "stand"; } - else { + else + { f_background = "wit"; f_desk_image = "wit_overlay"; } - if (pos == "def" && file_exists(get_image_suffix( - get_background_path("defenseempty")))) { + if (pos == "def" && file_exists(get_image_suffix(get_background_path("defenseempty")))) + { f_background = "defenseempty"; f_desk_image = "defensedesk"; } - else if (pos == "pro" && - file_exists(get_image_suffix( - get_background_path("prosecutorempty")))) { + else if (pos == "pro" && file_exists(get_image_suffix(get_background_path("prosecutorempty")))) + { f_background = "prosecutorempty"; f_desk_image = "prosecutiondesk"; } - else if (pos == "jud" && file_exists(get_image_suffix( - get_background_path("judgestand")))) { + else if (pos == "jud" && file_exists(get_image_suffix(get_background_path("judgestand")))) + { f_background = "judgestand"; f_desk_image = "judgedesk"; } - else if (pos == "hld" && - file_exists(get_image_suffix( - get_background_path("helperstand")))) { + else if (pos == "hld" && file_exists(get_image_suffix(get_background_path("helperstand")))) + { f_background = "helperstand"; f_desk_image = "helperdesk"; } - else if (pos == "hlp" && - file_exists(get_image_suffix( - get_background_path("prohelperstand")))) { + else if (pos == "hlp" && file_exists(get_image_suffix(get_background_path("prohelperstand")))) + { f_background = "prohelperstand"; f_desk_image = "prohelperdesk"; } - else if (pos == "jur" && file_exists(get_image_suffix( - get_background_path("jurystand")))) { + else if (pos == "jur" && file_exists(get_image_suffix(get_background_path("jurystand")))) + { f_background = "jurystand"; f_desk_image = "jurydesk"; } - else if (pos == "sea" && - file_exists(get_image_suffix( - get_background_path("seancestand")))) { + else if (pos == "sea" && file_exists(get_image_suffix(get_background_path("seancestand")))) + { f_background = "seancestand"; f_desk_image = "seancedesk"; } - if (file_exists(get_image_suffix( - get_background_path(pos)))) // Unique pos path + if (file_exists(get_image_suffix(get_background_path(pos)))) // Unique pos path { f_background = pos; f_desk_image = pos + "_overlay"; } QString desk_override = read_design_ini("overlays/" + f_background, get_background_path("design.ini")); - if (desk_override != "") { + if (desk_override != "") + { f_desk_image = desk_override; -} - if (desk) { + } + if (desk) + { return f_desk_image; } return f_background; @@ -150,108 +155,130 @@ VPath AOApplication::get_evidence_path(QString p_file) QVector<VPath> 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<VPath> pathlist; - if (p_character != "") - pathlist += get_character_path(p_character, p_element); // Character folder - if (p_misc != "" && p_theme != "" && p_subtheme != "") - pathlist += get_theme_path("misc/" + p_misc + "/" + p_element, p_theme + "/" + p_subtheme); // Subtheme misc path - if (p_misc != "" && p_theme != "") - pathlist += get_theme_path("misc/" + p_misc + "/" + p_element, p_theme); // Theme misc path - if (p_theme != "" && p_subtheme != "") - pathlist += get_theme_path(p_element, p_theme + "/" + p_subtheme); // Subtheme path - if (p_misc != "") - pathlist += get_misc_path(p_misc, p_element); // Base misc path - if (p_theme != "") - pathlist += get_theme_path(p_element, p_theme); // Theme path - if (p_default_theme != "") - pathlist += get_theme_path(p_element, p_default_theme); // Default theme path - 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 != "") - pathlist += get_theme_path(p_placeholder, p_default_theme); // Default placeholder path - return pathlist; + QVector<VPath> pathlist; + if (p_character != "") + { + pathlist += get_character_path(p_character, p_element); // Character folder + } + if (p_misc != "" && p_theme != "" && p_subtheme != "") + { + pathlist += get_theme_path("misc/" + p_misc + "/" + p_element, p_theme + "/" + p_subtheme); // Subtheme misc path + } + if (p_misc != "" && p_theme != "") + { + pathlist += get_theme_path("misc/" + p_misc + "/" + p_element, p_theme); // Theme misc path + } + if (p_theme != "" && p_subtheme != "") + { + pathlist += get_theme_path(p_element, p_theme + "/" + p_subtheme); // Subtheme path + } + if (p_misc != "") + { + pathlist += get_misc_path(p_misc, p_element); // Base misc path + } + if (p_theme != "") + { + pathlist += get_theme_path(p_element, p_theme); // Theme path + } + if (p_default_theme != "") + { + pathlist += get_theme_path(p_element, p_default_theme); // Default theme path + } + 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 != "") + { + pathlist += get_theme_path(p_placeholder, p_default_theme); // Default placeholder path + } + return pathlist; } QString AOApplication::get_asset_path(QVector<VPath> pathlist) { - for (const VPath &p : pathlist) { - QString path = get_real_path(p); - if (!path.isEmpty()) { - return path; - } + for (const VPath &p : pathlist) + { + QString path = get_real_path(p); + if (!path.isEmpty()) + { + return path; + } } return QString(); } QString AOApplication::get_image_path(QVector<VPath> pathlist, bool static_image) { - for (const VPath &p : pathlist) { - QString path = get_image_suffix(p, static_image); - if (!path.isEmpty()) { - return path; - } + for (const VPath &p : pathlist) + { + QString path = get_image_suffix(p, static_image); + if (!path.isEmpty()) + { + return path; + } } return QString(); } QString AOApplication::get_sfx_path(QVector<VPath> pathlist) { - for (const VPath &p : pathlist) { - QString path = get_sfx_suffix(p); - if (!path.isEmpty()) { - return path; - } + 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; - 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); + QString path; + // qDebug() << "got request for" << p_identifier << "in" << p_config; + 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); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - settings.setIniCodec("UTF-8"); + settings.setIniCodec("UTF-8"); #endif - QVariant value = settings.value(p_identifier); - if (value.type() == QVariant::StringList) { - return value.toStringList().join(","); - } - else if (!value.isNull()){ - return value.toString(); - } - } + QVariant value = settings.value(p_identifier); + if (value.type() == QVariant::StringList) + { + return value.toStringList().join(","); + } + else if (!value.isNull()) + { + return value.toString(); + } } - return ""; + } + return ""; } QString AOApplication::get_asset(QString p_element, QString p_theme, QString p_subtheme, QString p_default_theme, QString p_misc, QString p_character, QString p_placeholder) { QString ret = get_asset_path(get_asset_paths(p_element, p_theme, p_subtheme, p_default_theme, p_misc, p_character, p_placeholder)); - if (ret.isEmpty()) { - qWarning().nospace() << "could not find asset " << p_element - << " (theme = " << p_theme - << ", misc = " << p_misc - << ", char = " << p_character << ")"; + if (ret.isEmpty()) + { + qWarning().nospace() << "could not find asset " << p_element << " (theme = " << p_theme << ", misc = " << p_misc << ", char = " << p_character << ")"; } return ret; } -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) +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) { QString ret = get_image_path(get_asset_paths(p_element, p_theme, p_subtheme, p_default_theme, p_misc, p_character, p_placeholder), static_image); - if (ret.isEmpty()) { - qWarning().nospace() << "could not find image " << p_element - << " (theme = " << p_theme - << ", misc = " << p_misc - << ", char = " << p_character - << ", static = " << static_image << ")"; + if (ret.isEmpty()) + { + qWarning().nospace() << "could not find image " << p_element << " (theme = " << p_theme << ", misc = " << p_misc << ", char = " << p_character << ", static = " << static_image << ")"; } return ret; } @@ -266,62 +293,69 @@ QString AOApplication::get_sfx(QString p_sfx, QString p_misc, QString p_characte // If SFX not found, search base/sounds/general/ folder pathlist += get_sounds_path(p_sfx); QString ret = get_sfx_path(pathlist); - if (ret.isEmpty()) { - qWarning().nospace() << "could not find sfx " << p_sfx - << " (char = " << p_character - << ", misc = " << p_misc << ")"; + if (ret.isEmpty()) + { + qWarning().nospace() << "could not find sfx " << p_sfx << " (char = " << p_character << ", misc = " << p_misc << ")"; } return ret; } QString AOApplication::get_case_sensitive_path(QString p_file) { -#ifdef CASE_SENSITIVE_FILESYSTEM +#ifndef CASE_SENSITIVE_FILESYSTEM + return p_file; +#endif + // first, check to see if it's actually there (also serves as base case for // recursion) QFileInfo file(p_file); QString file_basename = file.fileName(); if (exists(p_file)) + { return p_file; - + } QString file_parent_dir = get_case_sensitive_path(file.absolutePath()); // second, does it exist in the new parent dir? if (exists(file_parent_dir + "/" + file_basename)) + { return file_parent_dir + "/" + file_basename; + } // last resort, dirlist parent dir and find case insensitive match - - if (!dir_listing_exist_cache.contains(qHash(file_parent_dir))) { + if (!dir_listing_exist_cache.contains(qHash(file_parent_dir))) + { QStringList files = QDir(file_parent_dir).entryList(); - for (const QString &file : files) { + 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())); + QString found_file = dir_listing_cache.value(qHash(file_parent_dir % QChar('/') % file_basename.toLower())); - if (!found_file.isEmpty()) { + 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; -#else - return p_file; -#endif } -QString AOApplication::get_real_path(const VPath &vpath, - const QStringList &suffixes) { +QString AOApplication::get_real_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.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; + } } } @@ -338,20 +372,26 @@ QString AOApplication::get_real_path(const VPath &vpath, // content 2 // content 1 // base - for (const QString &base : bases) { - for (const QString &suffix : suffixes) { + 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())) { + if (!path.startsWith(baseDir.absolutePath())) + { qWarning() << "invalid path" << path << "(path is outside vfs)"; break; } path = get_case_sensitive_path(path); - if (exists(path)) { + if (exists(path)) + { asset_lookup_cache.insert(qHash(vpath), path); unsigned int cache_size = asset_lookup_cache.size(); if (is_power_2(cache_size)) + { qDebug() << "lookup cache has reached" << cache_size << "entries"; + } return path; } } @@ -359,16 +399,11 @@ QString AOApplication::get_real_path(const VPath &vpath, // Not found in mount paths; check if the file is remote QString remotePath = vpath.toQString(); - if (remotePath.startsWith("http:") || remotePath.startsWith("https:")) { - return remotePath; + if (remotePath.startsWith("http:") || remotePath.startsWith("https:")) + { + return remotePath; } // 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 b526a8ab..25090a7a 100644 --- a/src/scrolltext.cpp +++ b/src/scrolltext.cpp @@ -1,6 +1,8 @@ #include "scrolltext.h" -ScrollText::ScrollText(QWidget *parent) : QWidget(parent), scrollPos(0) +ScrollText::ScrollText(QWidget *parent) + : QWidget(parent) + , scrollPos(0) { staticText.setTextFormat(Qt::PlainText); @@ -13,7 +15,10 @@ ScrollText::ScrollText(QWidget *parent) : QWidget(parent), scrollPos(0) timer.setInterval(50); } -QString ScrollText::text() const { return _text; } +QString ScrollText::text() const +{ + return _text; +} void ScrollText::setText(QString text) { @@ -22,7 +27,10 @@ void ScrollText::setText(QString text) update(); } -QString ScrollText::separator() const { return _separator; } +QString ScrollText::separator() const +{ + return _separator; +} void ScrollText::setSeparator(QString separator) { @@ -42,39 +50,40 @@ void ScrollText::updateText() scrollEnabled = (singleTextWidth > width() - leftMargin * 2); - if (scrollEnabled) { + if (scrollEnabled) + { scrollPos = -64; staticText.setText(_text + _separator); timer.start(); } else + { staticText.setText(_text); + } staticText.prepare(QTransform(), font()); #if QT_VERSION > QT_VERSION_CHECK(5, 11, 0) - wholeTextSize = QSize(fontMetrics().horizontalAdvance(staticText.text()), - fontMetrics().height()); + wholeTextSize = QSize(fontMetrics().horizontalAdvance(staticText.text()), fontMetrics().height()); #else - wholeTextSize = QSize(fontMetrics().boundingRect(staticText.text()).width(), - fontMetrics().height()); + wholeTextSize = QSize(fontMetrics().boundingRect(staticText.text()).width(), fontMetrics().height()); #endif - } void ScrollText::paintEvent(QPaintEvent *) { QPainter p(this); - if (scrollEnabled) { + if (scrollEnabled) + { buffer.fill(qRgba(0, 0, 0, 0)); QPainter pb(&buffer); pb.setPen(p.pen()); pb.setFont(p.font()); int x = qMin(-scrollPos, 0) + leftMargin; - while (x < width()) { - pb.drawStaticText(QPointF(x, (height() - wholeTextSize.height()) / 2), - staticText); + while (x < width()) + { + pb.drawStaticText(QPointF(x, (height() - wholeTextSize.height()) / 2), staticText); x += wholeTextSize.width(); } @@ -86,16 +95,17 @@ void ScrollText::paintEvent(QPaintEvent *) // initial situation: don't apply alpha channel in the left half of the // image at all; apply it more and more until scrollPos gets positive if (scrollPos < 0) + { pb.setOpacity(static_cast<qreal>((qMax(-8, scrollPos) + 8) / 8.0)); + } pb.drawImage(0, 0, alphaChannel); // pb.end(); p.drawImage(0, 0, buffer); } - else { - p.drawStaticText( - QPointF(leftMargin, (height() - wholeTextSize.height()) / 2), - staticText); + else + { + p.drawStaticText(QPointF(leftMargin, (height() - wholeTextSize.height()) / 2), staticText); } } @@ -107,25 +117,35 @@ void ScrollText::resizeEvent(QResizeEvent *) buffer = QImage(size(), QImage::Format_ARGB32_Premultiplied); // Create Alpha Channel: - if (width() > 64) { + if (width() > 64) + { // create first scanline QRgb *scanline1 = reinterpret_cast<QRgb *>(alphaChannel.scanLine(0)); for (int x = 1; x < 16; ++x) + { scanline1[x - 1] = scanline1[width() - x] = qRgba(0, 0, 0, x << 4); + } for (int x = 15; x < width() - 15; ++x) + { scanline1[x] = qRgb(0, 0, 0); + } // copy scanline to the other ones for (int y = 1; y < height(); ++y) - memcpy(alphaChannel.scanLine(y), scanline1, - static_cast<uint>(width() * 4)); + { + memcpy(alphaChannel.scanLine(y), scanline1, static_cast<uint>(width() * 4)); + } } else + { alphaChannel.fill(qRgb(0, 0, 0)); + } // Update scrolling state bool newScrollEnabled = (singleTextWidth > width() - leftMargin); if (newScrollEnabled != scrollEnabled) + { updateText(); + } } void ScrollText::timer_timeout() diff --git a/src/scrolltext.h b/src/scrolltext.h new file mode 100644 index 00000000..b7dd59f8 --- /dev/null +++ b/src/scrolltext.h @@ -0,0 +1,46 @@ +#pragma once + +#include <QDebug> +#include <QPainter> +#include <QStaticText> +#include <QTimer> +#include <QWidget> + +class ScrollText : public QWidget +{ + Q_OBJECT + + Q_PROPERTY(QString text READ text WRITE setText) + Q_PROPERTY(QString separator READ separator WRITE setSeparator) + +public: + explicit ScrollText(QWidget *parent = nullptr); + +public Q_SLOTS: + QString text() const; + void setText(QString text); + + QString separator() const; + void setSeparator(QString separator); + +protected: + virtual void paintEvent(QPaintEvent *); + virtual void resizeEvent(QResizeEvent *); + +private: + void updateText(); + QString _text; + QString _separator; + QStaticText staticText; + int singleTextWidth; + QSize wholeTextSize; + int leftMargin; + bool scrollEnabled; + int scrollPos; + QImage alphaChannel; + QImage buffer; + QTimer timer; + +private Q_SLOTS: + virtual void timer_timeout(); +}; diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 51dc95ad..d8d0c61c 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -1,7 +1,16 @@ -#include "text_file_functions.h" +#include "aoapplication.h" + #include "aoutils.h" +#include "file_functions.h" #include "options.h" +#include <QColor> +#include <QDebug> +#include <QSettings> +#include <QStringList> +#include <QTextStream> +#include <QVector> + QStringList AOApplication::get_list_file(VPath path) { return get_list_file(get_real_path(path)); @@ -16,11 +25,14 @@ QStringList AOApplication::get_list_file(QString p_file) p_ini.setFileName(p_file); if (!p_ini.open(QIODevice::ReadOnly)) + { return return_value; + } QTextStream in(&p_ini); - while (!in.atEnd()) { + while (!in.atEnd()) + { QString line = in.readLine(); return_value.append(line); } @@ -31,11 +43,14 @@ QStringList AOApplication::get_list_file(QString p_file) QString AOApplication::read_file(QString filename) { if (filename.isEmpty()) + { return QString(); + } QFile f_log(filename); - if (!f_log.open(QIODevice::ReadOnly | QIODevice::Text)) { + if (!f_log.open(QIODevice::ReadOnly | QIODevice::Text)) + { qWarning() << "Couldn't open" << filename << "for reading"; return QString(); } @@ -49,17 +64,22 @@ QString AOApplication::read_file(QString filename) bool AOApplication::write_to_file(QString p_text, QString p_file, bool make_dir) { QString path = QFileInfo(p_file).path(); - if (make_dir) { + if (make_dir) + { // Create the dir if it doesn't exist yet QDir dir(path); if (!dir.exists()) + { if (!dir.mkpath(".")) + { return false; + } + } } QFile f_log(p_file); - if (f_log.open(QIODevice::WriteOnly | QIODevice::Text | - QIODevice::Truncate)) { + if (f_log.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) + { QTextStream out(&f_log); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) @@ -74,24 +94,29 @@ bool AOApplication::write_to_file(QString p_text, QString p_file, bool make_dir) return false; } -bool AOApplication::append_to_file(QString p_text, QString p_file, - bool make_dir) +bool AOApplication::append_to_file(QString p_text, QString p_file, bool make_dir) { - if(!file_exists(p_file)) //Don't create a newline if file didn't exist before now + if (!file_exists(p_file)) // Don't create a newline if file didn't exist before now { return write_to_file(p_text, p_file, make_dir); } QString path = QFileInfo(p_file).path(); // Create the dir if it doesn't exist yet - if (make_dir) { + if (make_dir) + { QDir dir(path); if (!dir.exists()) + { if (!dir.mkpath(".")) + { return false; + } + } } QFile f_log(p_file); - if (f_log.open(QIODevice::WriteOnly | QIODevice::Append)) { + if (f_log.open(QIODevice::WriteOnly | QIODevice::Append)) + { QTextStream out(&f_log); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) @@ -108,41 +133,43 @@ bool AOApplication::append_to_file(QString p_text, QString p_file, QMultiMap<QString, QString> AOApplication::load_demo_logs_list() const { - QString l_log_path = applicationDirPath() + "/logs/"; - QDir l_log_folder(l_log_path); - l_log_folder.setFilter(QDir::NoDotAndDotDot | QDir::Dirs); + QString l_log_path = applicationDirPath() + "/logs/"; + QDir l_log_folder(l_log_path); + l_log_folder.setFilter(QDir::NoDotAndDotDot | QDir::Dirs); - QMultiMap<QString,QString> l_demo_logs; - for (const QString &l_demo_folder_name : l_log_folder.entryList()) { - QDir l_demo_folder(l_log_path + l_demo_folder_name); - l_demo_folder.setFilter(QDir::Files); - l_demo_folder.setNameFilters(QStringList() << "*.demo"); + QMultiMap<QString, QString> l_demo_logs; + for (const QString &l_demo_folder_name : l_log_folder.entryList()) + { + QDir l_demo_folder(l_log_path + l_demo_folder_name); + l_demo_folder.setFilter(QDir::Files); + l_demo_folder.setNameFilters(QStringList() << "*.demo"); - for (QString l_demo_name : l_demo_folder.entryList()) { - l_demo_logs.insert(l_demo_folder_name, l_demo_name); - } + for (QString l_demo_name : l_demo_folder.entryList()) + { + l_demo_logs.insert(l_demo_folder_name, l_demo_name); } - return l_demo_logs; + } + return l_demo_logs; } -QString AOApplication::read_design_ini(QString p_identifier, - VPath p_design_path) +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) +QString AOApplication::read_design_ini(QString p_identifier, QString p_design_path) { QSettings settings(p_design_path, QSettings::IniFormat); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) settings.setIniCodec("UTF-8"); #endif QVariant value = settings.value(p_identifier); - if (value.type() == QVariant::StringList) { + if (value.type() == QVariant::StringList) + { return value.toStringList().join(","); } - else if (!value.isNull()) { + else if (!value.isNull()) + { return value.toString(); } return ""; @@ -151,10 +178,14 @@ QString AOApplication::read_design_ini(QString p_identifier, Qt::TransformationMode AOApplication::get_scaling(QString p_scaling) { if (p_scaling.isEmpty()) + { p_scaling = Options::getInstance().defaultScalingMode(); + } if (p_scaling == "smooth") + { return Qt::SmoothTransformation; + } return Qt::FastTransformation; } @@ -167,21 +198,23 @@ QPoint AOApplication::get_button_spacing(QString p_identifier, QString p_file) return_value.setY(0); if (value == "") + { return return_value; + } QStringList sub_line_elements = value.split(","); if (sub_line_elements.size() < 2) + { return return_value; + } return_value.setX(sub_line_elements.at(0).toInt() * Options::getInstance().themeScalingFactor()); return_value.setY(sub_line_elements.at(1).toInt() * Options::getInstance().themeScalingFactor()); return return_value; } -pos_size_type AOApplication::get_element_dimensions(QString p_identifier, - QString p_file, - QString p_misc) +pos_size_type AOApplication::get_element_dimensions(QString p_identifier, QString p_file, QString p_misc) { pos_size_type return_value; return_value.x = 0; @@ -193,7 +226,9 @@ pos_size_type AOApplication::get_element_dimensions(QString p_identifier, QStringList sub_line_elements = f_result.split(","); if (sub_line_elements.size() < 4) + { return return_value; + } int scale = Options::getInstance().themeScalingFactor(); @@ -204,36 +239,32 @@ pos_size_type AOApplication::get_element_dimensions(QString p_identifier, return return_value; } -QString AOApplication::get_design_element(QString p_identifier, QString p_file, - QString p_misc) +QString AOApplication::get_design_element(QString p_identifier, QString p_file, QString p_misc) { QString value = get_config_value(p_identifier, p_file, Options::getInstance().theme(), Options::getInstance().subTheme(), default_theme, p_misc); if (!value.isEmpty()) + { return value; + } return ""; } -// tfw this function is only used for lobby and nowhere else -int AOApplication::get_font_size(QString p_identifier, QString p_file) -{ - QString value = get_config_value(p_identifier, p_file, Options::getInstance().theme(), Options::getInstance().subTheme(), default_theme); - if (!value.isEmpty()) - return value.toInt(); - return 10; -} - QColor AOApplication::get_color(QString p_identifier, QString p_file) { QString value = get_config_value(p_identifier, p_file, Options::getInstance().theme(), Options::getInstance().subTheme(), default_theme); QColor return_color(0, 0, 0); if (value.isEmpty()) + { return return_color; + } QStringList color_list = value.split(","); if (color_list.size() < 3) + { return return_color; + } return_color.setRed(color_list.at(0).toInt()); return_color.setGreen(color_list.at(1).toInt()); @@ -248,47 +279,17 @@ QString AOApplication::get_stylesheet(QString p_file) QFile design_ini; design_ini.setFileName(path); if (!design_ini.open(QIODevice::ReadOnly)) + { return ""; - - QTextStream in(&design_ini); - - QString f_text; - - while (!in.atEnd()) { - f_text.append(in.readLine()); } - design_ini.close(); - return f_text; -} - -QString AOApplication::get_tagged_stylesheet(QString target_tag, QString p_file) -{ - QString path = get_asset(p_file, Options::getInstance().theme(), Options::getInstance().subTheme(), default_theme); - QFile design_ini; - design_ini.setFileName(path); - if (!design_ini.open(QIODevice::ReadOnly)) - return ""; - QTextStream in(&design_ini); QString f_text; - bool tag_found = false; - - while (!in.atEnd()) { - QString line = in.readLine(); - - if (line.startsWith(target_tag, Qt::CaseInsensitive)) { - tag_found = true; - continue; - } - - if (tag_found) { - if ((line.startsWith("[") && line.endsWith("]"))) - break; - f_text.append(line); - } + while (!in.atEnd()) + { + f_text.append(in.readLine()); } design_ini.close(); @@ -300,19 +301,18 @@ QString AOApplication::get_chat_markup(QString p_identifier, QString p_chat) // New Chadly method QString value = get_config_value(p_identifier, "chat_config.ini", Options::getInstance().theme(), Options::getInstance().subTheme(), default_theme, p_chat); if (!value.isEmpty()) + { return value.toUtf8(); + } // Backwards ass compatibility - QVector<VPath> 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") - }; + QVector<VPath> 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) { + for (const VPath &p : backwards_paths) + { QString value = read_design_ini(p_identifier, p); - if (!value.isEmpty()) { + if (!value.isEmpty()) + { return value.toUtf8(); } } @@ -325,12 +325,16 @@ QColor AOApplication::get_chat_color(QString p_identifier, QString p_chat) QColor return_color(255, 255, 255); QString f_result = get_chat_markup(p_identifier, p_chat); if (f_result == "") + { return return_color; + } QStringList color_list = f_result.split(","); if (color_list.size() < 3) + { return return_color; + } return_color.setRed(color_list.at(0).toInt()); return_color.setGreen(color_list.at(1).toInt()); @@ -341,30 +345,33 @@ QColor AOApplication::get_chat_color(QString p_identifier, QString p_chat) QString AOApplication::get_penalty_value(QString p_identifier) { - return get_config_value(p_identifier, "penalty/penalty.ini", Options::getInstance().theme(), - Options::getInstance().subTheme(), default_theme, ""); + return get_config_value(p_identifier, "penalty/penalty.ini", Options::getInstance().theme(), Options::getInstance().subTheme(), default_theme, ""); } - QString AOApplication::get_court_sfx(QString p_identifier, QString p_misc) { QString value = get_config_value(p_identifier, "courtroom_sounds.ini", Options::getInstance().theme(), Options::getInstance().subTheme(), default_theme, p_misc); if (!value.isEmpty()) + { return value.toUtf8(); + } return ""; } QString AOApplication::get_sfx_suffix(VPath sound_to_check) { - QStringList suffixes = {".opus", ".ogg", ".mp3", ".wav", ".mid", ".midi", ".xm", ".it", ".s3m", ".mod", ".mtm", ".umx" }; + QStringList suffixes = {".opus", ".ogg", ".mp3", ".wav", ".mid", ".midi", ".xm", ".it", ".s3m", ".mod", ".mtm", ".umx"}; // Check if we were provided a direct filepath with a suffix already QString path = sound_to_check.toQString(); // Loop through our suffixes - for (const QString &suffix : suffixes) { + for (const QString &suffix : suffixes) + { // If our VPath ends with a valid suffix if (path.endsWith(suffix, Qt::CaseInsensitive)) + { // Return that as the path return get_real_path(sound_to_check); + } } // Otherwise, ignore the provided suffix and check our own return get_real_path(sound_to_check, suffixes); @@ -372,20 +379,24 @@ QString AOApplication::get_sfx_suffix(VPath sound_to_check) QString AOApplication::get_image_suffix(VPath path_to_check, bool static_image) { - QStringList suffixes {}; - if (!static_image) { - suffixes.append({ ".webp", ".apng", ".gif" }); + QStringList suffixes{}; + if (!static_image) + { + suffixes.append({".webp", ".apng", ".gif"}); } suffixes.append(".png"); // Check if we were provided a direct filepath with a suffix already QString path = path_to_check.toQString(); // Loop through our suffixes - for (const QString &suffix : suffixes) { + for (const QString &suffix : suffixes) + { // If our VPath ends with a valid suffix if (path.endsWith(suffix, Qt::CaseInsensitive)) + { // Return that as the path return get_real_path(path_to_check); + } } // Otherwise, ignore the provided suffix and check our own return get_real_path(path_to_check, suffixes); @@ -394,11 +405,9 @@ QString AOApplication::get_image_suffix(VPath path_to_check, bool static_image) // returns whatever is to the right of "search_line =" within target_tag and // terminator_tag, trimmed returns the empty string if the search line couldnt // be found -QString AOApplication::read_char_ini(QString p_char, QString p_search_line, - QString target_tag) +QString AOApplication::read_char_ini(QString p_char, QString p_search_line, QString target_tag) { - QSettings settings(get_real_path(get_character_path(p_char, "char.ini")), - QSettings::IniFormat); + QSettings settings(get_real_path(get_character_path(p_char, "char.ini")), QSettings::IniFormat); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) settings.setIniCodec("UTF-8"); #endif @@ -408,20 +417,6 @@ QString AOApplication::read_char_ini(QString p_char, QString p_search_line, return value; } -void AOApplication::set_char_ini(QString p_char, QString value, - QString p_search_line, QString target_tag) -{ - QSettings settings(get_real_path(get_character_path(p_char, "char.ini")), - QSettings::IniFormat); - -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - settings.setIniCodec("UTF-8"); -#endif - settings.beginGroup(target_tag); - settings.setValue(p_search_line, value); - settings.endGroup(); -} - // returns all the values of target_tag QStringList AOApplication::read_ini_tags(VPath p_path, QString target_tag) { @@ -431,14 +426,19 @@ QStringList AOApplication::read_ini_tags(VPath p_path, QString target_tag) settings.setIniCodec("UTF-8"); #endif if (!target_tag.isEmpty()) + { settings.beginGroup(target_tag); + } QStringList keys = settings.allKeys(); - foreach (QString key, keys) { + foreach (QString key, keys) + { QString value = settings.value(key).value<QString>(); r_values << key + "=" + value; } if (!settings.group().isEmpty()) + { settings.endGroup(); + } return r_values; } @@ -448,9 +448,13 @@ QString AOApplication::get_showname(QString p_char) QString f_needed = read_char_ini(p_char, "needs_showname", "Options"); if (f_needed.startsWith("false")) + { return ""; + } if (f_result == "") + { return p_char; + } return f_result; } @@ -459,7 +463,9 @@ QString AOApplication::get_char_side(QString p_char) QString f_result = read_char_ini(p_char, "side", "Options"); if (f_result == "") + { return "wit"; + } return f_result; } @@ -467,42 +473,51 @@ QString AOApplication::get_blips(QString p_char) { QString f_result = read_char_ini(p_char, "blips", "Options"); - if (f_result == "") { + if (f_result == "") + { f_result = read_char_ini(p_char, "gender", "Options"); // not very PC, FanatSors if (f_result == "") + { f_result = "male"; + } } - if (!file_exists(get_sfx_suffix(get_sounds_path(f_result)))) { + if (!file_exists(get_sfx_suffix(get_sounds_path(f_result)))) + { if (file_exists(get_sfx_suffix(get_sounds_path("../blips/" + f_result)))) + { return "../blips/" + f_result; // Return the cool kids variant + } return "sfx-blip" + f_result; // Return legacy variant } return f_result; } -QString AOApplication::get_emote_property(QString p_char, QString p_emote, - QString p_property) +QString AOApplication::get_emote_property(QString p_char, QString p_emote, QString p_property) { - QString f_result = - read_char_ini(p_char, p_emote, p_property); // per-emote override + QString f_result = read_char_ini(p_char, p_emote, p_property); // per-emote override if (f_result == "") + { f_result = read_char_ini(p_char, p_property, "Options"); // global for this character + } return f_result; } Qt::TransformationMode AOApplication::get_misc_scaling(QString p_miscname) { - if (p_miscname != "") { - QString misc_transform_mode = read_design_ini( - "scaling", get_theme_path("misc/" + p_miscname + "/config.ini")); + if (p_miscname != "") + { + QString misc_transform_mode = read_design_ini("scaling", get_theme_path("misc/" + p_miscname + "/config.ini")); if (misc_transform_mode == "") - misc_transform_mode = - read_design_ini("scaling", get_misc_path(p_miscname, "config.ini")); + { + misc_transform_mode = read_design_ini("scaling", get_misc_path(p_miscname, "config.ini")); + } if (misc_transform_mode == "smooth") + { return Qt::SmoothTransformation; + } } return Qt::FastTransformation; } @@ -516,7 +531,9 @@ QString AOApplication::get_category(QString p_char) QString AOApplication::get_chat(QString p_char) { if (p_char == "default") + { return "default"; + } QString f_result = read_char_ini(p_char, "chat", "Options"); return f_result; } @@ -533,7 +550,9 @@ int AOApplication::get_chat_size(QString p_char) QString f_result = read_char_ini(p_char, "chat_size", "Options"); if (f_result == "") + { return -1; + } return f_result.toInt(); } @@ -542,7 +561,9 @@ int AOApplication::get_preanim_duration(QString p_char, QString p_emote) QString f_result = read_char_ini(p_char, p_emote, "Time"); if (f_result == "") + { return -1; + } return f_result.toInt(); } @@ -551,18 +572,20 @@ int AOApplication::get_emote_number(QString p_char) QString f_result = read_char_ini(p_char, "number", "Emotions"); if (f_result == "") + { return 0; + } return f_result.toInt(); } QString AOApplication::get_emote_comment(QString p_char, int p_emote) { - QString f_result = - read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); + QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); QStringList result_contents = f_result.split("#"); - if (result_contents.size() < 4) { + if (result_contents.size() < 4) + { qWarning() << "misformatted char.ini: " << p_char << ", " << p_emote; return "normal"; } @@ -571,12 +594,12 @@ QString AOApplication::get_emote_comment(QString p_char, int p_emote) QString AOApplication::get_pre_emote(QString p_char, int p_emote) { - QString f_result = - read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); + QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); QStringList result_contents = f_result.split("#"); - if (result_contents.size() < 4) { + if (result_contents.size() < 4) + { qWarning() << "misformatted char.ini: " << p_char << ", " << p_emote; return ""; } @@ -585,12 +608,12 @@ QString AOApplication::get_pre_emote(QString p_char, int p_emote) QString AOApplication::get_emote(QString p_char, int p_emote) { - QString f_result = - read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); + QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); QStringList result_contents = f_result.split("#"); - if (result_contents.size() < 4) { + if (result_contents.size() < 4) + { qWarning() << "misformatted char.ini: " << p_char << ", " << p_emote; return "normal"; } @@ -599,14 +622,13 @@ QString AOApplication::get_emote(QString p_char, int p_emote) int AOApplication::get_emote_mod(QString p_char, int p_emote) { - QString f_result = - read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); + QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); QStringList result_contents = f_result.split("#"); - if (result_contents.size() < 4) { - qWarning() << "misformatted char.ini: " << p_char << ", " - << QString::number(p_emote); + if (result_contents.size() < 4) + { + qWarning() << "misformatted char.ini: " << p_char << ", " << QString::number(p_emote); return 0; } return result_contents.at(3).toInt(); @@ -614,89 +636,90 @@ int AOApplication::get_emote_mod(QString p_char, int p_emote) int AOApplication::get_desk_mod(QString p_char, int p_emote) { - QString f_result = - read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); + QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "Emotions"); QStringList result_contents = f_result.split("#"); if (result_contents.size() < 5) + { return -1; + } QString string_result = result_contents.at(4); if (string_result == "") + { return -1; + } return string_result.toInt(); } QString AOApplication::get_sfx_name(QString p_char, int p_emote) { - QString f_result = - read_char_ini(p_char, QString::number(p_emote + 1), "SoundN"); + QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "SoundN"); if (f_result == "") + { return "1"; - return f_result; -} - -QString AOApplication::get_emote_blip(QString p_char, int p_emote) -{ - QString f_result = - read_char_ini(p_char, QString::number(p_emote + 1), "SoundB"); + } return f_result; } int AOApplication::get_sfx_delay(QString p_char, int p_emote) { - QString f_result = - read_char_ini(p_char, QString::number(p_emote + 1), "SoundT"); + QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "SoundT"); if (f_result == "") + { return 1; + } return f_result.toInt(); } QString AOApplication::get_sfx_looping(QString p_char, int p_emote) { - QString f_result = - read_char_ini(p_char, QString::number(p_emote + 1), "SoundL"); + QString f_result = read_char_ini(p_char, QString::number(p_emote + 1), "SoundL"); if (f_result == "") + { return "0"; + } else + { return f_result; + } } -QString AOApplication::get_sfx_frame(QString p_char, QString p_emote, - int n_frame) +QString AOApplication::get_sfx_frame(QString p_char, QString p_emote, int n_frame) { - QString f_result = read_char_ini(p_char, QString::number(n_frame), - p_emote.append("_FrameSFX")); + QString f_result = read_char_ini(p_char, QString::number(n_frame), p_emote.append("_FrameSFX")); if (f_result == "") + { return ""; + } return f_result; } -QString AOApplication::get_screenshake_frame(QString p_char, QString p_emote, - int n_frame) +QString AOApplication::get_screenshake_frame(QString p_char, QString p_emote, int n_frame) { - QString f_result = read_char_ini(p_char, QString::number(n_frame), - p_emote.append("_FrameScreenshake")); + QString f_result = read_char_ini(p_char, QString::number(n_frame), p_emote.append("_FrameScreenshake")); if (f_result == "") + { return ""; + } return f_result; } -QString AOApplication::get_flash_frame(QString p_char, QString p_emote, - int n_frame) +QString AOApplication::get_flash_frame(QString p_char, QString p_emote, int n_frame) { - QString f_result = read_char_ini(p_char, QString::number(n_frame), - p_emote.append("_FrameRealization")); + QString f_result = read_char_ini(p_char, QString::number(n_frame), p_emote.append("_FrameRealization")); if (f_result == "") + { return ""; + } return f_result; } @@ -705,15 +728,17 @@ int AOApplication::get_text_delay(QString p_char, QString p_emote) QString f_result = read_char_ini(p_char, p_emote, "stay_time"); if (f_result == "") + { return -1; + } return f_result.toInt(); } QStringList AOApplication::get_effects(QString p_char) { const QStringList l_filepath_list{ - get_asset("effects/effects.ini", Options::getInstance().theme(), Options::getInstance().subTheme(), default_theme, ""), - get_asset("effects.ini", Options::getInstance().theme(), Options::getInstance().subTheme(), default_theme, read_char_ini(p_char, "effects", "Options")), + get_asset("effects/effects.ini", Options::getInstance().theme(), Options::getInstance().subTheme(), default_theme, ""), + get_asset("effects.ini", Options::getInstance().theme(), Options::getInstance().subTheme(), default_theme, read_char_ini(p_char, "effects", "Options")), }; QStringList l_effect_name_list; @@ -728,14 +753,16 @@ QStringList AOApplication::get_effects(QString p_char) #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) l_effects_ini.setIniCodec("UTF-8"); #endif - // port legacy effects + // port legacy effects if (!l_effects_ini.contains("version/major") || l_effects_ini.value("version/major").toInt() < 2) { QFile effects_old(i_filepath); - if (QFile::copy(i_filepath, i_filepath + ".old")) { + if (QFile::copy(i_filepath, i_filepath + ".old")) + { AOUtils::migrateEffects(l_effects_ini); } - else { + else + { qWarning() << "Unable to copy effects.ini, skipping migration."; } } @@ -751,9 +778,7 @@ QStringList AOApplication::get_effects(QString p_char) } } - std::sort(l_group_list.begin(), l_group_list.end(), [](const QString &lhs, const QString &rhs) { - return lhs.toInt() < rhs.toInt(); - }); + std::sort(l_group_list.begin(), l_group_list.end(), [](const QString &lhs, const QString &rhs) { return lhs.toInt() < rhs.toInt(); }); for (const QString &i_group : qAsConst(l_group_list)) { @@ -775,46 +800,54 @@ QStringList AOApplication::get_effects(QString p_char) return l_effect_name_list; } -QString AOApplication::get_effect(QString effect, QString p_char, - QString p_folder) +QString AOApplication::get_effect(QString effect, QString p_char, QString p_folder) { if (p_folder == "") + { p_folder = read_char_ini(p_char, "effects", "Options"); + } - QStringList paths { - get_image("effects/" + effect, Options::getInstance().theme(), Options::getInstance().subTheme(), default_theme, ""), - get_image(effect, Options::getInstance().theme(), Options::getInstance().subTheme(), default_theme, p_folder) - }; + QStringList paths{get_image("effects/" + effect, Options::getInstance().theme(), Options::getInstance().subTheme(), default_theme, ""), get_image(effect, Options::getInstance().theme(), Options::getInstance().subTheme(), default_theme, p_folder)}; for (const auto &p : paths) + { if (file_exists(p)) + { return p; + } + } return {}; } -QString AOApplication::get_effect_property(QString fx_name, QString p_char, - QString p_folder, QString p_property) +QString AOApplication::get_effect_property(QString fx_name, QString p_char, QString p_folder, QString p_property) { if (p_folder == "") + { p_folder = read_char_ini(p_char, "effects", "Options"); + } const auto paths = get_asset_paths("effects/effects.ini", Options::getInstance().theme(), Options::getInstance().subTheme(), default_theme, ""); const auto misc_paths = get_asset_paths("effects.ini", Options::getInstance().theme(), Options::getInstance().subTheme(), default_theme, p_folder); QString path; QString f_result; - for (const VPath &p : paths + misc_paths) { + for (const VPath &p : paths + misc_paths) + { path = get_real_path(p); - if (!path.isEmpty()) { + if (!path.isEmpty()) + { QSettings settings(path, QSettings::IniFormat); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) settings.setIniCodec("UTF-8"); #endif QStringList char_effects = settings.childGroups(); - for (int i = 0; i < char_effects.size(); ++i) { + for (int i = 0; i < char_effects.size(); ++i) + { QString effect = settings.value(char_effects[i] + "/name").toString(); - if (effect.toLower() == fx_name.toLower()) { + if (effect.toLower() == fx_name.toLower()) + { f_result = settings.value(char_effects[i] + "/" + p_property).toString(); - if (!f_result.isEmpty()) { + if (!f_result.isEmpty()) + { // Only break the loop if we get a non-empty result, continue the search otherwise break; } @@ -822,7 +855,8 @@ QString AOApplication::get_effect_property(QString fx_name, QString p_char, } } } - if (fx_name == "realization" && p_property == "sound") { + if (fx_name == "realization" && p_property == "sound") + { f_result = get_custom_realization(p_char); } return f_result; @@ -832,15 +866,18 @@ QString AOApplication::get_custom_realization(QString p_char) { QString f_result = read_char_ini(p_char, "realization", "Options"); if (f_result == "") + { return get_court_sfx("realization"); + } return get_sfx_suffix(get_sounds_path(f_result)); } bool AOApplication::get_pos_is_judge(const QString &p_pos) { QStringList positions = read_design_ini("judges", get_background_path("design.ini")).split(","); - if (positions.size() == 1 && positions[0] == "") { - return p_pos == "jud"; //Hardcoded BS only if we have no judges= defined + if (positions.size() == 1 && positions[0] == "") + { + return p_pos == "jud"; // Hardcoded BS only if we have no judges= defined } return positions.contains(p_pos.trimmed()); } diff --git a/src/widgets/add_server_dialog.cpp b/src/widgets/add_server_dialog.cpp index d590d77c..dfc302f0 100644 --- a/src/widgets/add_server_dialog.cpp +++ b/src/widgets/add_server_dialog.cpp @@ -1,29 +1,28 @@ -#include "widgets/add_server_dialog.h" +#include "add_server_dialog.h" + #include "datatypes.h" #include "options.h" +#include "gui_utils.h" #include <QComboBox> #include <QDebug> #include <QDialogButtonBox> #include <QFile> -#include <QLineEdit> #include <QLabel> +#include <QLineEdit> #include <QPlainTextEdit> #include <QPushButton> #include <QSpinBox> #include <QUiLoader> #include <QVBoxLayout> -#define FROM_UI(type, name) \ - ; \ - ui_##name = findChild<type *>(#name); - AddServerDialog::AddServerDialog() { QUiLoader l_loader(this); QFile l_uiFile(Options::getInstance().getUIAsset(DEFAULT_UI)); - if (!l_uiFile.open(QFile::ReadOnly)) { + if (!l_uiFile.open(QFile::ReadOnly)) + { qCritical() << "Unable to open file " << l_uiFile.fileName(); return; } @@ -38,16 +37,13 @@ AddServerDialog::AddServerDialog() FROM_UI(QComboBox, server_protocol_box); FROM_UI(QPlainTextEdit, server_description_edit); FROM_UI(QDialogButtonBox, server_dialog_button); - connect(ui_server_dialog_button, &QDialogButtonBox::accepted, this, - &::AddServerDialog::onSavePressed); - connect(ui_server_dialog_button, &QDialogButtonBox::rejected, this, - &AddServerDialog::onCancelPressed); + connect(ui_server_dialog_button, &QDialogButtonBox::accepted, this, &::AddServerDialog::onSavePressed); + connect(ui_server_dialog_button, &QDialogButtonBox::rejected, this, &AddServerDialog::onCancelPressed); FROM_UI(QLabel, server_legacy_lbl); FROM_UI(QLineEdit, server_legacy_edit); FROM_UI(QPushButton, server_legacy_load_button); - connect(ui_server_legacy_load_button, &QPushButton::released, this, - &AddServerDialog::parseLegacyServerEntry); + connect(ui_server_legacy_load_button, &QPushButton::released, this, &AddServerDialog::parseLegacyServerEntry); } void AddServerDialog::onSavePressed() @@ -57,38 +53,42 @@ void AddServerDialog::onSavePressed() server.ip = ui_server_hostname_edit->text(); server.port = ui_server_port_box->value(); server.desc = ui_server_description_edit->toPlainText(); - server.socket_type = - ui_server_protocol_box->currentIndex() == TCP_INDEX ? TCP : WEBSOCKETS; + server.socket_type = ui_server_protocol_box->currentIndex() == TCP_INDEX ? TCP : WEBSOCKETS; Options::getInstance().addFavorite(server); close(); } void AddServerDialog::onCancelPressed() { - close(); - deleteLater(); + close(); + deleteLater(); } void AddServerDialog::parseLegacyServerEntry() { QStringList l_legacy_entry = ui_server_legacy_edit->text().split(":"); server_type l_server_entry; - if (l_legacy_entry.isEmpty()) { + if (l_legacy_entry.isEmpty()) + { qDebug() << "Legacy entry empty."; return; } int l_item_count = l_legacy_entry.size(); - if (l_item_count >= 3) { + if (l_item_count >= 3) + { ui_server_hostname_edit->setText(l_legacy_entry.at(0)); ui_server_port_box->setValue(l_legacy_entry.at(1).toInt()); ui_server_display_name_edit->setText(l_legacy_entry.at(2)); - if (l_item_count >= 4) { - if (l_legacy_entry.at(3) == "ws") { + if (l_item_count >= 4) + { + if (l_legacy_entry.at(3) == "ws") + { ui_server_protocol_box->setCurrentIndex(1); } - else { + else + { ui_server_protocol_box->setCurrentIndex(0); } } diff --git a/src/widgets/add_server_dialog.h b/src/widgets/add_server_dialog.h new file mode 100644 index 00000000..5df868cc --- /dev/null +++ b/src/widgets/add_server_dialog.h @@ -0,0 +1,40 @@ +#pragma once + +#include "interfaces/server_dialog.h" + +#include <QComboBox> +#include <QDialogButtonBox> +#include <QLabel> +#include <QLineEdit> +#include <QPlainTextEdit> +#include <QPushButton> +#include <QSpinBox> + +class AddServerDialog : public AttorneyOnline::UI::FavoriteServerDialog +{ + Q_OBJECT + +public: + AddServerDialog(); + ~AddServerDialog() = default; + +private: + QWidget *ui_widget; + + QLineEdit *ui_server_display_name_edit; + QLineEdit *ui_server_hostname_edit; + QSpinBox *ui_server_port_box; + QComboBox *ui_server_protocol_box; + QPlainTextEdit *ui_server_description_edit; + QDialogButtonBox *ui_server_dialog_button; + + // Legacy Server UI + QLabel *ui_server_legacy_lbl; + QLineEdit *ui_server_legacy_edit; + QPushButton *ui_server_legacy_load_button; + +private Q_SLOTS: + void onSavePressed() override; + void onCancelPressed() override; + void parseLegacyServerEntry(); +}; diff --git a/src/widgets/aooptionsdialog.cpp b/src/widgets/aooptionsdialog.cpp index 72c9f4e8..a25bde36 100644 --- a/src/widgets/aooptionsdialog.cpp +++ b/src/widgets/aooptionsdialog.cpp @@ -1,45 +1,37 @@ -#include "widgets/aooptionsdialog.h" +#include "aooptionsdialog.h" + #include "QDesktopServices" #include "aoapplication.h" #include "bass.h" #include "file_functions.h" +#include "gui_utils.h" #include "networkmanager.h" #include "options.h" -#include <QCheckBox> #include <QCollator> -#include <QComboBox> -#include <QDialogButtonBox> #include <QGroupBox> -#include <QLabel> -#include <QLineEdit> -#include <QPlainTextEdit> -#include <QPushButton> #include <QResource> -#include <QSpinBox> #include <QUiLoader> #include <QVBoxLayout> -#define FROM_UI(type, name) \ - ; \ - ui_##name = findChild<type *>(#name); - -AOOptionsDialog::AOOptionsDialog(QDialog *parent, AOApplication *p_ao_app) +AOOptionsDialog::AOOptionsDialog(AOApplication *p_ao_app, QWidget *parent) : QDialog(parent) + , ao_app(p_ao_app) { - ao_app = p_ao_app; setupUI(); } void AOOptionsDialog::populateAudioDevices() { ui_audio_device_combobox->clear(); - if (needsDefaultAudioDevice()) { + if (needsDefaultAudioDevice()) + { ui_audio_device_combobox->addItem("default", "default"); } BASS_DEVICEINFO info; - for (int a = 0; BASS_GetDeviceInfo(a, &info); a++) { + for (int a = 0; BASS_GetDeviceInfo(a, &info); a++) + { ui_audio_device_combobox->addItem(info.name, info.name); } } @@ -50,7 +42,8 @@ void AOOptionsDialog::setWidgetData(QCheckBox *widget, const bool &value) widget->setChecked(value); } -template <> bool AOOptionsDialog::widgetData(QCheckBox *widget) const +template <> +bool AOOptionsDialog::widgetData(QCheckBox *widget) const { return widget->isChecked(); } @@ -61,7 +54,8 @@ void AOOptionsDialog::setWidgetData(QLineEdit *widget, const QString &value) widget->setText(value); } -template <> QString AOOptionsDialog::widgetData(QLineEdit *widget) const +template <> +QString AOOptionsDialog::widgetData(QLineEdit *widget) const { return widget->text(); } @@ -72,14 +66,14 @@ void AOOptionsDialog::setWidgetData(QLineEdit *widget, const uint16_t &value) widget->setText(QString::number(value)); } -template <> uint16_t AOOptionsDialog::widgetData(QLineEdit *widget) const +template <> +uint16_t AOOptionsDialog::widgetData(QLineEdit *widget) const { return widget->text().toUShort(); } template <> -void AOOptionsDialog::setWidgetData(QPlainTextEdit *widget, - const QStringList &value) +void AOOptionsDialog::setWidgetData(QPlainTextEdit *widget, const QStringList &value) { widget->setPlainText(value.join('\n')); } @@ -96,7 +90,8 @@ void AOOptionsDialog::setWidgetData(QSpinBox *widget, const int &value) widget->setValue(value); } -template <> int AOOptionsDialog::widgetData(QSpinBox *widget) const +template <> +int AOOptionsDialog::widgetData(QSpinBox *widget) const { return widget->value(); } @@ -104,17 +99,19 @@ template <> int AOOptionsDialog::widgetData(QSpinBox *widget) const template <> void AOOptionsDialog::setWidgetData(QComboBox *widget, const QString &value) { - for (auto i = 0; i < widget->count(); i++) { - if (widget->itemData(i).toString() == value) { + for (auto i = 0; i < widget->count(); i++) + { + if (widget->itemData(i).toString() == value) + { widget->setCurrentIndex(i); return; } } - qWarning() << "value" << value << "not found for widget" - << widget->objectName(); + qWarning() << "value" << value << "not found for widget" << widget->objectName(); } -template <> QString AOOptionsDialog::widgetData(QComboBox *widget) const +template <> +QString AOOptionsDialog::widgetData(QComboBox *widget) const { return widget->currentData().toString(); } @@ -125,34 +122,35 @@ void AOOptionsDialog::setWidgetData(QGroupBox *widget, const bool &value) widget->setChecked(value); } -template <> bool AOOptionsDialog::widgetData(QGroupBox *widget) const +template <> +bool AOOptionsDialog::widgetData(QGroupBox *widget) const { return widget->isChecked(); } template <> -void AOOptionsDialog::setWidgetData(QListWidget *widget, - const QStringList &value) +void AOOptionsDialog::setWidgetData(QListWidget *widget, const QStringList &value) { widget->addItems(value); } -template <> QStringList AOOptionsDialog::widgetData(QListWidget *widget) const +template <> +QStringList AOOptionsDialog::widgetData(QListWidget *widget) const { QStringList paths; - for (auto i = 1; i < widget->count(); i++) { + for (auto i = 1; i < widget->count(); i++) + { paths.append(widget->item(i)->text()); } return paths; } template <typename T, typename V> -void AOOptionsDialog::registerOption(const QString &widgetName, - V (Options::*getter)() const, - void (Options::*setter)(V)) +void AOOptionsDialog::registerOption(const QString &widgetName, V (Options::*getter)() const, void (Options::*setter)(V)) { auto *widget = findChild<T *>(widgetName); - if (!widget) { + if (!widget) + { qWarning() << "could not find widget" << widgetName; return; } @@ -174,70 +172,74 @@ void AOOptionsDialog::updateValues() QStringList bases = Options::getInstance().mountPaths(); bases.push_front(get_base_path()); - for (const QString &base : bases) { - QStringList l_themes = - QDir(base + "/themes").entryList(QDir::Dirs | QDir::NoDotAndDotDot); + for (const QString &base : bases) + { + QStringList l_themes = QDir(base + "/themes").entryList(QDir::Dirs | QDir::NoDotAndDotDot); // Resorts list to match numeric sorting found in Windows. QCollator l_sorting; l_sorting.setNumericMode(true); std::sort(l_themes.begin(), l_themes.end(), l_sorting); - for (const QString &l_theme : qAsConst(l_themes)) { - if (!themes.contains(l_theme)) { + for (const QString &l_theme : qAsConst(l_themes)) + { + if (!themes.contains(l_theme)) + { ui_theme_combobox->addItem(l_theme, l_theme); themes.insert(l_theme); } } } - QStringList l_subthemes = - QDir(ao_app->get_real_path(ao_app->get_theme_path(""))) - .entryList(QDir::Dirs | QDir::NoDotAndDotDot); - for (const QString &l_subtheme : qAsConst(l_subthemes)) { - if (l_subtheme.toLower() != "server" && l_subtheme.toLower() != "default" && - l_subtheme.toLower() != "effects" && l_subtheme.toLower() != "misc") { + QStringList l_subthemes = QDir(ao_app->get_real_path(ao_app->get_theme_path(""))).entryList(QDir::Dirs | QDir::NoDotAndDotDot); + for (const QString &l_subtheme : qAsConst(l_subthemes)) + { + if (l_subtheme.toLower() != "server" && l_subtheme.toLower() != "default" && l_subtheme.toLower() != "effects" && l_subtheme.toLower() != "misc") + { ui_subtheme_combobox->addItem(l_subtheme, l_subtheme); } } - ao_app->net_manager->request_document( - MSDocumentType::PrivacyPolicy, [this](QString document) { - if (document.isEmpty()) { - document = tr("Couldn't get the privacy policy."); - } - ui_privacy_policy->setHtml(document); - }); + ao_app->net_manager->request_document(MSDocumentType::PrivacyPolicy, [this](QString document) { + if (document.isEmpty()) + { + document = tr("Couldn't get the privacy policy."); + } + ui_privacy_policy->setHtml(document); + }); - for (const OptionEntry &entry : qAsConst(optionEntries)) { + for (const OptionEntry &entry : qAsConst(optionEntries)) + { entry.load(); } } void AOOptionsDialog::savePressed() { - bool l_reload_theme_required = - (ui_theme_combobox->currentText() != Options::getInstance().theme()) || - (ui_theme_scaling_factor_sb->value() != - Options::getInstance().themeScalingFactor()); - for (const OptionEntry &entry : qAsConst(optionEntries)) { + bool l_reload_theme_required = (ui_theme_combobox->currentText() != Options::getInstance().theme()) || (ui_theme_scaling_factor_sb->value() != Options::getInstance().themeScalingFactor()); + for (const OptionEntry &entry : qAsConst(optionEntries)) + { entry.save(); } - if (l_reload_theme_required) { - emit reloadThemeRequest(); + if (l_reload_theme_required) + { + Q_EMIT reloadThemeRequest(); } close(); } -void AOOptionsDialog::discardPressed() { close(); } +void AOOptionsDialog::discardPressed() +{ + close(); +} void AOOptionsDialog::buttonClicked(QAbstractButton *button) { - if (ui_settings_buttons->buttonRole(button) == QDialogButtonBox::ResetRole) { - if (QMessageBox::question( - this, "", "Restore default settings?\nThis can't be undone!", - QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { + if (ui_settings_buttons->buttonRole(button) == QDialogButtonBox::ResetRole) + { + if (QMessageBox::question(this, "", "Restore default settings?\nThis can't be undone!", QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) + { // Destructive operation. Options::getInstance().clearConfig(); updateValues(); @@ -249,9 +251,8 @@ void AOOptionsDialog::onReloadThemeClicked() { Options::getInstance().setTheme(ui_theme_combobox->currentText()); Options::getInstance().setSettingsSubTheme(ui_subtheme_combobox->currentText()); - Options::getInstance().setAnimatedThemeEnabled( - ui_animated_theme_cb->isChecked()); - emit reloadThemeRequest(); + Options::getInstance().setAnimatedThemeEnabled(ui_animated_theme_cb->isChecked()); + Q_EMIT reloadThemeRequest(); delete layout(); delete ui_settings_widget; optionEntries.clear(); @@ -265,24 +266,21 @@ void AOOptionsDialog::themeChanged(int i) ui_subtheme_combobox->addItem("server", "server"); ui_subtheme_combobox->addItem("default", "server"); - QStringList l_subthemes = QDir(ao_app->get_real_path(ao_app->get_theme_path( - "", ui_theme_combobox->itemText(i)))) - .entryList(QDir::Dirs | QDir::NoDotAndDotDot); + QStringList l_subthemes = QDir(ao_app->get_real_path(ao_app->get_theme_path("", ui_theme_combobox->itemText(i)))).entryList(QDir::Dirs | QDir::NoDotAndDotDot); - for (const QString &l_subthemes : qAsConst(l_subthemes)) { - if (l_subthemes.toLower() != "server" && - l_subthemes.toLower() != "default" && - l_subthemes.toLower() != "effects" && l_subthemes.toLower() != "misc") { + for (const QString &l_subthemes : qAsConst(l_subthemes)) + { + if (l_subthemes.toLower() != "server" && l_subthemes.toLower() != "default" && l_subthemes.toLower() != "effects" && l_subthemes.toLower() != "misc") + { ui_subtheme_combobox->addItem(l_subthemes, l_subthemes); } } QString l_ressource_name = Options::getInstance().theme() + ".rcc"; - QString l_resource = - ao_app->get_asset("themes/" + ui_theme_combobox->currentText() + ".rcc"); - if (l_resource.isEmpty()) { - QResource::unregisterResource( - ao_app->get_asset("themes/" + l_ressource_name)); + QString l_resource = ao_app->get_asset("themes/" + ui_theme_combobox->currentText() + ".rcc"); + if (l_resource.isEmpty()) + { + QResource::unregisterResource(ao_app->get_asset("themes/" + l_ressource_name)); qDebug() << "Unable to locate ressource file" << l_ressource_name; return; } @@ -293,7 +291,8 @@ void AOOptionsDialog::setupUI() { QUiLoader l_loader(this); QFile l_uiFile(Options::getInstance().getUIAsset("options_dialog.ui")); - if (!l_uiFile.open(QFile::ReadOnly)) { + if (!l_uiFile.open(QFile::ReadOnly)) + { qWarning() << "Unable to open file " << l_uiFile.fileName(); return; } @@ -306,98 +305,71 @@ void AOOptionsDialog::setupUI() // General dialog element. FROM_UI(QDialogButtonBox, settings_buttons); - connect(ui_settings_buttons, &QDialogButtonBox::accepted, this, - &AOOptionsDialog::savePressed); - connect(ui_settings_buttons, &QDialogButtonBox::rejected, this, - &AOOptionsDialog::discardPressed); - connect(ui_settings_buttons, &QDialogButtonBox::clicked, this, - &AOOptionsDialog::buttonClicked); + connect(ui_settings_buttons, &QDialogButtonBox::accepted, this, &AOOptionsDialog::savePressed); + connect(ui_settings_buttons, &QDialogButtonBox::rejected, this, &AOOptionsDialog::discardPressed); + connect(ui_settings_buttons, &QDialogButtonBox::clicked, this, &AOOptionsDialog::buttonClicked); // Gameplay Tab - FROM_UI(QComboBox, theme_combobox) - connect(ui_theme_combobox, - QOverload<int>::of(&QComboBox::currentIndexChanged), this, - &AOOptionsDialog::themeChanged); + FROM_UI(QComboBox, theme_combobox); + connect(ui_theme_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &AOOptionsDialog::themeChanged); - registerOption<QComboBox, QString>("theme_combobox", &Options::theme, - &Options::setTheme); + registerOption<QComboBox, QString>("theme_combobox", &Options::theme, &Options::setTheme); - FROM_UI(QComboBox, subtheme_combobox) - registerOption<QComboBox, QString>("subtheme_combobox", &Options::settingsSubTheme, - &Options::setSettingsSubTheme); + FROM_UI(QComboBox, subtheme_combobox); + registerOption<QComboBox, QString>("subtheme_combobox", &Options::settingsSubTheme, &Options::setSettingsSubTheme); - FROM_UI(QPushButton, theme_reload_button) - connect(ui_theme_reload_button, &QPushButton::clicked, this, - &::AOOptionsDialog::onReloadThemeClicked); + FROM_UI(QPushButton, theme_reload_button); + connect(ui_theme_reload_button, &QPushButton::clicked, this, &::AOOptionsDialog::onReloadThemeClicked); - FROM_UI(QPushButton, theme_folder_button) + FROM_UI(QPushButton, theme_folder_button); connect(ui_theme_folder_button, &QPushButton::clicked, this, [=] { - QString p_path = ao_app->get_real_path(ao_app->get_theme_path( - "", ui_theme_combobox->itemText(ui_theme_combobox->currentIndex()))); - if (!dir_exists(p_path)) { + QString p_path = ao_app->get_real_path(ao_app->get_theme_path("", ui_theme_combobox->itemText(ui_theme_combobox->currentIndex()))); + if (!dir_exists(p_path)) + { return; } QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); }); - FROM_UI(QSpinBox, theme_scaling_factor_sb) - FROM_UI(QCheckBox, animated_theme_cb) - FROM_UI(QSpinBox, stay_time_spinbox) - FROM_UI(QCheckBox, instant_objection_cb) - FROM_UI(QSpinBox, text_crawl_spinbox) - FROM_UI(QSpinBox, chat_ratelimit_spinbox) - FROM_UI(QLineEdit, username_textbox) - FROM_UI(QCheckBox, showname_cb) - FROM_UI(QLineEdit, default_showname_textbox) - FROM_UI(QLineEdit, ms_textbox) - FROM_UI(QCheckBox, discord_cb) - FROM_UI(QComboBox, language_combobox) - FROM_UI(QComboBox, scaling_combobox) - FROM_UI(QCheckBox, shake_cb) - FROM_UI(QCheckBox, effects_cb) - FROM_UI(QCheckBox, framenetwork_cb) - FROM_UI(QCheckBox, colorlog_cb) - FROM_UI(QCheckBox, stickysounds_cb) - FROM_UI(QCheckBox, stickyeffects_cb) - FROM_UI(QCheckBox, stickypres_cb) - FROM_UI(QCheckBox, customchat_cb) - FROM_UI(QCheckBox, sticker_cb) - FROM_UI(QCheckBox, continuous_cb) - FROM_UI(QCheckBox, category_stop_cb) - FROM_UI(QCheckBox, sfx_on_idle_cb) - FROM_UI(QCheckBox, evidence_double_click_cb) - - registerOption<QSpinBox, int>("theme_scaling_factor_sb", - &Options::themeScalingFactor, - &Options::setThemeScalingFactor); - registerOption<QCheckBox, bool>("animated_theme_cb", - &Options::animatedThemeEnabled, - &Options::setAnimatedThemeEnabled); - registerOption<QSpinBox, int>("stay_time_spinbox", &Options::textStayTime, - &Options::setTextStayTime); - registerOption<QCheckBox, bool>("instant_objection_cb", - &Options::objectionSkipQueueEnabled, - &Options::setObjectionSkipQueueEnabled); - registerOption<QSpinBox, int>("text_crawl_spinbox", &Options::textCrawlSpeed, - &Options::setTextCrawlSpeed); - registerOption<QSpinBox, int>("chat_ratelimit_spinbox", - &Options::chatRateLimit, - &Options::setChatRateLimit); - registerOption<QLineEdit, QString>("username_textbox", &Options::username, - &Options::setUsername); - registerOption<QCheckBox, bool>("showname_cb", - &Options::customShownameEnabled, - &Options::setCustomShownameEnabled); - registerOption<QLineEdit, QString>("default_showname_textbox", - &Options::shownameOnJoin, - &Options::setShownameOnJoin); - registerOption<QLineEdit, QString>("ms_textbox", - &Options::alternativeMasterserver, - &Options::setAlternativeMasterserver); - registerOption<QCheckBox, bool>("discord_cb", &Options::discordEnabled, - &Options::setDiscordEnabled); - registerOption<QComboBox, QString>("language_combobox", &Options::language, - &Options::setLanguage); + FROM_UI(QSpinBox, theme_scaling_factor_sb); + FROM_UI(QCheckBox, animated_theme_cb); + FROM_UI(QSpinBox, stay_time_spinbox); + FROM_UI(QCheckBox, instant_objection_cb); + FROM_UI(QSpinBox, text_crawl_spinbox); + FROM_UI(QSpinBox, chat_ratelimit_spinbox); + FROM_UI(QLineEdit, username_textbox); + FROM_UI(QCheckBox, showname_cb); + FROM_UI(QLineEdit, default_showname_textbox); + FROM_UI(QLineEdit, ms_textbox); + FROM_UI(QCheckBox, discord_cb); + FROM_UI(QComboBox, language_combobox); + FROM_UI(QComboBox, scaling_combobox); + FROM_UI(QCheckBox, shake_cb); + FROM_UI(QCheckBox, effects_cb); + FROM_UI(QCheckBox, framenetwork_cb); + FROM_UI(QCheckBox, colorlog_cb); + FROM_UI(QCheckBox, stickysounds_cb); + FROM_UI(QCheckBox, stickyeffects_cb); + FROM_UI(QCheckBox, stickypres_cb); + FROM_UI(QCheckBox, customchat_cb); + FROM_UI(QCheckBox, sticker_cb); + FROM_UI(QCheckBox, continuous_cb); + FROM_UI(QCheckBox, category_stop_cb); + FROM_UI(QCheckBox, sfx_on_idle_cb); + FROM_UI(QCheckBox, evidence_double_click_cb); + + registerOption<QSpinBox, int>("theme_scaling_factor_sb", &Options::themeScalingFactor, &Options::setThemeScalingFactor); + registerOption<QCheckBox, bool>("animated_theme_cb", &Options::animatedThemeEnabled, &Options::setAnimatedThemeEnabled); + registerOption<QSpinBox, int>("stay_time_spinbox", &Options::textStayTime, &Options::setTextStayTime); + registerOption<QCheckBox, bool>("instant_objection_cb", &Options::objectionSkipQueueEnabled, &Options::setObjectionSkipQueueEnabled); + registerOption<QSpinBox, int>("text_crawl_spinbox", &Options::textCrawlSpeed, &Options::setTextCrawlSpeed); + registerOption<QSpinBox, int>("chat_ratelimit_spinbox", &Options::chatRateLimit, &Options::setChatRateLimit); + registerOption<QLineEdit, QString>("username_textbox", &Options::username, &Options::setUsername); + registerOption<QCheckBox, bool>("showname_cb", &Options::customShownameEnabled, &Options::setCustomShownameEnabled); + registerOption<QLineEdit, QString>("default_showname_textbox", &Options::shownameOnJoin, &Options::setShownameOnJoin); + registerOption<QLineEdit, QString>("ms_textbox", &Options::alternativeMasterserver, &Options::setAlternativeMasterserver); + registerOption<QCheckBox, bool>("discord_cb", &Options::discordEnabled, &Options::setDiscordEnabled); + registerOption<QComboBox, QString>("language_combobox", &Options::language, &Options::setLanguage); ui_language_combobox->addItem("English", "en"); ui_language_combobox->addItem("Deutsch", "de"); @@ -407,108 +379,69 @@ void AOOptionsDialog::setupUI() ui_language_combobox->addItem("日本語", "jp"); ui_language_combobox->addItem("Русский", "ru"); - registerOption<QComboBox, QString>("scaling_combobox", - &Options::defaultScalingMode, - &Options::setDefaultScalingMode); + registerOption<QComboBox, QString>("scaling_combobox", &Options::defaultScalingMode, &Options::setDefaultScalingMode); // Populate scaling dropdown. This is necessary as we need the user data // embeeded into the entry. ui_scaling_combobox->addItem(tr("Pixel"), "fast"); ui_scaling_combobox->addItem(tr("Smooth"), "smooth"); - registerOption<QCheckBox, bool>("shake_cb", &Options::shakeEnabled, - &Options::setShakeEnabled); - registerOption<QCheckBox, bool>("effects_cb", &Options::effectsEnabled, - &Options::setEffectsEnabled); - registerOption<QCheckBox, bool>("framenetwork_cb", - &Options::networkedFrameSfxEnabled, - &Options::setNetworkedFrameSfxEnabled); - registerOption<QCheckBox, bool>("colorlog_cb", &Options::colorLogEnabled, - &Options::setColorLogEnabled); - registerOption<QCheckBox, bool>( - "stickysounds_cb", &Options::clearSoundsDropdownOnPlayEnabled, - &Options::setClearSoundsDropdownOnPlayEnabled); - registerOption<QCheckBox, bool>( - "stickyeffects_cb", &Options::clearEffectsDropdownOnPlayEnabled, - &Options::setClearEffectsDropdownOnPlayEnabled); - registerOption<QCheckBox, bool>("stickypres_cb", - &Options::clearPreOnPlayEnabled, - &Options::setClearPreOnPlayEnabled); - registerOption<QCheckBox, bool>("customchat_cb", - &Options::customChatboxEnabled, - &Options::setCustomChatboxEnabled); - registerOption<QCheckBox, bool>("sticker_cb", - &Options::characterStickerEnabled, - &Options::setCharacterStickerEnabled); - registerOption<QCheckBox, bool>("continuous_cb", - &Options::continuousPlaybackEnabled, - &Options::setContinuousPlaybackEnabled); - registerOption<QCheckBox, bool>("category_stop_cb", - &Options::stopMusicOnCategoryEnabled, - &Options::setStopMusicOnCategoryEnabled); - registerOption<QCheckBox, bool>("sfx_on_idle_cb", - &Options::playSelectedSFXOnIdle, - &Options::setPlaySelectedSFXOnIdle); - registerOption<QCheckBox, bool>("evidence_double_click_cb", - &Options::evidenceDoubleClickEdit, - &Options::setEvidenceDoubleClickEdit); + registerOption<QCheckBox, bool>("shake_cb", &Options::shakeEnabled, &Options::setShakeEnabled); + registerOption<QCheckBox, bool>("effects_cb", &Options::effectsEnabled, &Options::setEffectsEnabled); + registerOption<QCheckBox, bool>("framenetwork_cb", &Options::networkedFrameSfxEnabled, &Options::setNetworkedFrameSfxEnabled); + registerOption<QCheckBox, bool>("colorlog_cb", &Options::colorLogEnabled, &Options::setColorLogEnabled); + registerOption<QCheckBox, bool>("stickysounds_cb", &Options::clearSoundsDropdownOnPlayEnabled, &Options::setClearSoundsDropdownOnPlayEnabled); + registerOption<QCheckBox, bool>("stickyeffects_cb", &Options::clearEffectsDropdownOnPlayEnabled, &Options::setClearEffectsDropdownOnPlayEnabled); + registerOption<QCheckBox, bool>("stickypres_cb", &Options::clearPreOnPlayEnabled, &Options::setClearPreOnPlayEnabled); + registerOption<QCheckBox, bool>("customchat_cb", &Options::customChatboxEnabled, &Options::setCustomChatboxEnabled); + registerOption<QCheckBox, bool>("sticker_cb", &Options::characterStickerEnabled, &Options::setCharacterStickerEnabled); + registerOption<QCheckBox, bool>("continuous_cb", &Options::continuousPlaybackEnabled, &Options::setContinuousPlaybackEnabled); + registerOption<QCheckBox, bool>("category_stop_cb", &Options::stopMusicOnCategoryEnabled, &Options::setStopMusicOnCategoryEnabled); + registerOption<QCheckBox, bool>("sfx_on_idle_cb", &Options::playSelectedSFXOnIdle, &Options::setPlaySelectedSFXOnIdle); + registerOption<QCheckBox, bool>("evidence_double_click_cb", &Options::evidenceDoubleClickEdit, &Options::setEvidenceDoubleClickEdit); // Callwords tab. This could just be a QLineEdit, but no, we decided to allow // people to put a billion entries in. - FROM_UI(QPlainTextEdit, callwords_textbox) - registerOption<QPlainTextEdit, QStringList>( - "callwords_textbox", &Options::callwords, &Options::setCallwords); + FROM_UI(QPlainTextEdit, callwords_textbox); + registerOption<QPlainTextEdit, QStringList>("callwords_textbox", &Options::callwords, &Options::setCallwords); // Audio tab. - FROM_UI(QComboBox, audio_device_combobox) + FROM_UI(QComboBox, audio_device_combobox); populateAudioDevices(); - registerOption<QComboBox, QString>("audio_device_combobox", - &Options::audioOutputDevice, - &Options::setAudioOutputDevice); - - FROM_UI(QSpinBox, suppress_audio_spinbox) - FROM_UI(QSpinBox, bliprate_spinbox) - FROM_UI(QCheckBox, blank_blips_cb) - FROM_UI(QCheckBox, loopsfx_cb) - FROM_UI(QCheckBox, objectmusic_cb) - FROM_UI(QCheckBox, disablestreams_cb) - - registerOption<QSpinBox, int>("suppress_audio_spinbox", - &::Options::defaultSuppressAudio, - &Options::setDefaultSupressedAudio); - registerOption<QSpinBox, int>("bliprate_spinbox", &::Options::blipRate, - &Options::setBlipRate); - registerOption<QCheckBox, bool>("blank_blips_cb", &Options::blankBlip, - &Options::setBlankBlip); - registerOption<QCheckBox, bool>("loopsfx_cb", &Options::loopingSfx, - &Options::setLoopingSfx); - registerOption<QCheckBox, bool>("objectmusic_cb", - &Options::objectionStopMusic, - &Options::setObjectionStopMusic); - registerOption<QCheckBox, bool>("disablestreams_cb", - &Options::streamingEnabled, - &Options::setStreamingEnabled); + registerOption<QComboBox, QString>("audio_device_combobox", &Options::audioOutputDevice, &Options::setAudioOutputDevice); + + FROM_UI(QSpinBox, suppress_audio_spinbox); + FROM_UI(QSpinBox, bliprate_spinbox); + FROM_UI(QCheckBox, blank_blips_cb); + FROM_UI(QCheckBox, loopsfx_cb); + FROM_UI(QCheckBox, objectmusic_cb); + FROM_UI(QCheckBox, disablestreams_cb); + + registerOption<QSpinBox, int>("suppress_audio_spinbox", &::Options::defaultSuppressAudio, &Options::setDefaultSupressedAudio); + registerOption<QSpinBox, int>("bliprate_spinbox", &::Options::blipRate, &Options::setBlipRate); + registerOption<QCheckBox, bool>("blank_blips_cb", &Options::blankBlip, &Options::setBlankBlip); + registerOption<QCheckBox, bool>("loopsfx_cb", &Options::loopingSfx, &Options::setLoopingSfx); + registerOption<QCheckBox, bool>("objectmusic_cb", &Options::objectionStopMusic, &Options::setObjectionStopMusic); + registerOption<QCheckBox, bool>("disablestreams_cb", &Options::streamingEnabled, &Options::setStreamingEnabled); // Asset tab - FROM_UI(QListWidget, mount_list) - auto *defaultMount = - new QListWidgetItem(tr("%1 (default)").arg(get_base_path())); + FROM_UI(QListWidget, mount_list); + auto *defaultMount = new QListWidgetItem(tr("%1 (default)").arg(get_base_path())); defaultMount->setFlags(Qt::ItemFlag::NoItemFlags); ui_mount_list->addItem(defaultMount); - registerOption<QListWidget, QStringList>("mount_list", &Options::mountPaths, - &Options::setMountPaths); + registerOption<QListWidget, QStringList>("mount_list", &Options::mountPaths, &Options::setMountPaths); - FROM_UI(QPushButton, mount_add) + FROM_UI(QPushButton, mount_add); connect(ui_mount_add, &QPushButton::clicked, this, [this] { - QString path = QFileDialog::getExistingDirectory( - this, tr("Select a base folder"), QApplication::applicationDirPath(), - QFileDialog::ShowDirsOnly); - if (path.isEmpty()) { + QString path = QFileDialog::getExistingDirectory(this, tr("Select a base folder"), QApplication::applicationDirPath(), QFileDialog::ShowDirsOnly); + if (path.isEmpty()) + { return; } QDir dir(QApplication::applicationDirPath()); QString relative = dir.relativeFilePath(path); - if (!relative.contains("../")) { + if (!relative.contains("../")) + { path = relative; } QListWidgetItem *dir_item = new QListWidgetItem(path); @@ -516,22 +449,28 @@ void AOOptionsDialog::setupUI() ui_mount_list->setCurrentItem(dir_item); // quick hack to update buttons - emit ui_mount_list->itemSelectionChanged(); + Q_EMIT ui_mount_list->itemSelectionChanged(); }); - FROM_UI(QPushButton, mount_remove) + FROM_UI(QPushButton, mount_remove); connect(ui_mount_remove, &QPushButton::clicked, this, [this] { auto selected = ui_mount_list->selectedItems(); - if (selected.isEmpty()) return; + if (selected.isEmpty()) + { + return; + } delete selected[0]; - emit ui_mount_list->itemSelectionChanged(); + Q_EMIT ui_mount_list->itemSelectionChanged(); asset_cache_dirty = true; }); - FROM_UI(QPushButton, mount_up) + FROM_UI(QPushButton, mount_up); connect(ui_mount_up, &QPushButton::clicked, this, [this] { auto selected = ui_mount_list->selectedItems(); - if (selected.isEmpty()) return; + if (selected.isEmpty()) + { + return; + } auto *item = selected[0]; int row = ui_mount_list->row(item); ui_mount_list->takeItem(row); @@ -541,10 +480,13 @@ void AOOptionsDialog::setupUI() asset_cache_dirty = true; }); - FROM_UI(QPushButton, mount_down) + FROM_UI(QPushButton, mount_down); connect(ui_mount_down, &QPushButton::clicked, this, [this] { auto selected = ui_mount_list->selectedItems(); - if (selected.isEmpty()) return; + if (selected.isEmpty()) + { + return; + } auto *item = selected[0]; int row = ui_mount_list->row(item); ui_mount_list->takeItem(row); @@ -554,7 +496,7 @@ void AOOptionsDialog::setupUI() asset_cache_dirty = true; }); - FROM_UI(QPushButton, mount_clear_cache) + FROM_UI(QPushButton, mount_clear_cache); connect(ui_mount_clear_cache, &QPushButton::clicked, this, [this] { asset_cache_dirty = true; ui_mount_clear_cache->setEnabled(false); @@ -567,48 +509,43 @@ void AOOptionsDialog::setupUI() ui_mount_up->setEnabled(row_selected); ui_mount_down->setEnabled(row_selected); - if (!row_selected) return; + 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); + if (row <= 1) + { + ui_mount_up->setEnabled(false); + } + if (row >= ui_mount_list->count() - 1) + { + ui_mount_down->setEnabled(false); + } }); // Logging tab - FROM_UI(QCheckBox, downwards_cb) - FROM_UI(QSpinBox, length_spinbox) - FROM_UI(QCheckBox, log_newline_cb) - FROM_UI(QSpinBox, log_margin_spinbox) - FROM_UI(QLabel, log_timestamp_format_lbl) - FROM_UI(QComboBox, log_timestamp_format_combobox) - - registerOption<QCheckBox, bool>("downwards_cb", - &Options::logDirectionDownwards, - &Options::setLogDirectionDownwards); - registerOption<QSpinBox, int>("length_spinbox", &Options::maxLogSize, - &Options::setMaxLogSize); - registerOption<QCheckBox, bool>("log_newline_cb", &Options::logNewline, - &Options::setLogNewline); - registerOption<QSpinBox, int>("log_margin_spinbox", &Options::logMargin, - &Options::setLogMargin); - - FROM_UI(QCheckBox, log_timestamp_cb) - registerOption<QCheckBox, bool>("log_timestamp_cb", - &Options::logTimestampEnabled, - &Options::setLogTimestampEnabled); - connect(ui_log_timestamp_cb, &QCheckBox::stateChanged, this, - &::AOOptionsDialog::timestampCbChanged); - ui_log_timestamp_format_lbl->setText( - tr("Log timestamp format:\n") + - QDateTime::currentDateTime().toString( - Options::getInstance().logTimestampFormat())); - - FROM_UI(QComboBox, log_timestamp_format_combobox) - registerOption<QComboBox, QString>("log_timestamp_format_combobox", - &Options::logTimestampFormat, - &Options::setLogTimestampFormat); - connect(ui_log_timestamp_format_combobox, &QComboBox::currentTextChanged, - this, &::AOOptionsDialog::onTimestampFormatEdited); + FROM_UI(QCheckBox, downwards_cb); + FROM_UI(QSpinBox, length_spinbox); + FROM_UI(QCheckBox, log_newline_cb); + FROM_UI(QSpinBox, log_margin_spinbox); + FROM_UI(QLabel, log_timestamp_format_lbl); + FROM_UI(QComboBox, log_timestamp_format_combobox); + + registerOption<QCheckBox, bool>("downwards_cb", &Options::logDirectionDownwards, &Options::setLogDirectionDownwards); + registerOption<QSpinBox, int>("length_spinbox", &Options::maxLogSize, &Options::setMaxLogSize); + registerOption<QCheckBox, bool>("log_newline_cb", &Options::logNewline, &Options::setLogNewline); + registerOption<QSpinBox, int>("log_margin_spinbox", &Options::logMargin, &Options::setLogMargin); + + FROM_UI(QCheckBox, log_timestamp_cb); + registerOption<QCheckBox, bool>("log_timestamp_cb", &Options::logTimestampEnabled, &Options::setLogTimestampEnabled); + connect(ui_log_timestamp_cb, &QCheckBox::stateChanged, this, &::AOOptionsDialog::timestampCbChanged); + ui_log_timestamp_format_lbl->setText(tr("Log timestamp format:\n") + QDateTime::currentDateTime().toString(Options::getInstance().logTimestampFormat())); + + FROM_UI(QComboBox, log_timestamp_format_combobox); + registerOption<QComboBox, QString>("log_timestamp_format_combobox", &Options::logTimestampFormat, &Options::setLogTimestampFormat); + connect(ui_log_timestamp_format_combobox, &QComboBox::currentTextChanged, this, &::AOOptionsDialog::onTimestampFormatEdited); QString l_current_format = Options::getInstance().logTimestampFormat(); @@ -620,28 +557,26 @@ void AOOptionsDialog::setupUI() ui_log_timestamp_format_combobox->addItem("h:mm AP", "h:mm AP"); ui_log_timestamp_format_combobox->addItem("hh:mm", "hh:mm"); - if (!Options::getInstance().logTimestampEnabled()) { + if (!Options::getInstance().logTimestampEnabled()) + { ui_log_timestamp_format_combobox->setDisabled(true); } - FROM_UI(QCheckBox, log_ic_actions_cb) - FROM_UI(QCheckBox, desync_logs_cb) - FROM_UI(QCheckBox, log_text_cb) + FROM_UI(QCheckBox, log_ic_actions_cb); + FROM_UI(QCheckBox, desync_logs_cb); + FROM_UI(QCheckBox, log_text_cb); - registerOption<QCheckBox, bool>("log_ic_actions_cb", &Options::logIcActions, - &Options::setLogIcActions); - registerOption<QCheckBox, bool>("desync_logs_cb", - &Options::desynchronisedLogsEnabled, - &Options::setDesynchronisedLogsEnabled); - registerOption<QCheckBox, bool>("log_text_cb", &Options::logToTextFileEnabled, - &Options::setLogToTextFileEnabled); - registerOption<QCheckBox, bool>("log_demo_cb", &Options::logToDemoFileEnabled, - &Options::setLogToDemoFileEnabled); + registerOption<QCheckBox, bool>("log_ic_actions_cb", &Options::logIcActions, &Options::setLogIcActions); + registerOption<QCheckBox, bool>("desync_logs_cb", &Options::desynchronisedLogsEnabled, &Options::setDesynchronisedLogsEnabled); + registerOption<QCheckBox, bool>("log_text_cb", &Options::logToTextFileEnabled, &Options::setLogToTextFileEnabled); + registerOption<QCheckBox, bool>("log_demo_cb", &Options::logToDemoFileEnabled, &Options::setLogToDemoFileEnabled); // DSGVO/Privacy tab - FROM_UI(QTextBrowser, privacy_policy) + FROM_UI(QTextBrowser, privacy_policy); ui_privacy_policy->setPlainText(tr("Getting privacy policy...")); + FROM_UI(QCheckBox, privacy_optout_cb); + registerOption<QCheckBox, bool>("privacy_optout", &Options::playerCountOptout, &Options::setPlayerCountOptout); updateValues(); } @@ -653,9 +588,7 @@ void AOOptionsDialog::onTimestampFormatEdited() ui_log_timestamp_format_combobox->setItemText(index, format); ui_log_timestamp_format_combobox->setItemData(index, format); - ui_log_timestamp_format_lbl->setText( - tr("Log timestamp format:\n") + - QDateTime::currentDateTime().toString(format)); + ui_log_timestamp_format_lbl->setText(tr("Log timestamp format:\n") + QDateTime::currentDateTime().toString(format)); } void AOOptionsDialog::timestampCbChanged(int state) @@ -664,11 +597,20 @@ void AOOptionsDialog::timestampCbChanged(int state) } #if (defined(_WIN32) || defined(_WIN64)) -bool AOOptionsDialog::needsDefaultAudioDevice() { return true; } +bool AOOptionsDialog::needsDefaultAudioDevice() +{ + return true; +} #elif (defined(LINUX) || defined(__linux__)) -bool AOOptionsDialog::needsDefaultAudioDevice() { return false; } +bool AOOptionsDialog::needsDefaultAudioDevice() +{ + return false; +} #elif defined __APPLE__ -bool AOOptionsDialog::needsDefaultAudioDevice() { return true; } +bool AOOptionsDialog::needsDefaultAudioDevice() +{ + return true; +} #else #error This operating system is not supported. #endif diff --git a/src/widgets/aooptionsdialog.h b/src/widgets/aooptionsdialog.h new file mode 100644 index 00000000..bccec581 --- /dev/null +++ b/src/widgets/aooptionsdialog.h @@ -0,0 +1,153 @@ +#pragma once + +#include "options.h" + +#include <QApplication> +#include <QCheckBox> +#include <QComboBox> +#include <QDialog> +#include <QDialogButtonBox> +#include <QLabel> +#include <QLineEdit> +#include <QListWidget> +#include <QPlainTextEdit> +#include <QPushButton> +#include <QScrollArea> +#include <QSpinBox> +#include <QTabWidget> +#include <QTextBrowser> +#include <QVariant> + +class AOApplication; + +struct OptionEntry +{ + std::function<void()> load; + std::function<void()> save; +}; + +class AOOptionsDialog : public QDialog +{ + Q_OBJECT + +public: + explicit AOOptionsDialog(AOApplication *p_ao_app, QWidget *parent = nullptr); + +private: + AOApplication *ao_app; + + // Dialog interaction buttons. Save/Discard/Restore Defaults + QDialogButtonBox *ui_settings_buttons; + + // The gameplay tab + QWidget *ui_settings_widget; + QComboBox *ui_theme_combobox; + QComboBox *ui_subtheme_combobox; + QSpinBox *ui_theme_scaling_factor_sb; + QPushButton *ui_theme_reload_button; + QPushButton *ui_theme_folder_button; + QCheckBox *ui_evidence_double_click_cb; + QCheckBox *ui_animated_theme_cb; + QSpinBox *ui_stay_time_spinbox; + QCheckBox *ui_instant_objection_cb; + QSpinBox *ui_text_crawl_spinbox; + QSpinBox *ui_chat_ratelimit_spinbox; + QFrame *ui_log_names_divider; + QLineEdit *ui_username_textbox; + QCheckBox *ui_showname_cb; + QLineEdit *ui_default_showname_textbox; + QFrame *ui_net_divider; + QLineEdit *ui_ms_textbox; + QCheckBox *ui_discord_cb; + QLabel *ui_language_label; + QComboBox *ui_language_combobox; + QLabel *ui_scaling_label; + QComboBox *ui_scaling_combobox; + QCheckBox *ui_shake_cb; + QCheckBox *ui_effects_cb; + QCheckBox *ui_framenetwork_cb; + QCheckBox *ui_colorlog_cb; + QCheckBox *ui_stickysounds_cb; + QCheckBox *ui_stickyeffects_cb; + QCheckBox *ui_stickypres_cb; + QCheckBox *ui_customchat_cb; + QCheckBox *ui_sticker_cb; + QCheckBox *ui_continuous_cb; + QCheckBox *ui_category_stop_cb; + QCheckBox *ui_sfx_on_idle_cb; + + // The callwords tab + QPlainTextEdit *ui_callwords_textbox; + QCheckBox *ui_callwords_char_textbox; + + // The audio tab + QWidget *ui_audio_tab; + QWidget *ui_audio_widget; + QComboBox *ui_audio_device_combobox; + QSpinBox *ui_suppress_audio_spinbox; + QFrame *ui_volume_blip_divider; + QSpinBox *ui_bliprate_spinbox; + QCheckBox *ui_blank_blips_cb; + QCheckBox *ui_loopsfx_cb; + QCheckBox *ui_objectmusic_cb; + QCheckBox *ui_disablestreams_cb; + + // The asset tab + 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; + + // The logging tab + QCheckBox *ui_downwards_cb; + QSpinBox *ui_length_spinbox; + QCheckBox *ui_log_newline_cb; + QSpinBox *ui_log_margin_spinbox; + QLabel *ui_log_timestamp_format_lbl; + QCheckBox *ui_log_timestamp_cb; + QComboBox *ui_log_timestamp_format_combobox; + QCheckBox *ui_desync_logs_cb; + QCheckBox *ui_log_ic_actions_cb; + QCheckBox *ui_log_text_cb; + QCheckBox *ui_log_demo_cb; + + /** + * Allows the AO2 master server hoster to go broke. + */ + QWidget *ui_privacy_tab; + QCheckBox *ui_privacy_optout_cb; + QFrame *ui_privacy_separator; + QTextBrowser *ui_privacy_policy; + + bool asset_cache_dirty = false; + + bool needsDefaultAudioDevice(); + void populateAudioDevices(); + void updateValues(); + + QVector<OptionEntry> optionEntries; + + template <typename T, typename V> + void setWidgetData(T *widget, const V &value); + + template <typename T, typename V> + V widgetData(T *widget) const; + + template <typename T, typename V> + void registerOption(const QString &widgetName, V (Options::*getter)() const, void (Options::*setter)(V)); + +Q_SIGNALS: + void reloadThemeRequest(); + +private Q_SLOTS: + void savePressed(); + void discardPressed(); + void buttonClicked(QAbstractButton *button); + void onTimestampFormatEdited(); + void timestampCbChanged(int state); + void onReloadThemeClicked(); + void themeChanged(int i); + void setupUI(); +}; diff --git a/src/widgets/direct_connect_dialog.cpp b/src/widgets/direct_connect_dialog.cpp index 82eaa23a..40e75b76 100644 --- a/src/widgets/direct_connect_dialog.cpp +++ b/src/widgets/direct_connect_dialog.cpp @@ -1,74 +1,65 @@ -#include "widgets/direct_connect_dialog.h" +#include "direct_connect_dialog.h" +#include "debug_functions.h" +#include "gui_utils.h" #include "networkmanager.h" #include "options.h" -#include "debug_functions.h" -#include <QComboBox> -#include <QLabel> -#include <QLineEdit> -#include <QPushButton> -#include <QSpinBox> +#include <QStringBuilder> #include <QUiLoader> #include <QVBoxLayout> -#include <QRegularExpressionMatch> -#include <QStringBuilder> -#include <QUrl> -#define FROM_UI(type, name) \ - ; \ - ui_##name = findChild<type *>(#name); - -DirectConnectDialog::DirectConnectDialog(NetworkManager *p_net_manager) : - net_manager(p_net_manager) +DirectConnectDialog::DirectConnectDialog(NetworkManager *p_net_manager) + : net_manager(p_net_manager) { - QUiLoader l_loader(this); - QFile l_uiFile(Options::getInstance().getUIAsset(DEFAULT_UI)); + QUiLoader l_loader(this); + QFile l_uiFile(Options::getInstance().getUIAsset(DEFAULT_UI)); - if (!l_uiFile.open(QFile::ReadOnly)) { - qCritical() << "Unable to open file " << l_uiFile.fileName(); - return; - } - ui_widget = l_loader.load(&l_uiFile, this); + if (!l_uiFile.open(QFile::ReadOnly)) + { + qCritical() << "Unable to open file " << l_uiFile.fileName(); + return; + } + ui_widget = l_loader.load(&l_uiFile, this); - auto l_layout = new QVBoxLayout(this); - l_layout->addWidget(ui_widget); + auto l_layout = new QVBoxLayout(this); + l_layout->addWidget(ui_widget); - FROM_UI(QLineEdit, direct_hostname_edit) + FROM_UI(QLineEdit, direct_hostname_edit); - FROM_UI(QLabel, direct_connection_status_lbl) + FROM_UI(QLabel, direct_connection_status_lbl); - FROM_UI(QPushButton, direct_connect_button); - connect(ui_direct_connect_button, &QPushButton::pressed, - this, &DirectConnectDialog::onConnectPressed); - FROM_UI(QPushButton, direct_cancel_button); - connect(ui_direct_cancel_button, &QPushButton::pressed, - this, &DirectConnectDialog::close); + FROM_UI(QPushButton, direct_connect_button); + connect(ui_direct_connect_button, &QPushButton::pressed, this, &DirectConnectDialog::onConnectPressed); + FROM_UI(QPushButton, direct_cancel_button); + connect(ui_direct_cancel_button, &QPushButton::pressed, this, &DirectConnectDialog::close); - connect(net_manager, &NetworkManager::server_connected, - this, &DirectConnectDialog::onServerConnected); + connect(net_manager, &NetworkManager::server_connected, this, &DirectConnectDialog::onServerConnected); - connect(&connect_timeout, &QTimer::timeout, this, - &DirectConnectDialog::onConnectTimeout); - connect_timeout.setSingleShot(true); + connect(&connect_timeout, &QTimer::timeout, this, &DirectConnectDialog::onConnectTimeout); + connect_timeout.setSingleShot(true); } void DirectConnectDialog::onConnectPressed() { QString l_hostname = ui_direct_hostname_edit->text(); - if (!SCHEME_PATTERN.match(l_hostname).hasMatch()) { + if (!SCHEME_PATTERN.match(l_hostname).hasMatch()) + { l_hostname = "tcp://" % l_hostname; } QUrl l_url(l_hostname); - if (!l_url.isValid()) { + if (!l_url.isValid()) + { call_error(tr("Invalid URL.")); return; } - if (!to_connection_type.contains(l_url.scheme())) { + if (!to_connection_type.contains(l_url.scheme())) + { call_error(tr("Scheme not recognized. Must be either of the following: ") % QStringList::fromVector(to_connection_type.keys().toVector()).join(", ")); return; } - if (l_url.port() == -1) { + if (l_url.port() == -1) + { call_error(tr("Invalid server port.")); return; } diff --git a/src/widgets/direct_connect_dialog.h b/src/widgets/direct_connect_dialog.h new file mode 100644 index 00000000..fc34f748 --- /dev/null +++ b/src/widgets/direct_connect_dialog.h @@ -0,0 +1,43 @@ +#pragma once + +#include <QComboBox> +#include <QDialog> +#include <QLabel> +#include <QLineEdit> +#include <QPushButton> +#include <QRegularExpression> +#include <QSpinBox> +#include <QTimer> + +class NetworkManager; + +class DirectConnectDialog : public QDialog +{ + Q_OBJECT + +public: + DirectConnectDialog(NetworkManager *p_net_manager); + ~DirectConnectDialog() = default; + +private Q_SLOTS: + void onConnectPressed(); + void onServerConnected(); + void onConnectTimeout(); + +private: + NetworkManager *net_manager; + + QLineEdit *ui_direct_hostname_edit; + + QLabel *ui_direct_connection_status_lbl; + QPushButton *ui_direct_connect_button; + QPushButton *ui_direct_cancel_button; + + QWidget *ui_widget; + QTimer connect_timeout; + + const int TCP_INDEX = 0; + const QRegularExpression SCHEME_PATTERN{"^\\w+://.+$"}; + const int CONNECT_TIMEOUT = 5 * 1000; + const QString DEFAULT_UI = "direct_connect_dialog.ui"; +}; diff --git a/src/widgets/edit_server_dialog.cpp b/src/widgets/edit_server_dialog.cpp index 109e968f..a302f372 100644 --- a/src/widgets/edit_server_dialog.cpp +++ b/src/widgets/edit_server_dialog.cpp @@ -1,87 +1,75 @@ -#include "widgets/edit_server_dialog.h" +#include "edit_server_dialog.h" + #include "datatypes.h" +#include "gui_utils.h" #include "options.h" -#include <QComboBox> -#include <QDebug> -#include <QDialogButtonBox> #include <QFile> -#include <QLineEdit> -#include <QLabel> -#include <QPlainTextEdit> -#include <QPushButton> -#include <QSpinBox> #include <QUiLoader> #include <QVBoxLayout> -#define FROM_UI(type, name) \ - ; \ - ui_##name = findChild<type *>(#name); - -EditServerDialog::EditServerDialog(int index) : - index(index) // lol +EditServerDialog::EditServerDialog(int index) + : index(index) // lol { - QUiLoader l_loader(this); - QFile l_uiFile(Options::getInstance().getUIAsset(DEFAULT_UI)); + QUiLoader l_loader(this); + QFile l_uiFile(Options::getInstance().getUIAsset(DEFAULT_UI)); - if (!l_uiFile.open(QFile::ReadOnly)) { - qCritical() << "Unable to open file " << l_uiFile.fileName(); - return; - } - ui_widget = l_loader.load(&l_uiFile, this); + if (!l_uiFile.open(QFile::ReadOnly)) + { + qCritical() << "Unable to open file " << l_uiFile.fileName(); + return; + } + ui_widget = l_loader.load(&l_uiFile, this); - auto l_layout = new QVBoxLayout(this); - l_layout->addWidget(ui_widget); + auto l_layout = new QVBoxLayout(this); + l_layout->addWidget(ui_widget); - FROM_UI(QLineEdit, server_display_name_edit); - FROM_UI(QLineEdit, server_hostname_edit); - FROM_UI(QSpinBox, server_port_box); - FROM_UI(QComboBox, server_protocol_box); - FROM_UI(QPlainTextEdit, server_description_edit); - FROM_UI(QDialogButtonBox, server_dialog_button); - connect(ui_server_dialog_button, &QDialogButtonBox::accepted, this, - &::EditServerDialog::onSavePressed); - connect(ui_server_dialog_button, &QDialogButtonBox::rejected, this, - &EditServerDialog::onCancelPressed); + FROM_UI(QLineEdit, server_display_name_edit); + FROM_UI(QLineEdit, server_hostname_edit); + FROM_UI(QSpinBox, server_port_box); + FROM_UI(QComboBox, server_protocol_box); + FROM_UI(QPlainTextEdit, server_description_edit); + FROM_UI(QDialogButtonBox, server_dialog_button); + connect(ui_server_dialog_button, &QDialogButtonBox::accepted, this, &::EditServerDialog::onSavePressed); + connect(ui_server_dialog_button, &QDialogButtonBox::rejected, this, &EditServerDialog::onCancelPressed); - // We don't need you. - FROM_UI(QLabel, server_legacy_lbl); - FROM_UI(QLineEdit, server_legacy_edit); - FROM_UI(QPushButton, server_legacy_load_button); + // We don't need you. + FROM_UI(QLabel, server_legacy_lbl); + FROM_UI(QLineEdit, server_legacy_edit); + FROM_UI(QPushButton, server_legacy_load_button); - ui_server_legacy_lbl->setVisible(false); - ui_server_legacy_edit->setVisible(false); - ui_server_legacy_load_button->setVisible(false); + ui_server_legacy_lbl->setVisible(false); + ui_server_legacy_edit->setVisible(false); + ui_server_legacy_load_button->setVisible(false); - loadEntry(); + loadEntry(); } void EditServerDialog::loadEntry() { - server_type server = Options::getInstance().favorites().at(index); - ui_server_display_name_edit->setText(server.name); - ui_server_hostname_edit->setText(server.ip); - ui_server_port_box->setValue(server.port); - ui_server_description_edit->setPlainText(server.desc); - ui_server_protocol_box->setCurrentIndex(server.socket_type); + server_type server = Options::getInstance().favorites().at(index); + ui_server_display_name_edit->setText(server.name); + ui_server_hostname_edit->setText(server.ip); + ui_server_port_box->setValue(server.port); + ui_server_description_edit->setPlainText(server.desc); + ui_server_protocol_box->setCurrentIndex(server.socket_type); } void EditServerDialog::onSavePressed() { - server_type server; - server.name = ui_server_display_name_edit->text(); - server.ip = ui_server_hostname_edit->text(); - server.port = ui_server_port_box->value(); - server.desc = ui_server_description_edit->toPlainText(); - server.socket_type = - ui_server_protocol_box->currentIndex() == TCP_INDEX ? TCP : WEBSOCKETS; - Options::getInstance().updateFavorite(server, index); - close(); - deleteLater(); + server_type server; + server.name = ui_server_display_name_edit->text(); + server.ip = ui_server_hostname_edit->text(); + server.port = ui_server_port_box->value(); + server.desc = ui_server_description_edit->toPlainText(); + server.socket_type = ui_server_protocol_box->currentIndex() == TCP_INDEX ? TCP : WEBSOCKETS; + Options::getInstance().updateFavorite(server, index); + close(); + deleteLater(); } void EditServerDialog::onCancelPressed() { - close(); - deleteLater(); + close(); + deleteLater(); } diff --git a/src/widgets/edit_server_dialog.h b/src/widgets/edit_server_dialog.h new file mode 100644 index 00000000..628ea606 --- /dev/null +++ b/src/widgets/edit_server_dialog.h @@ -0,0 +1,42 @@ +#pragma once + +#include "interfaces/server_dialog.h" + +#include <QComboBox> +#include <QDialogButtonBox> +#include <QLabel> +#include <QLineEdit> +#include <QPlainTextEdit> +#include <QPushButton> +#include <QSpinBox> + +class EditServerDialog : public AttorneyOnline::UI::FavoriteServerDialog +{ + Q_OBJECT + +public: + EditServerDialog(int index); + ~EditServerDialog() = default; + +private: + QWidget *ui_widget; + + QLineEdit *ui_server_display_name_edit; + QLineEdit *ui_server_hostname_edit; + QSpinBox *ui_server_port_box; + QComboBox *ui_server_protocol_box; + QPlainTextEdit *ui_server_description_edit; + QDialogButtonBox *ui_server_dialog_button; + + // Legacy Server UI + QLabel *ui_server_legacy_lbl; + QLineEdit *ui_server_legacy_edit; + QPushButton *ui_server_legacy_load_button; + + int index; + void loadEntry(); + +private Q_SLOTS: + void onSavePressed() override; + void onCancelPressed() override; +}; |
