From fd1d8a6c04ea301f7366066083e342718a7e2ed7 Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Mon, 31 Oct 2022 00:12:46 +0100 Subject: [PATCH 01/61] Utilise .ui file to create settings dialog (#858) * Remove config loading from AOApplications Removes most, but not all config functions from AOApplication and moves them into their own class. Not even remotely done here. but holy shit I'm tired. * First steps towards UI file * Fixed your UI layout issue * Leifa bullies me * Set all the setters Reminder : Figure out why username and ooc_name exist. Are they the same? Maybe. Maybe not. Gonna have to look at it and migrate the key. Todo : Cleanup key naming. Most of these are terrible, imprecise or I just don't like them. * Make layout appear proper * Minor option dialog update * Hookup AOOptionsdialogue to Options Getter/setter Not done yet, but parts of the options interactions work again. * More settings menu working * Mostly working settings dialogue Restore default and cancel still need work * Fix asset widget * Tooltips Also removes the commented out tooltip code * Finish Tooltips Move widget implementation to its own folder * Migrate callwords to config.ini Also correct sleep deprived code. * Fix widget translation * Language dropdown changes We might want to look into doing this a bit better. * Remove QSettings from AOApplication Try cleaning up stray references to said object anymore * Fix constructor order to prevent runtime crash * Slightly sort implementation file * Remove unused label declarations from header Fix some comments * Formatting * Fix buttons Also fixes restore settings when a restore to default is aborted. * Raise pair list after courtroom construction (#859) * Don't reset evidence selection (#860) They are defaulted in the header. This SHOULD not affect the client negatively. * Hitting the emergency exit (#861) Don't change the widget state when the ID exceeds the current widget list due to pages being changed while evidence is being edited. * add CI and license badge * add contributors * Handle config.temp after confirmation * Deletes config.temp when the user has confirmed they want to keep the current settings. * Make reset to default destructive Don't worry, we ask first! :) * Fix case of self_offset received without a y offset (#864) caused by typos in #701 it's possible for older clients to send x offsets without a y offset. if you think this case is annoying you can remove it in the next version and handle it server-side instead * Change default settings (#839) * Make default config enable features for most cases except for Continuous Playback due to it introducing performance issues according to tooltip and confirmed in testing * Increase log size to 1000 * Default disable animated themes Co-authored-by: Salanto <62221668+Salanto@users.noreply.github.com> Co-authored-by: stonedDiscord * Make it a singleton? Maybe? I dunno? Ask Longbyte * Commit suggestions * More suggestions Also try fixing a memory leak. Not going to well. * Return to dialog Otherwise we don't have Exec. * Cleanup * Deprecate ooc_name, implement username * Remove ooc_name key and copy its value to default_showname if its empty. * Consistent naming in AOOptionsDialog * Clang format * Don't write the username to the showname * Fix theme dropdown being incorrectly set * Bandaid callword playing every message * Remove unused or duplicate includes * More include removals Removes lobby and courtroom direct includes from the dialog source * Burn baby, burn! * Remove reload_theme function * Remove "Case Alert Supported Message" All servers I tested on master supported it. The text is redundant in operation. Co-authored-by: TrickyLeifa Co-authored-by: stonedDiscord Co-authored-by: oldmud0 Co-authored-by: Crystalwarrior --- Attorney_Online.pro | 11 +- include/aoapplication.h | 201 +-- include/aooptionsdialog.h | 273 --- include/courtroom.h | 2 +- include/options.h | 296 ++++ include/widgets/aooptionsdialog.h | 175 ++ resource/translations/ao_de.qm | Bin 43755 -> 45758 bytes resource/translations/ao_de.ts | 2628 +++++++++++++---------------- resource/ui/options_dialog.ui | 1302 ++++++++++++++ resources.qrc | 1 + src/aoapplication.cpp | 30 +- src/aobutton.cpp | 7 +- src/aoimage.cpp | 9 +- src/aolayer.cpp | 16 +- src/aomusicplayer.cpp | 5 +- src/courtroom.cpp | 158 +- src/emotes.cpp | 3 +- src/evidence.cpp | 5 +- src/lobby.cpp | 2 - src/main.cpp | 4 +- src/networkmanager.cpp | 7 +- src/options.cpp | 620 +++++++ src/packet_distribution.cpp | 9 +- src/path_functions.cpp | 10 +- src/text_file_functions.cpp | 426 +---- src/widgets/aooptionsdialog.cpp | 651 +++++++ 26 files changed, 4351 insertions(+), 2500 deletions(-) delete mode 100644 include/aooptionsdialog.h create mode 100644 include/options.h create mode 100644 include/widgets/aooptionsdialog.h create mode 100644 resource/ui/options_dialog.ui create mode 100644 src/options.cpp create mode 100644 src/widgets/aooptionsdialog.cpp diff --git a/Attorney_Online.pro b/Attorney_Online.pro index a7815d030..1bb32c1b1 100644 --- a/Attorney_Online.pro +++ b/Attorney_Online.pro @@ -1,4 +1,4 @@ -QT += core gui widgets network websockets +QT += core gui widgets network websockets uitools TARGET = Attorney_Online TEMPLATE = app @@ -10,8 +10,10 @@ DESTDIR = $$PWD/bin OBJECTS_DIR = $$PWD/build MOC_DIR = $$PWD/build -SOURCES += $$files($$PWD/src/*.cpp) -HEADERS += $$files($$PWD/include/*.h) +SOURCES += $$files($$PWD/src/*.cpp, true) +HEADERS += $$files($$PWD/include/*.h, true) + +FORMS += $$files($$PWD/resource/ui/*.ui) LIBS += -L$$PWD/lib QMAKE_LFLAGS += -Wl,-rpath,"'\$$ORIGIN/lib'" @@ -57,7 +59,8 @@ TRANSLATIONS = resource/translations/ao_en.ts \ resource/translations/ao_es.ts \ resource/translations/ao_pt.ts \ resource/translations/ao_pl.ts \ - resource/translations/ao_it.ts + resource/translations/ao_it.ts \ + ressource/ui/ win32:RC_ICONS = resource/logo_ao2.ico macx:ICON = resource/logo_ao2.icns diff --git a/include/aoapplication.h b/include/aoapplication.h index 16895d858..252693627 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -1,6 +1,7 @@ #ifndef AOAPPLICATION_H #define AOAPPLICATION_H +#include "widgets/aooptionsdialog.h" #include "aopacket.h" #include "datatypes.h" #include "demoserver.h" @@ -34,6 +35,7 @@ class NetworkManager; class Lobby; class Courtroom; +class Options; class VPath : QString { using QString::QString; @@ -141,9 +143,6 @@ class AOApplication : public QApplication { void set_server_list(QVector &servers) { server_list = servers; } QVector &get_server_list() { return server_list; } - // reads the theme from config.ini and sets it accordingly - void reload_theme(); - // Returns the character the player has currently selected QString get_current_char(); @@ -173,147 +172,6 @@ class AOApplication : public QApplication { ////// Functions for reading and writing files ////// // Implementations file_functions.cpp - // Instead of reinventing the wheel, we'll use a QSettings class. - QSettings *configini; - - // Reads the theme from config.ini and loads it into the current_theme - // variable - QString read_theme(); - - // Returns the value of ooc_name in config.ini - QString get_ooc_name(); - - // Returns the blip rate from config.ini (once per X symbols) - int read_blip_rate(); - - // Returns true if blank blips is enabled in config.ini and false otherwise - bool get_blank_blip(); - - // Returns true if looping sound effects are enabled in the config.ini - bool get_looping_sfx(); - - // Returns true if stop music on objection is enabled in the config.ini - bool objection_stop_music(); - - // Returns true if streaming is enabled in the config.ini - bool is_streaming_disabled(); - - // Returns the value of default_music in config.ini - int get_default_music(); - - // Returns the value of default_sfx in config.ini - int get_default_sfx(); - - // Returns the value of default_blip in config.ini - int get_default_blip(); - - // Returns the value of suppress_audio in config.ini - int get_default_suppress_audio(); - - // Returns the value if objections interrupt and skip the message queue - // from the config.ini. - bool is_instant_objection_enabled(); - - // returns if log will show messages as-received, while viewport will parse according to the queue (Text Stay Time) - // from the config.ini - bool is_desyncrhonized_logs_enabled(); - - // Returns the value of whether Discord should be enabled on startup - // from the config.ini. - bool is_discord_enabled(); - - // Returns the value of whether shaking should be enabled. - // from the config.ini. - bool is_shake_enabled(); - - // Returns the value of whether effects should be enabled. - // from the config.ini. - bool is_effects_enabled(); - - // Returns the value of whether frame-specific effects defined in char.ini - // should be sent/received over the network. from the config.ini. - bool is_frame_network_enabled(); - - // Returns the value of whether colored ic log should be a thing. - // from the config.ini. - bool is_colorlog_enabled(); - - // Returns the value of whether sticky sounds should be a thing. - // from the config.ini. - bool is_stickysounds_enabled(); - - // Returns the value of whether sticky effects should be a thing. - // from the config.ini. - bool is_stickyeffects_enabled(); - - // Returns the value of whether sticky preanims should be a thing. - // from the config.ini. - bool is_stickypres_enabled(); - - // 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 is_customchat_enabled(); - - // Returns the value of characer sticker (avatar) setting - bool is_sticker_enabled(); - - // Returns the value of whether continuous playback should be used - // from the config.ini. - bool is_continuous_enabled(); - - // Returns the value of whether stopping music by double clicking category should be used - // from the config.ini. - bool is_category_stop_enabled(); - - // Returns the value of the maximum amount of lines the IC chatlog - // may contain, from config.ini. - int get_max_log_size(); - - // Current wait time between messages for the queue system - int stay_time(); - - // Returns the letter display speed during text crawl in in-character messages - int get_text_crawl(); - - // Returns Minimum amount of time (in miliseconds) that must pass before the next Enter key press will send your IC message. (new behaviour) - int get_chat_ratelimit(); - - // Returns whether the log should go upwards (new behaviour) - // or downwards (vanilla behaviour). - bool get_log_goes_downwards(); - - // Returns whether the log should separate name from text via newline or : - bool get_log_newline(); - - // Get spacing between IC log entries. - int get_log_margin(); - - // Returns whether the log should have a timestamp. - bool get_log_timestamp(); - - // Returns the format string for the log timestamp - QString get_log_timestamp_format(); - - // Returns whether to log IC actions. - bool get_log_ic_actions(); - - // Returns the username the user may have set in config.ini. - QString get_default_username(); - - // Returns the audio device used for the client. - QString get_audio_output_device(); - - // Returns whether the user would like to have custom shownames on by default. - bool get_showname_enabled_by_default(); - - //Returns the showname the user may have set in config.ini. - QString get_default_showname(); - - // Returns the list of words in callwords.ini - QStringList get_call_words(); - // returns all of the file's lines in a QStringList QStringList get_list_file(VPath path); QStringList get_list_file(QString p_file); @@ -505,62 +363,11 @@ class AOApplication : public QApplication { // These are all casing-related settings. // ====== - // Returns if the user has casing alerts enabled. - bool get_casing_enabled(); - - // Returns if the user wants to get alerts for the defence role. - bool get_casing_defence_enabled(); - - // Same for prosecution. - bool get_casing_prosecution_enabled(); - - // Same for judge. - bool get_casing_judge_enabled(); - - // Same for juror. - bool get_casing_juror_enabled(); - - // Same for steno. - bool get_casing_steno_enabled(); - - // Same for CM. - bool get_casing_cm_enabled(); - - // Get the message for the CM for casing alerts. - QString get_casing_can_host_cases(); - - // Get if text file logging is enabled - bool get_text_logging_enabled(); - - // Get if demo logging is enabled - bool get_demo_logging_enabled(); - - // Get the subtheme from settings - QString get_subtheme(); - - // Get if the theme is animated - bool get_animated_theme(); - - // Get the default scaling method - QString get_default_scaling(); - - // Get a list of custom mount paths - QStringList get_mount_paths(); - - // Get whether to opt out of player count metrics sent to the master server - bool get_player_count_optout(); - - // Get if sfx can be sent to play on idle - bool get_sfx_on_idle(); - - // Whether opening evidence requires a single or double click - bool get_evidence_double_click(); - // Currently defined subtheme QString subtheme; - QString default_theme = "default"; - QString current_theme = default_theme; + //Default is always default. + const QString default_theme = "default"; // The file name of the log file in base/logs. QString log_filename; diff --git a/include/aooptionsdialog.h b/include/aooptionsdialog.h deleted file mode 100644 index be305d216..000000000 --- a/include/aooptionsdialog.h +++ /dev/null @@ -1,273 +0,0 @@ -#ifndef AOOPTIONSDIALOG_H -#define AOOPTIONSDIALOG_H - -#include "aoapplication.h" -#include "bass.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -class Lobby; -class Courtroom; - -class AOOptionsDialog : public QDialog { - Q_OBJECT -public: - explicit AOOptionsDialog(QWidget *parent = nullptr, - AOApplication *p_ao_app = nullptr); - -private: - AOApplication *ao_app; - - QVBoxLayout *ui_vertical_layout; - QTabWidget *ui_settings_tabs; - - QWidget *ui_gameplay_tab; - QWidget *ui_form_layout_widget; - QFormLayout *ui_gameplay_form; - - QLabel *ui_theme_label; - QComboBox *ui_theme_combobox; - QLabel *ui_subtheme_label; - QComboBox *ui_subtheme_combobox; - QPushButton *ui_theme_reload_button; - QPushButton *ui_theme_folder_button; - QLabel *ui_evidence_double_click_lbl; - QCheckBox *ui_evidence_double_click_cb; - QLabel *ui_animated_theme_lbl; - QCheckBox *ui_animated_theme_cb; - QFrame *ui_theme_log_divider; - QLabel *ui_stay_time_lbl; - QSpinBox *ui_stay_time_spinbox; - QLabel *ui_instant_objection_lbl; - QCheckBox *ui_instant_objection_cb; - QLabel *ui_text_crawl_lbl; - QSpinBox *ui_text_crawl_spinbox; - QLabel *ui_chat_ratelimit_lbl; - QSpinBox *ui_chat_ratelimit_spinbox; - QFrame *ui_log_names_divider; - QLineEdit *ui_username_textbox; - QLabel *ui_username_lbl; - QLabel *ui_showname_lbl; - QCheckBox *ui_showname_cb; - QLabel *ui_default_showname_lbl; - QLineEdit *ui_default_showname_textbox; - QFrame *ui_net_divider; - QLabel *ui_ms_lbl; - QLineEdit *ui_ms_textbox; - QLabel *ui_discord_lbl; - QCheckBox *ui_discord_cb; - QLabel *ui_language_label; - QComboBox *ui_language_combobox; - QLabel *ui_scaling_label; - QComboBox *ui_scaling_combobox; - - QLabel *ui_shake_lbl; - QCheckBox *ui_shake_cb; - QLabel *ui_effects_lbl; - QCheckBox *ui_effects_cb; - QLabel *ui_framenetwork_lbl; - QCheckBox *ui_framenetwork_cb; - - QLabel *ui_colorlog_lbl; - QCheckBox *ui_colorlog_cb; - - QLabel *ui_stickysounds_lbl; - QCheckBox *ui_stickysounds_cb; - - QLabel *ui_stickyeffects_lbl; - QCheckBox *ui_stickyeffects_cb; - - QLabel *ui_stickypres_lbl; - QCheckBox *ui_stickypres_cb; - - QLabel *ui_customchat_lbl; - QCheckBox *ui_customchat_cb; - - QLabel *ui_sticker_lbl; - QCheckBox *ui_sticker_cb; - - QLabel *ui_continuous_lbl; - QCheckBox *ui_continuous_cb; - - QLabel *ui_category_stop_lbl; - QCheckBox *ui_category_stop_cb; - - QLabel *ui_sfx_on_idle_lbl; - QCheckBox *ui_sfx_on_idle_cb; - - QWidget *ui_callwords_tab; - QWidget *ui_callwords_widget; - QVBoxLayout *ui_callwords_layout; - QPlainTextEdit *ui_callwords_textbox; - QLabel *ui_callwords_explain_lbl; - QCheckBox *ui_callwords_char_textbox; - - QWidget *ui_audio_tab; - QWidget *ui_audio_widget; - QFormLayout *ui_audio_layout; - QLabel *ui_audio_device_lbl; - QComboBox *ui_audio_device_combobox; - QFrame *ui_audio_volume_divider; - QSpinBox *ui_music_volume_spinbox; - QLabel *ui_music_volume_lbl; - QSpinBox *ui_sfx_volume_spinbox; - QSpinBox *ui_blips_volume_spinbox; - QSpinBox *ui_suppress_audio_spinbox; - QLabel *ui_sfx_volume_lbl; - QLabel *ui_blips_volume_lbl; - QLabel *ui_suppress_audio_lbl; - QFrame *ui_volume_blip_divider; - QSpinBox *ui_bliprate_spinbox; - QLabel *ui_bliprate_lbl; - QCheckBox *ui_blank_blips_cb; - QLabel *ui_blank_blips_lbl; - QLabel *ui_loopsfx_lbl; - QCheckBox *ui_loopsfx_cb; - QLabel *ui_objectmusic_lbl; - QCheckBox *ui_objectmusic_cb; - QLabel *ui_disablestreams_lbl; - QCheckBox *ui_disablestreams_cb; - QDialogButtonBox *ui_settings_buttons; - - QWidget *ui_casing_tab; - QWidget *ui_casing_widget; - QFormLayout *ui_casing_layout; - QLabel *ui_casing_supported_lbl; - QLabel *ui_casing_enabled_lbl; - QCheckBox *ui_casing_enabled_cb; - QLabel *ui_casing_def_lbl; - QCheckBox *ui_casing_def_cb; - QLabel *ui_casing_pro_lbl; - QCheckBox *ui_casing_pro_cb; - QLabel *ui_casing_jud_lbl; - QCheckBox *ui_casing_jud_cb; - QLabel *ui_casing_jur_lbl; - QCheckBox *ui_casing_jur_cb; - QLabel *ui_casing_steno_lbl; - QCheckBox *ui_casing_steno_cb; - QLabel *ui_casing_cm_lbl; - QCheckBox *ui_casing_cm_cb; - QLabel *ui_casing_cm_cases_lbl; - QLineEdit *ui_casing_cm_cases_textbox; - - QWidget *ui_assets_tab; - QVBoxLayout *ui_assets_tab_layout; - QGridLayout *ui_mount_buttons_layout; - QLabel *ui_asset_lbl; - QListWidget *ui_mount_list; - QPushButton *ui_mount_add; - QPushButton *ui_mount_remove; - QPushButton *ui_mount_up; - QPushButton *ui_mount_down; - QPushButton *ui_mount_clear_cache; - - QWidget *ui_logging_tab; - QWidget *ui_form_logging_widget; - QFormLayout *ui_logging_form; - - /** - * Option for log direction. Supported options are downwards and wrong way. - */ - QLabel *ui_downwards_lbl; - QCheckBox *ui_downwards_cb; - - /** - * Option for log length. Controls how many IC-log entries are kept before it autowraps. - */ - QLabel *ui_length_lbl; - QSpinBox *ui_length_spinbox; - - /** - * Option for log newline. Controls if the IC-log contains newlines or as one consecutive string. - */ - QLabel *ui_log_newline_lbl; - QCheckBox *ui_log_newline_cb; - - /** - * Option for log margin. Controls how many pixels are between each log entry. - */ - QLabel *ui_log_margin_lbl; - QSpinBox *ui_log_margin_spinbox; - - /** - * Option for timestamp format. A checkmark to enable the timestamp dropdown. - * Why does this exist? Are we Dorico now? - */ - QLabel *ui_log_timestamp_lbl; - QCheckBox *ui_log_timestamp_cb; - - /** - * Option for timestamp format. Dropdown to select the preferred format. - */ - QLabel *ui_log_timestamp_format_lbl; - QComboBox *ui_log_timestamp_format_combobox; - - /** - * Option for desynched IC-log and viewport. Controls if entires are appended to the IC-log before displayed in the viewport. - */ - QLabel *ui_desync_logs_lbl; - QCheckBox *ui_desync_logs_cb; - - /** - * Option for logging IC-actions. Will add shouts, evidence or music changes to the IC-log. - */ - QLabel *ui_log_ic_actions_lbl; - QCheckBox *ui_log_ic_actions_cb; - - /** - * Option to enable logging. If enabled client will save all messages to the log folder. - */ - QLabel *ui_log_text_lbl; - QCheckBox *ui_log_text_cb; - - /** - * Option to enable demo logging. If enabled, client will save a demo file for replay trough the demo server. - */ - QLabel *ui_log_demo_lbl; - QCheckBox *ui_log_demo_cb; - - QWidget *ui_privacy_tab; - QVBoxLayout *ui_privacy_layout; - QCheckBox *ui_privacy_optout_cb; - QFrame *ui_privacy_separator; - QTextBrowser *ui_privacy_policy; - - bool asset_cache_dirty = false; - - bool needs_default_audiodev(); - void update_values(); - -signals: - -public slots: - void save_pressed(); - void discard_pressed(); - void button_clicked(QAbstractButton *button); - void on_timestamp_format_edited(); - void timestamp_cb_changed(int state); - void on_reload_theme_clicked(); - void theme_changed(int i); -}; - -#endif // AOOPTIONSDIALOG_H diff --git a/include/courtroom.h b/include/courtroom.h index d767f0afe..6e9a4c97a 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -12,7 +12,7 @@ #include "aoimage.h" #include "aolayer.h" #include "aomusicplayer.h" -#include "aooptionsdialog.h" +#include "widgets/aooptionsdialog.h" #include "aopacket.h" #include "aosfxplayer.h" #include "aotextarea.h" diff --git a/include/options.h b/include/options.h new file mode 100644 index 000000000..fe37dc6cc --- /dev/null +++ b/include/options.h @@ -0,0 +1,296 @@ +#ifndef OPTIONS_H +#define OPTIONS_H + + +#include +#include + +class Options { +private: + /** + * @brief QSettings object for config.ini + */ + QSettings config; + + void migrateCallwords(); + + /** + * @brief Constructor for options class. + */ + Options(); + +public: + Options(Options const &) = delete; + void operator=(Options const &) = 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); + + // Returns the value of oocname in config.ini + QString oocName() const; + void setOocName(QString 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); + + // Returns if the user has casing alerts Enabled. + bool casingAlertEnabled() const; + void setCasingAlertEnabled(bool value); + + // Returns if the user wants to get alerts for the defence role. + bool casingDefenceEnabled() const; + void setcasingDefenceEnabled(bool value); + + // Same for prosecution. + bool casingProsecutionEnabled() const; + void setCasingProseuctionEnabled(bool value); + + // Same for judge. + bool casingJudgeEnabled() const; + void setCasingJudgeEnabled(bool value); + + // Same for juror. + bool casingJurorEnabled() const; + void setCasingJurorEnabled(bool value); + + // Same for steno. + bool casingStenoEnabled() const; + void setCasingStenoEnabled(bool value); + + // Same for CM. + bool casingCmEnabled() const; + void setCasingCmEnabled(bool value); + + // Get the message for the CM for casing alerts. + QString casingCanHostCases() const; + void setCasingCanHostCases(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; + void setSubTheme(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(); +}; + +#endif // OPTIONS_H diff --git a/include/widgets/aooptionsdialog.h b/include/widgets/aooptionsdialog.h new file mode 100644 index 000000000..21fc322b6 --- /dev/null +++ b/include/widgets/aooptionsdialog.h @@ -0,0 +1,175 @@ +#ifndef AOOPTIONSDIALOG_H +#define AOOPTIONSDIALOG_H + +#include "options.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +class AOApplication; + +struct OptionEntry { + std::function load; + std::function save; +}; + +class AOOptionsDialog : public QDialog { + Q_OBJECT +public: + explicit AOOptionsDialog(QDialog *parent = nullptr, + AOApplication *p_ao_app = 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; + 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; + QFormLayout *ui_audio_layout; + QComboBox *ui_audio_device_combobox; + QSpinBox *ui_music_volume_spinbox; + QSpinBox *ui_sfx_volume_spinbox; + QSpinBox *ui_blips_volume_spinbox; + 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 casing tab + QGroupBox *ui_casing_enabled_box; + QCheckBox *ui_casing_def_cb; + QCheckBox *ui_casing_pro_cb; + QCheckBox *ui_casing_jud_cb; + QCheckBox *ui_casing_jur_cb; + QCheckBox *ui_casing_steno_cb; + QCheckBox *ui_casing_cm_cb; + QLineEdit *ui_casing_cm_cases_textbox; + + // 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; + QVBoxLayout *ui_privacy_layout; + 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 optionEntries; + + template + void setWidgetData(T *widget, const V &value); + + template V widgetData(T *widget) const; + + template + void registerOption(const QString &widgetName, V (Options::*getter)() const, + void (Options::*setter)(V)); + +signals: + void reloadThemeRequest(); + +private slots: + void savePressed(); + void discardPressed(); + void buttonClicked(QAbstractButton *button); + void onTimestampFormatEdited(); + void timestampCbChanged(int state); + void onReloadThemeClicked(); + void themeChanged(int i); +}; + +#endif // AOOPTIONSDIALOG_H diff --git a/resource/translations/ao_de.qm b/resource/translations/ao_de.qm index 0b914aa15bf739e217fc9c44872dd1f1dc1e9a19..0c5e8fd90685af6077b78a2cc4e25041fe4ba809 100644 GIT binary patch delta 9534 zcmb7J2YeLO)<0X4E!pf+5|U8DgkF-6Kxhd>Lka{!f`k%`lu34yEZN;jwj_W)mLe8F z+9>TIA~rw;bX9DRXM<1lJrwdjDR(U#}qljByB-&6&J)*F-#!qR1i9`(&4clfW zTKEW!-}nXvs8UN4Ui^*7vz`jmyhPSBH1UN4M2TyuXiEiA?<2~y)=0(A-wuI4)3hV! zA+QV0w7yJa8b>!TJxEk=50!tPN;JSnx4g5Rs9zI#x2++1;2m1Ea|=;cN80Lqi>NVz zc8ty@ifyJxwigFr!Xxz9xpboLooM%~`0%Kn4jjPqMmrt;=oHbNC3I|HGtr{I(}kq% zL{m0vjN*Et+*dWm*SEr=p_-_sIYh}zG}ehX5p~|B=}0=FZo4%jR$zYjy_(`fPZOl9JPe9d>8_YxV)H5Zu0i7#stxXDEN7qv;t0l7CyJ3%~1l(9uyejC1L zCTsmqK@ms1w(-&)ApM5+wuF_KSE^kexE&w5_SW7#a52$?&uH&{bt%ydyLLmjW@xxr z`)mpX**a(sHSj=+lxO8<+Ao@R5_LGB{q7sMXz+8|pM!vQDO16%+NS*OfG2;phh4%>8jh8l&>8 zdO_#NUj)c9biNE|?6c@z-1Rwp++X+JCkVFnKj}Wcb3W0k;kq;PCPINU-G#F6iS8Jy zyU4z0OwvbAdwrzV2zW+4h;i_H8lJ_H?te68=@ezApUrDt6V#GhwVu=FPuE>7V z)&rtVktrjxk?&EF^D<+ICcGc%-MpBncxL4C6R8;A7K6udhn8YUQD?wLrmtAp|Fw8hA}<;JFSf$tGCcH@bkpt1P}<7q=SCT>)o>objCE}H|5 zmm9xIvl5k8nDiwbk%W(%I(NXj`)@U+92tjf$uf;$!Pe<3)7T#}kqu`}<8J+wX#RRr z{)T3vb#Iy`J$Z!4FxynL)cl6epS^EE;2ow*FG9iImrTDnUL^82 zn3Kj}-D5YH`<`Dz;a{I5cN_xVmvovqR_Z6F>^>Y!_0|!UjirqvTM@AR*NC!f;=(5dt z4-}t|p38`)?*3@|gYad&A$sYSR1nN3(OajS$HuPcf8CcuG|d_P{;!Edi;qQrFzXXg zs4e=7wOH4f6a7{Hr@-lZqQAWi3;SxKznf-7uss%iHM$qlOmDSWcYt_etetx{6W!~w zrs*C5BQ{vmT-nI~hlgA9mSqCUrPjqC9woYOgZ0iY?O3?QdiS|vqH$5y2iC!os3zrE zIncW6-bO&jS)X3C{*K_*+;7urlaT+D<88JNPJw7%w~Zf;1-HF!oACV22(F&C=^q|Lc^zY$ z_t_j|$4j=Vd!a}|lFgk93&tI`JtzUO%|F{7yY(OtId0q66GYQH+jjT{AlIkT_V!5Z z8#rz|ZYw6bYpSiukqu%RX#4j{%+D{i{V=^NxIO>4?ZVPeksgO^SF<3v_6(AAcW3Ek z<1Hf+DUSqlkw_fPBnN)m@#mpx;;DiJBP+_0_>0aHTq0NJIWl(uk*%Dyarfjv64%Bmef`jVC`}cvrGWGVjQ9WyGt`g$6vH{Hg+gxpW3VyE z+?c}vW56<3uz4OCs#Zv^!9%GbUASD)@9buG_xEwtf{*jnFkl=FeC0x}PINjd7fP>k zT`O;d`MeA*bK0NNG?nl#BrjpS;PW}$)$OFDrZPFEv}-VP5jUPL-Ql1I2H&__PKBnqV_CcVt(cD z=a9i;p7zQkC9<>J`0WWTk0}+LLZy%65lLPF;+%HD!*=UtmLr9!=L^k_EOm*ZuZDe> zvS-?Z1!Z4Y9ZP5uL^2Q6LhK^=#U+ckV~ly1`HJ}|6{C6h{i{5asaQ^BG`r0jFH(r9 ztt5v>R-XkuGX%RxIbvL9E8c0jaAGaz6FI@|@TGE7Jc8HDm6y$CL;gBD?-N)`c(}?M z-d!ztr5tBW+|V}4D#0TwEbUt#o5)mb>(CC@36S=ebqOX{uhnR#NlWWH2UsF7MOg}@ z$|^c&AdG1ntSnHg)|VXf`=Qxex^Fy zj)5!?xW4HI(2ohzJwEA|dQ#wYYr>gu;<`GS*l(arJg0YcTTGu%yHY6`*GG_7B0_Sk2NUzN8 zuE}6CM~N`h2l@~pEhXdu9={k}v_^J(%W~20OA)K&Eu?psM+Q$fNP{)W(koGM>5Ol^ zGMz9^tj0fIn}m*;1ww5UJOU%aYQfHleyM(0tmNJ4861P)EutJipHIbd5V!THrM##l zC$F%0{A~D4_QK~oi!_1NG~*gfzd{sCOr|o2kW|QC;ZzYSfe`?Rh#7WD#ta5%+xI%W z@w8C>R)=5A3_*TljIw~{qRjAcj87h8!H4(=Kq%XcRURkRg@De>Y2Y1BzQQSRm7>eV zyY1dgvs2{l$tWMnlNGyUu8#M6g=EgfFPPiNJABC~JczPnu10XyvB)&D!dNPJ8U&9< zhxe^=WGV#}+!~P0bwC4_&Ingo4~2XcdML#RD=Q3?As_?ANDe@-oXN(Y!f7Q`Lb-TT zsD=>@TM?#aW0d7LCx>#NT3*hCLtM!G{9M1sBe;FA24%g<0T>js1$!!2Dj*?;F!MPi zU^ZfrD=Eok3{xSnaBk@WQp4Gwi~y;H(SAsDl5-*+%#QXhVpgFLh7{`DqEHLaoWt90 zdnx(h(!lL);QcdLGJO9C&;JX@YcNh~hhvu97RmUrp!rkiNwp782@FCav{bDIgfA;9 zExH!MWh_~g(w`K*jOdfR?Cj(Kin}g#tem_e?@7H-c-RKq%$|c)334TQ*~X|NjYfC9PP% zv%ZQIrj`y$3;{U=uqwRLvS&+uMMYCKV7b)N3bAZeGUy`swo0DSHhK7|0$*7JZe;Bh z%N4Oo{u#=pKT07KY#;9dk07;%I0Fb8mRMq);D$@xLZh6FVIfcc9dEJ%#H?m)$hyqy z-PviX;PtzH&!2%1Z>7pkQPwN1yj)!Y#boSnm+@_Zr7i8pmtN}tWnM&2j>a4YDP_Ao zIrh3v2sj~d9dFC~hr+yb%g!N6@QLA~d=#3tU*Tcacd=Aqq{xC!sWV=TvOwkJKE5?3 z(ugG#&V}rB6F)=FC1jKzodJ*Pm(Ki?7B;K8Bgh@Ng*i4dHqgqb(JqJ6>G0y{fl?CI ze@o!=E#jVE^767aW zw(>h`1c~%ZnM)kh;uy-Zn+5kK7}+ zJ(Q)}efR z9U^kDr7g&0UCgD&9_rmmW;!2ufCZIYNJAkSIThuzL6BDO+CM6>o#0G}h8X;J03}iD zanUwI5yb>>1CjgAbNBPlR`RbOD3_29d62V@aXBr`F%doJx*L8y|SQ}v}ku> z?=fiW3Si^}G6@qAyKvqb9OrnK5Q6eLBrV;isx%08uT+io?UAAy z<9o~rgwrYw{ep;AiXGpbXn9+&16t0zjKJB=7wdF|Htz3|&+^w@DR6nBpPfMDGj~|c z<E6&%51gSM*% zr9&y3+V34K7^2gJ-TYo`-dkFl_ICRvQhEAosL%Ba0T+s+wW3pMVpP;HK?5u7@J85bB(*?|3ixSJYk(sGnc()cpV`(KCZ+CTA?h8JY^-%bv zd_ode#Y%x2eo-mH$|>dpQGp1KYXO#&_8I{N)%B@)H;Ik_ORfQjJ-T_49vIEllh~l+mDaZ9GS`_FGl;U2t&K z{i^C4bBLOUs5Ug-B-;LvO8!Ui8z_!b9WT8|6rZd5@tt;}*$=9&uoK!&sjj}0L3C%c zI%yd~YPqBy{^IvU6P{7$c#aa)j8@NEf_3%B)wS35;{9IrlEg-&ZmfFsum+@Ykb3oN zONq90sGItB5Ixpg{d~%PqGGH1jT##wK;*(a4r=b6*-rGp7)?gfXc#!9$=4JREjX$vtiiha9-27^6QJ)UMYi_SIHoK{ z1V(72JK<2zM$M7k=aI6hns>GUQ?9Qx|2hNAjIwKjpRZg9gO@a4EyyDp{-fr~{TGRD zU!%Fo76i^~b$Ne9j_b9CpN|qPj?+$zg@c)&X>%WEircl*696Xdv)YG0yAubPt9|76 zxkPoxwJQ!FGP*U|m8TFn<7sV^;W>czS#6Wp49D8FvL1GO)CIL$b6-X-MrgOTp#pji zROIYk+7=x`b>Ba=FI0VnoPDT0oreerhqYf^1?r`N+8;(n!r=qjs}kmW_l@Yg4-O4` zKce5`4`ALHk>3gfY4ajxAJ|N^^XCYgCL5KuFXHh9aL6(!;)zwLy!zl)<)QWSh?bVu zf!6wn{l}mv`=f||rp2Qyt8}*)1ALCdx|A^)L@p~8mo2wtqnx$FX@(@!buDF z=~gs;iV$Dbt$Dr}pnG2TH)jVTF;92A-wq;kmhO|EONf%c*PR=O6h7Lb`(-jB5uBW) zyEbtEk$t9q;CRT*oAk3n?-7|U=^x61;gunM$$mQwpM{iQXpDaTq-xAx(A%$jP{*(8 z7oKcKPHp;z80=g1x_-^0`@kD#^-ZgdFtA%M57-XL71_*!ApNvaI z{in~+pPF!#DDjH^i#{MC@udFx_+OFJ2*U{DIHHM@4XKNe56Q zhs?(MUf&y2-kuE9Uo@sOtjxJ-obVGIPHrxL^F38AB-v? zTH!K^>!5Gv0b`>!2## z@!$S;U|_QG+7UBRMQ`J8jw3knmB^%Y?3=bPa>(U%L{Uc~)9!?$8;2@#=cLHHN|3Ty zt0U{D%mk*IBbWca2a!-mZVtx4!_;phTZ~JIwuK@O9(o=T*dO`wTI9O)-pG%O0LBr8 zkzbvS!-hv9&rgNHw2hJ160`_yQB+(Kay(;a)Np$Pk^D^5=wooeelhAv-B{$hI_jAU z5S*?@)ZPF94`6rT>ruhi3bA2oT+~|$%_yJhsDC^(92EOp)U}3G zqO#4Vz8z4UyV#V{=MtL9o2GjfwG-X_o@v~u45BGfrhAjol$M_{6+Z+5oBf_iw7QA1 zE|?arDo zJ=o}3V>)|g79vq^x?ZxMXmz8hqXqAWL`G}p1B}l5qAdk5I5sjmzyBRL*`Db8w_?2E zvFPUMm$6?T{o&?JqQ`a7AKw^2)bID`uh%a`GkQAu$LnysGME(od-Nb8&0%xwzz(7@ zd(3H?r$9K8In9+pl=q}L`w?Ja_ylvqr|%KnBbrx!gL2g7n^*r_fVTXUxpe~^n*O~a zTLzhTZ>mMAj+p;C0_&&jH$S)hBGI5;=0j@{di6B(-^U}8j%@RPZ(oP<^gU-jbs7u% zUNT?02Xc|YeDhVHS~cCGRwogyd(JYIb+0}@S#n-@0ASm0nf2)jG^f>;1!qgZ;on-y zH^G6Ddo1oOIR5AY%T5^}op8}|U?9r5yu=dPw-?n^WjQ_(5vf>adH3#iqW&G04=e?g zMnl^yCmk6G;SI}ojYm-)7c4)`0%fjrTCObp5-6T;`F%VL8&{)-b`6zRxN_wS#@Nub z$myz3k;$SCJ!_t;PMAajrQqL2RU}b>L~`O!lqZc&)Cg26?<`B`ogkzL_lcrcC=2*} zqFWODq9i%o74nIg-a*w{lunh{>%zVa{wzY9oksFeDS7Z*hv%u}pi)@!V@9AFjF>GE z&zX=m@%+W=HEzgSzE*&q07fpXDdQGJ=t`6*6_Zo3!9!8|4$e zgrEaUB(ACgCY*fjy>x@CUkC$s?!X-EWo8AK3*2IwIrji}gE^Xn!AF=&PH9iF@SSP2Z+X`S4u8tMtY@avyaS3FZI~#GN!mC(I?pa zg3IQv6UuB(XRXI)_p_NgPe7>k1e|uk>8KJ@h2qMf=obZ>PsBPrINW~G?RQ9y8oZol zs}co&0PiG^;1q2&q9E3YzHXIRE;uB=;Hh;(pIb~yFZE?)djz*f>RfN*^FpmdsuXO3 z-)k#_F-edrp~`I+Qc{E>?vlgl6iV^RDf%SQu9%S=E|~YYM2}k(0)7z(=+pqS(BSY1 zF46C|Rfzu7^pX7J=_7eG0Omw_O<ncLl9^PQYn!*wQQUUOET-090K|bXhjPQh132Ow{%M7A1ORg`()tpOoVm8nU=A^Ban} ze6w?W&Ke`91@Go_p9QBenbL=5a}2X0bO5dnsz6P+@!RdGAzLg*%0

_=iilhJ6nY zyOEG1;qmW^Q(#x|M*`z4en9zlL%qEpp3IT5_OSh_0u3kP;eskGc76VliMi0qvJi3LAWbg8C`0Oe^ z`}T?re6)d&-d)+uM~!^+@v8N=j6PW%U?bVq_%@drYrbSMG8mZ@3VXN={d|P!_`*;>sAt4T`Jew8^3wW?~;A9ga53j|jG9p9aj`fdux!@NvcdR3u$40=;&V0^7-deS=oSKQ$x&9t z^f)BJ?(ln^wmLt120vNdST`=L*P5ya%~>)F3%!#3d5lG#xW0+SMDL~?R!?&9&xyhE z&KAHh#?H$aS~(v(Cwo%3*$U2PC{yqj;CQm)Ekhw|6%sARfA^_#fh)-u5R-+>!chuf zZ2l^K7{BNP4>DNzrNJJr;0pL1WkM}G9Ah(Zm0&FlV=c)la6US}zJvL$+JxK>mium0 zDCgIWukdWY+my#-QV*I5FT*|2cT1t_@&fh>UZ#B$^LT5k`{P@m$EOtWFj*<$C*)yV z_a|~8m*Y1Tak*=gmCMtcCUBX$ncJ4vZe}$d8~SMT4;*N!cKPGYxua_kAXcUlhnM1< z0wEVd@5i4qVu7sT-B*+cj!#Tbnq>F_kd56e=vDHAYx@smmj*>E+shj1t)Z`$gGk$bf3pBmIWAHC}BO@{0!G{dBT{8;!4pa^0Z!hq8|@hX-g{$ zTI_Vy7%JlDVQ>mJcY&-l3nx{g!Aem?v5A;X<^Z)JiVV04gq7z2pR>zjbNU90yLK>* zEE_Ch9I)7zkDV+J>|JbXqA4UtXfQgAU3gk zT{zjPoysL%Yj*rHCh0byxS`w*vHgGV?&9v}i$q)>Y=YGvC)XWTedKj0e2btNd*jWM1|sa^yFm{EciphSu|J@GI4I! z$2^_TI>+JgN48>@U6z7#SQ`#}Hv9o~I3~&f7bUbWPrz;Wr|RVo zVtT7)%CF=l$TM5(I7H91wsU!+&CX=7)1&ZWH4AOjLS~Nfaw9hma3^v9yud^0>iqCFJ_gY(6Z9%8J^jVof%Z17RG28u@3p* zZGD3ZnAmE?RClmm>I#+u43MxLjX$M=Hy+02yff7@i7Nt6C9afg*6ArNt+V-WjAUCtqMcs?!3X1_GR@Q@<%c8slAXirCBow`4D(7PTkE=(M6Kz_Eh+6 z-b%5P`CE4>jDKp^M6PP&llfe(e{wpPm!EV&#)kZVevLy{&Uu<$Pvhh@Pb)Xw51!^N zAvE}z3Z(@+EJp)Z{~ll-vY3Cng;5&LGLzk(Rc^U)ZC?jN6LX#QVTL8f4dXDEc1w57 zE=J_g{BbV>q;aA5Iu?me#`03Fh(0RX5IlUJ;%h^>?K47mdMZ){+*es`juX<9ulx16C!j-yBrhdMMVOnM^}) z_#ECD9pG&CLCAu`E-S1^GEpL|yYg^#QDfu~VG$^=9N*{i32Xd#rXzftci^(y-u4dw9}3I!X@t}`Ed14xz(2>$KKOluJ`AL#!5*l M{VH7H)GF0~00e?)3jhEB diff --git a/resource/translations/ao_de.ts b/resource/translations/ao_de.ts index caf9c6ace..0e2cba946 100644 --- a/resource/translations/ao_de.ts +++ b/resource/translations/ao_de.ts @@ -4,127 +4,69 @@ AOApplication - + Disconnected from server. Vom Server getrennt. - Error connecting to master server. Will try again in %1 seconds. - Fehler bei der Verbindung zum Master Server. Erneuter Versuch in %1 Sekunden. - - - Error connecting to master server. Will try again in %n seconds. - Fehler bei der Verbindung zum Master Server. Erneuter Versuch in %n Sekunden. - - - There was an error connecting to the master server. -We deploy multiple master servers to mitigate any possible downtime, but the client appears to have exhausted all possible methods of finding and connecting to one. -Please check your Internet connection and firewall, and please try again. - Es gab einen Fehler beim Verbinden zum Master Server. -Wir verwenden mehrere Master Server um Ausfälle zu verhindern, jedoch hat der Client alle Möglichkeiten einen zu finden erschöpft. -Bitte prüfe deine Internetverbindung und Firewall, und versuche es erneut. - - - Outdated version! Your version: %1 -Please go to aceattorneyonline.com to update. - Version zu alt! Deine Version: %1 -Bitte besuche aceattorneyonline.com für ein Update. - - - You have been exiled from AO. -Have a nice day. - Du wurdest von AO befreit. -Schönen Urlaub. - - - Attorney Online - Attorney Online - - - + Loading Laden - Loading evidence: -%1/%2 - Lade Beweisstücke: -%1/%2 - - - + Loading music: %1/%2 Lade Musik: %1/%2 - + Loading chars: %1/%2 Lade Charaktere: %1/%2 - + Attorney Online %1 Attorney Online %1 - + [Global log] - + [Globaler Log] - + You have been kicked from the server. Reason: %1 Du wurdest von diesem Server geschmissen. Grund: %1 - + You have been banned from the server. Reason: %1 Du wurdest von diesem Server verbannt. Grund: %1 - + You are banned on this server. Reason: %1 Du bist von diesem Server verbannt. Grund: %1 - You have been kicked from the server. -Reason: - Du wurdest von diesem Server geschmissen. -Grund: - - - You are banned on this server. -Reason: - Du wurdest von diesem Server verbannt. -Grund: - - - You have been kicked. - Du wurdest rausgeschmissen. - - - You are banned on this server. - Du wurdest verbannt. - - - + Demo playback - + Demo Wiedergabe - + Play back demos you have previously recorded - + Spielt Demo Dateien welche vorher aufgenommen wurden @@ -164,2112 +106,1824 @@ Grund: Stenographer needed Stenograph benötigt - - Witness needed - Zeuge benötigt - AOOptionsDialog - - Settings - Einstellungen + + + Log timestamp format: + + Log Zeitstempel Format: + - - Gameplay - Spiel + + Pixel + Pixel - - Theme: - Theme: + + Smooth + Glatt - - Sets the theme used in-game. If the new theme changes the lobby's look as well, you'll need to reload the lobby for the changes to take effect, such as by joining a server and leaving it. - Setzt das Theme. Wenn das neue Theme auch das Aussehen der Lobby verändert, must du diese neu laden um die Änderungen zu sehen. + + Couldn't get the privacy policy. + Datenschutz-Bestimmungen konnten nicht abgerufen werden. - Gives the default value for the in-game 'Custom shownames' checkbox, which in turn determines whether the client should display custom in-character names. - Setzt den Standardwerd für den eigenen Anzeigenamen. + + Select a base folder + Wähle ein base Ordner - Sets the default volume for music. - Standardlautstärke für die Musik. + + Getting privacy policy... + Lade Datenschutz-Bestimmungen... - Sets the default volume for SFX sounds, like interjections or other character sound effects. - Standardlautstärke für Soundeffekte. + + %1 (default) + %1 (Standard) + + + Courtroom - IC Log - Log + + Password + Passwort - Colorful IC log: - Farbiges Log: + + Spectator + Zuschauer - Enables colored text in the log. - Aktiviert farbigen Text im Log. + + + Search + Suche - Only inline coloring: - Nur in-Zeilen Farben: + + Passworded + Gesperrt - Only inline coloring will be shown such as <>,|| etc. - Nur die in-Zeilen Farben wie <>,|| etc. werden gezeigt. + + Taken + Benutzt - Mirror IC log: - Log spiegeln: + + + Could not find character (char.ini) for %1 + Charakter (char.ini) nicht gefunden für %1 - IC log will mirror the IC box. Meaning that if somebody gets interrupted nobody will know what they wanted to say. Enable for a more realistic experience. - Das Log spiegelt die Nachrichten. Bedeutet dass wenn jemand unterbrochen wird, kann man nicht sehen was derjenige sagen wollte. Für ein realistischeres Spielerlebnis. + + Generating chars: +%1/%2 + Generiere Charaktere: +%1/%2 - - Log goes downwards: - Verlauf geht nach unten: + + Showname + Anzeigename - - If ticked, new messages will appear at the bottom (like the OOC chatlog). The traditional (AO1) behaviour is equivalent to this being unticked. - Wenn angehakt werden neue Nachrichten unten erscheinen (wie beim OOC). Das traditionelle (AO1) Verhalten wäre nicht angehakt. + + Name + Name - - Log length: - Länge: + + Pre + Vor - The amount of messages the IC chatlog will keep before deleting older messages. A value of 0 or below counts as 'infinite'. - Die Menge an Nachrichten die aufgehoben werden bevor alte gelöscht werden. 0 bedeutet unendlich. + + Flip + Spiegeln - - Log newline: - Absätze protokollieren: + + Guard + Wache - - If ticked, new messages will appear separated, with the message coming on the next line after the name. When unticked, it displays it as 'name: message'. - Wenn Nachrichten mehrere Zeilen enthalten wird dies mitprotokolliert. + + + Casing + Fall - - Log margin: - Protokollabstand: + + Shownames + Anzeigenamen - - The distance in pixels between each entry in the IC log. Default: 0. - Setzt den Abstand zwischen den Zeilen im Protokoll. Standard: 0. + + Immediate + Keine Unterbrechung - - Log timestamp: - Zeitstempel: + + Music + Musik - - If ticked, log will contain a timestamp in UTC before the name. - Das Protokoll enthält vor dem Namen einen Zeitstempel in UTC. + + Sfx + Sfx - - Log IC actions: - Aktionen protokollieren: + + Blips + Blips - - If ticked, log will show IC actions such as shouting and presenting evidence. - Protokolliert Charakteraktionen wie Zwischenrufe und Beweisstücke. + + + Server + Server - - Text Stay Time: - Standzeit: + + Change character + Charakter ändern - Minimum amount of time (in miliseconds) an IC message must stay on screen before the next IC message is shown, acting as a 'queue'. Set to 0 to disable this behaivor. - Minimale Zeit (in Milisekunden) die eine Nachricht auf dem Bildschirm bleibt bevor die nächste gezeigt wird. 0 deaktiviert dies. + + Reload theme + Aussehen neu laden - - Desynchronize IC Logs: - Protokoll desynchronisieren: + + Call mod + Moderator rufen - - If ticked, log will show messages as-received, while viewport will parse according to the queue (Text Stay Time). - Wenn angehakt werden die Nachrichten sofort im Protokoll angezeigt, ansonsten wartet es auf den Chat. + + Settings + Einstellungen - - Instant Objection: - Zwischenrufe sofort: + + A/M + A/M - - If Text Stay Time is more than 0, instant objection will skip queued messages instead of waiting to catch up. - Wenn die Standzeit länger als 0 ist überspringen Zwischenrufe die Warteschleife. + + Preanim + Voranimation - - Default username: - Standard Benutzername: + + Back to Lobby + Zurück zur Lobby - - Your OOC name will be automatically set to this value when you join a server. - Dein OOC Name wird automatisch auf dies gesetzt. + + You were granted the Disable Modcalls button. + Du hast nun den "Modcall deaktivieren" Knopf. - - Custom shownames: - Eigener Anzeigename: + + You have been banned. + Du wurdest verbannt. - - Gives the default value for the in-game 'Custom shownames' tickbox, which in turn determines whether the client should display custom in-character names. - Standardwert für die Anzeigename Box, welche den In-Charakter Namen bestimmt. + + + None + Keine - Backup MS: - Rückfall MS: + + Message in-character + Nachricht als Charakter - If the built-in server lookups fail, the game will try the address given here and use it as a backup master server address. - Wenn dereingebaute Master Server fehlschlägt, wird das Spiel diesen hier verwenden. + + Message out-of-character + Nachricht out-of-character - - Discord: - Discord: + + Additive + Hinzufügend - - Allows others on Discord to see what server you are in, what character are you playing, and how long you have been playing for. - Erlaubt anderen auf Discord zu sehen auf welchem Server du spielst, welchen Charakter du spielst und wie lange. + + To front + Vorne - Allow Shake/Flash: - Schütteln/Geistesblitz erlauben: + + To behind + Hinten - Allows screenshaking and flashing. Disable this if you have concerns or issues with photosensitivity and/or seizures. - Erlaubt schütteln des Bildschirms und weiße Blitze. Deaktiviere dies falls du Bedenken wegen Photosensitivität hast. + + Log goes down + Log geht nach unten - - Language: - Sprache: + + Log goes up + Log geht nach oben - - Sets the language if you don't want to use your system language. - Setzte die Sprache falls du nicht die Systemsprache verwenden möchtest. + + Select a character you wish to pair with. + Wähle einen Charakter mit dem du gepaart sein möchtest. - Slower text speed: - Langsamerer Text: + + Change the order of appearance for your character. + Ändere die Reihenfolge in der die Charaktere erscheinen. - Set the text speed to be the same as the AA games. - Setzt den Text auf die gleiche Geschwindigkeit wie in den AA Spielen. + + Display the list of characters to pair with. + Zeigt die Liste der paarbaren Charaktere. - Blip delay on punctuations: - Blip Pausen bei Satzzeichen: + + Oops, you're muted! + Ohje, du bist stumm! - Punctuation delay modifier. Enable it for the blips to slow down on punctuations. - Aktivieren damit die Blips bei Satzzeichen langsamer werden. + + Set your character's emote to play on your next message. + Setzt den Ausdruck für die nächste Nachricht. - - Subtheme: - Untertheme: + + Set your character's supplementary background. + Setzt die Position des Charakters. - - Sets a 'subtheme', which will stack on top of the current theme and replace anything it can.Keep it at 'server' to let the server decide. Keep it at 'default' to keep it unchanging. - Setzt ein 'Untertheme', das alles aus dem aktuellen Theme ersetzt. Lass es auf 'Server' um den Server entscheiden zu lassen. 'Standard' um es so zu lassen. + + Change the horizontal percentage offset of your character's position from the center of the screen. + Ändert den Hoizontalen Abstand relativ zur Mitte. - - Reload Theme - Aussehen neu laden + + Change the vertical percentage offset of your character's position from the center of the screen. + Ändert den vertikalen Abstand relativ zur Mitte. - - Refresh the theme and update all of the ui elements to match. - Aktualisiert das Design und alle UI Elemente. + + Reset your character's supplementary background to its default. + Setzt den Zusatzhintergrund deines Charakters zurück. - - Animated Theme: - Animiertes Theme: + + Set an 'iniswap', or an alternative character folder to refer to from your current character. +Edit by typing and pressing Enter, [X] to remove. This saves to your base/iniswaps.ini + Setz einen 'iniswap', oder einen anderen Charakterordner von deinem aktuellen Charakter. +Bearbeiten durch tippen und Enter drücken, [X] zum entfernen. Das wird in base/iniswaps.ini gespeichert. - - If ticked, themes will be allowed to have animated elements. - Aktiviert animierte Theme Elemente. + + Remove the currently selected iniswap from the list and return to the original character folder. + Entfernt den aktuellen iniswap von der Liste und stellt den originalen Ordner wieder her. - - The amount of message lines the IC chatlog will keep before deleting older message lines. A value of 0 or below counts as 'infinite'. - Die menge an Zeilen die das IC Log behält bevor ältere Nachrichten gelöscht werden. 0 bedeutet unendlich. + + Set a sound effect to play on your next 'Preanim'. Leaving it on Default will use the emote-defined sound (if any). +Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters/<charname>/soundlist.ini + Wähle einen Soundeffekt der bei der nächsten 'Preanim' gespielt wird. Lasse dies auf Standard um den emote-Sound zu verwenden. +Bearbeiten durch tippen und Enter drücken, [X] zum entfernen. Das wird in base/characters/<charname>/soundlist.ini gespeichert. - - - Log timestamp format: - - + + Remove the currently selected sound effect. + Entfernt den aktuell ausgewählten Soundeffekt. - - Minimum amount of time (in miliseconds) an IC message must stay on screen before the next IC message is shown, acting as a 'queue'. Set to 0 to disable this behavior. - Minimale Zeit (in Milisekunden) die eine IC Nachricht auf dem Bildschirm bleibt bevore die nächste kommt, wie eine Art 'Warteschlange'. 0 deaktiviert das. + + Choose an effect to play on your next spoken message. +The effects are defined in your theme/effects/effects.ini. Your character can define custom effects by +char.ini [Options] category, effects = 'miscname' where it referes to misc/<miscname>/effects.ini to read the effects. + Wähle einen Effekt für die nächste Nachricht. +Die Effekte sind definiert in theme/effects/effects.ini. Dein Charakter kann eigene Effekte in der +char.ini [Options] Kategorie, effects = 'miscname' haben welcher dann misc/<miscname>/effects.ini liest. - - Text crawl: - Kriechender Text: + + Hold It! + Moment mal! - - Amount of time (in miliseconds) spent on each letter when the in-character text is being displayed. - Zeit (in Milisekunden) für jeden Buchstaben. + + + + When this is turned on, your next in-character message will be a shout! + Wenn dies an ist, wird die Nächste Nachricht ein Zuruf! - - Chat Rate Limit: - Chat Rate Limit: + + Objection! + Einspruch! - - Minimum amount of time (in miliseconds) that must pass before the next Enter key press will send your IC message. - Minimale Zeit (in Milisekunden) die verstreichen müssen bevore der nächste Enter Druck die Nachricht versendet. + + Take That! + Nimm das! - - Default showname: - + + Toggle between server chat and global AO2 chat. + Wechselt zwischen Serverchat und AO2 Chat. - - Your showname will be automatically set to this value when you join a server. - + + + + + This will display the animation in the viewport as soon as it is pressed. + Dies zeigt die Animation im Spielfeld sobald es angeklickt wird. - - Alternate Server List: - + + Guilty! + Schuldig! - - Overrides the base URL to retrieve server information from. - + + Bring up the Character Select Screen and change your character. + Zeige die Charakterauswahl und ändere deinen Charakter. - - - Keep current setting - - aktuelle Einstellung behalten - - - - Scaling: - + + Refresh the theme and update all of the ui elements to match. + Aktualisiert das Design und alle UI Elemente. - - Sets the default scaling method, if there is not one already defined specifically for the character. - + + Request the attention of the current server's moderator. + Fordere einen Moderator an. - - Pixel - + + Allows you to change various aspects of the client. + Lässt dich verschiedene Dinge des Clients anpassen. - - Smooth - + + An interface to help you announce a case (you have to be a CM first to be able to announce cases) + Ein Menü um einen Fall anzukündigen (du musst dafür erst CM sein) - - Allow Screenshake: - Schütteln erlauben: + + Switch between Areas and Music lists + Wechsel zwischen Areal- und Musikliste - - Allows screenshaking. Disable this if you have concerns or issues with photosensitivity and/or seizures. - Erlaubt schütteln des Bildschirms. Deaktiviere dies falls du Bedenken wegen Photosensitivität hast. + + Play a single-shot animation as defined by the emote when checked. + Zeigt eine Animation vor dem Sprechen. - - Allow Effects: - Effekte erlauben: + + If preanim is checked, display the input text immediately as the animation plays concurrently. + Starte sofort zu sprechen, ohne auf das Ende der Voranimation zu warten. - - Allows screen effects. Disable this if you have concerns or issues with photosensitivity and/or seizures. - Erlaubt Bildeffekte. Deaktiviere dies falls du Bedenken wegen Photosensitivität hast. + + Mirror your character's emotes when checked. + Spiegelt die Emotes deines Charakters. - - Network Frame Effects: - Netzwerk Frame-Effekte: + + Add text to your last spoken message when checked. + Füge Text zu deiner letzten Nachricht hinzu. - - Send screen-shaking, flashes and sounds as defined in the char.ini over the network. Only works for servers that support this functionality. - Sendet schüttel, Blitze und Geräusche aus der char.ini Datei über das Netzwerk. Funkioniert nur wenn der Server dies unterstützt. + + Do not listen to mod calls when checked, preventing them from playing sounds or focusing attention on the window. + Ignoriere Modcalls und spiel keinen Ton ab. - - Colors in IC Log: - Farben im IC Log: + + Lets you receive case alerts when enabled. +(You can set your preferences in the Settings!) + Lässt dich Fallalarme erhalten. +(Du kannst dies in den Einstellungen anpassen!) - - Use the markup colors in the server IC chatlog. - Verwendet Farbe im IC Log so wie im Bild. + + Display customized shownames for all users when checked. + Zeigt selbst einstellbare Namen für alle. - - Sticky Sounds: - Klebende Geräuschauswahl: + + Custom Shout! + Eigener Zwischenruf! - - Turn this on to prevent the sound dropdown from clearing the sound after playing it. - Aktiviere dies damit die Geräuschauswahl nicht zurückspringt nachdem es abgespielt wurde. + + This will display the custom character-defined animation in the viewport as soon as it is pressed. +To make one, your character's folder must contain custom.[webp/apng/gif/png] and custom.[wav/ogg/opus] sound effect + Dies zeigt des Charakters eigenen Zwischenruf. +Um einen zu haben muss im Charakterordner eine custom.[webp/apng/gif/png] und ein custom.[wav/ogg/opus] Soundeffekt sein - - Sticky Effects: - Klebende Effekt: + + Play realization sound and animation in the viewport on the next spoken message when checked. + Spiele den Realisierung Sound und Animation mit der nächsten Nachricht. - - Turn this on to prevent the effects dropdown from clearing the effect after playing it. - Aktiviere dies damit die Effektauswahl nicht zurückspringt nachdem er abgespielt wurde. + + Shake the screen on next spoken message when checked. + Schüttelt den Bildschirm bei der nächsten Nachricht. - - Sticky Preanims: - Klebende Voranimation: + + Display the list of character folders you wish to mute. + Zeigt die Charakterliste um einen stumm zu schalten. - - Turn this on to prevent preanimation checkbox from clearing after playing the emote. - Aktiviere dies damit das Kontrollkästchen für die Voranimation nicht zurückspringt nachdem sie abgespielt wurde. + + + Increase the health bar. + Erhöhe die Gesundheit. - - Custom Chatboxes: - Eigene Chatboxen: + + + Decrease the health bar. + Verringere die Gesundheit. - - Turn this on to allow characters to define their own custom chat box designs. - Charaktere können ihre eigenen Chatboxen verwenden. + + Change the text color of the spoken message. +You can also select a part of your currently typed message and use the dropdown to change its color! + Ändert die Textfarbe. +Du kannst auch nur einen Teil der Nachricht auswählen und dessen Farbe ändern! - - Stickers: - Sticker: + + Return back to the server list. + Zurück zur Serverliste. - - Turn this on to allow characters to define their own stickers (unique images that show up over the chatbox - like avatars or shownames). - An zeigt 'Sticker' an, kleine Bilder wie Avatare. + + Become a spectator. You won't be able to interact with the in-character screen. + Werde ein Zuschauer. Es ist dir nicht möglich mit dem Spielfeld zu interagieren. - - Continuous Playback: - Durchgehendes Abspielen: + + + + + CLIENT + CLIENT - - Whether or not to resume playing animations from where they left off. Turning off might reduce lag. - Spielt Animationen wieder dort ab wo sie aufgehört haben. Ausschalten kann bei Lag helfen. + + Login unsuccessful. + Login erfolgreich. - - Stop Music w/ Category: - Musik durch eine Kategorie stoppen: + + You were logged out. + Du wurdest ausgeloggt. - - Stop music when double-clicking a category. If this is disabled, use the right-click context menu to stop music. - Stoppt die Musik wenn eine Kategorie doppelt geklickt wird. Wenn dies deaktiviert ist, benutze die Rechte Maustaste und das Kontextmenü um die Musik anzuhalten. + + HOLD IT! + MOMENT MAL! - - Log to Text Files: - + + OBJECTION! + EINSPRUCH! - - Text logs of gameplay will be automatically written in the /logs folder. - + + TAKE THAT! + NIMM DAS! - - Log to Demo Files: - + + CUSTOM OBJECTION! + SPEZIALRUF! - - Gameplay will be automatically recorded as demos in the /logs folder. - + + + + + + shouts + Zwischenruf - - Callwords - Alarmwörter + + + + + has presented evidence + hat Beweis präsentiert - - <html><head/><body>Enter as many callwords as you would like. These are case insensitive. Make sure to leave every callword in its own line!<br>Do not leave a line with a space at the end -- you will be alerted everytime someone uses a space in their messages.</body></html> - <html><head/><body>Gib so viele Alarmwörter ein wie du möchtest. Groß/Kleinschreibung ist egal. Für jede Wort nur eine Zeile!<br>Bitte keine leere Zeile am Ende -- du bekommst sonst bei jeder Nachricht einen Alarm.</body></html> + + + + has stopped the music + hat die Musik angehalten - - Audio - Audio + + [LOADING] %1 + [LADEN] %1 - - Audio device: - Audiogerät: + + Debug + Debug - - Sets the audio device for all sounds. - Setzt das Audiogerät für all Geräusche. + + + has played a song + spielte ein Lied - - Music: - Musik: + + 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. + Du hattest keinen 'base/cases' Ordner! Ich hab ihn nun angelegt aber bedenke das er leer sein wird. - - Sets the music's default volume. - Setzt die Musiklautstärke. + + 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. +Cases you can load: %1 + Du musst einen Dateinamen angeben (ohne .ini). Stelle sicher das er im 'base/cases' Ordner ist und das er korrekt formatiert ist. +Verfügbare Fälle: %1 - - SFX: - SFX: + + Case made by %1. + Fall von %1. - - Sets the SFX's default volume. Interjections and actual sound effects count as 'SFX'. - Setzt die Lautstärke der Soundeffekte wie Einsprüche und die Geräusche der Charaktere. + + Navigate to %1 for the CM doc. + Gehe zu %1 für das CM Dokument. - - Blips: - Blips: + + + UNKNOWN + UNBEKANNT - - Sets the volume of the blips, the talking sound effects. - Setzt die Lautstärke der Blips, das ist das Geräusch das die Charaktere beim Reden machen. + + Your case "%1" was loaded! + Dein Fall "%1" wurde geladen! - - Blip rate: - Bliprate: + + Too many arguments to load a case! You only need one filename, without extension. + Zu viele Argumente! Du brauchst nur den Dateinamen, ohne Erweiterung. - - Sets the delay between playing the blip sounds. - Setzt die Pause zwischen einzelnen Blips. + + 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. + Du hattest keinen 'base/cases' Ordner! Ich hab ihn nun angelegt aber bedenke das er leer sein wird. - - Play a blip sound "once per every X symbols", where X is the blip rate. 0 plays a blip sound only once. - + + You need to give a filename to save (extension not needed) and the courtroom status! + Du musst einen Dateinamen (ohne Erweiterung) angebenn, sowie den Gebietsstatus! - - Add or remove base folders for use by assets. Base folders on the bottom are prioritized over those above them. - + + Too many arguments to save a case! You only need a filename without extension and the courtroom status! + Zu viele Argumente! Du brauchst nur den Dateinamen, ohne Erweiterung sowie den Gebietsstatus! - - Couldn't get the privacy policy. - + + Succesfully saved, edit doc and cmdoc link on the ini! + Erfolgreich gespeichert! - Play a blip sound "once per every X symbols", where X is the blip rate. - Spiele ein blip einmal für all X Buchstaben. + + Stop Current Song + Lied stoppen - - Blank blips: - Leere Blips: + + Play Random Song + Zufälliges Lied - - If true, the game will play a blip sound even when a space is 'being said'. - Wenn angehakt wird das Spiel auch bei einem Leerzeichen einen Blip machen. + + Expand All Categories + Alle Kategorien erweitern - - Enable Looping SFX: - Wiederholende Soundeffekte: + + Collapse All Categories + Alle Kategorien verstecken - - If true, the game will allow looping sound effects to play on preanimations. - Wenn aktiviert, werden wiederholende Soundeffekte bei den Voranimationen erlaubt. + + Fade Out Previous + Vorheriges ausblenden - - Kill Music On Objection: - Stoppe Musik bei Einspruch: + + Fade In + Einblenden - - If true, AO2 will ask the server to stop music when you use 'Objection!' - Hält die Musik für alle an wenn du 'Einspruch' benutzt. + + Synchronize + Synchronisieren - - Assets - + + Default + Standard - - Add… - + + Reason: + Grund: - - Select a base folder - + + Call Moderator + Moderator rufen - - Remove - + + + Error + Fehler - - ↑ - + + You must provide a reason. + Du musst einen Grund angeben. - - ↓ - + + The message is too long. + Die Nachricht ist zu lang. - - Clear Cache - + + Choose.. + Wähle.. - - Clears the lookup cache for assets. Use this when you have added an asset that takes precedence over another existing asset. - + + Present this piece of evidence to everyone on your next spoken message + Präsentiere dieses Beweisstück allen in der nächsten Nachricht - - Privacy - + + Save evidence to an .ini file. + Speichere Beweise in einer .ini Datei. - - Do not include me in public player counts - + + Load evidence from an .ini file. + Lade Beweise aus einer .ini Datei. - - Getting privacy policy... - + + Destroy this piece of evidence + Zerstöre dieses Beweisstück - - %1 (default) - - - - If true, AO2 will stop the music for you when you or someone else does 'Objection!'. - Hält die Musik an wenn jemand "Einspruch" ruft, wie im echten Spiel. - - - Automatic Logging: - Autmatisches Protokollieren: - - - If checked, all logs will be automatically written in the /logs folder. - Schreibt die Protokolle automatisch in den /logs Ordner. - - - If true, the game will stop music when someone objects, like in the actual games. - Hält die Musik an wenn jemand "Einspruch" ruft, wie im echten Spiel. - - - - Casing - Fälle + + Close the evidence display/editing overlay. +You will be prompted if there's any unsaved changes. + Schließe das Beweisfenster. +Du wirst gefragt wenn es ungespeicherte Änderungen gibt. - - This server supports case alerts. - Dieser Server unterstützt Fallalarme. + + Save any changes made to this piece of evidence and send them to server. + Speichert alle Änderungen an diesem Beweisstück und schickt sie zum Server. - - This server does not support case alerts. - Dieser Server unterstützt Fallalarme nicht. + + Click to edit. Press [X] to update your changes. + Klick zum editieren. Drücke [X] zum speichern deiner Änderungen. - - Pretty self-explanatory. - Eigentlich selbsterklärend. + + Bring up the Evidence screen. + Zeigt die Beweisliste. - - Casing: - Fälle: + + Switch evidence to private inventory. + Wechselt zum eigenen Inventar. - - If checked, you will get alerts about case announcements. - Wenn angehakt wirst du benachrichtigt wenn ein Fall angekündigt wird. + + Switch evidence to global inventory. + Wechselt zum globalen Inventar. - - Defense: - Verteidigung: + + + Transfer evidence to private inventory. + Übertrage Beweisstück zum eigenen Inventar. - - If checked, you will get alerts about case announcements if a defense spot is open. - Wenn angehakt wirst du benachrichtigt wenn ein Verteidiger benötigt wird. + + + Transfer evidence to global inventory. + Übertrage Beweisstück zum globalen Inventar. - - Prosecution: - Kläger: + + The piece of evidence you've been editing has changed. + Das Beweisstück das du bearbeitet hast hat sich verändert. - - If checked, you will get alerts about case announcements if a prosecutor spot is open. - Wenn angehakt wirst du benachrichtigt wenn ein Kläger benötigt wird. + + Do you wish to keep your changes? + Möchtest du deine Änderungen behalten? - - Judge: - Richter: + + Name: %1 +Image: %2 +Description: +%3 + Name: %1 +Bild: %2 +Beschreibung: +%3 - - If checked, you will get alerts about case announcements if the judge spot is open. - Wenn angehakt wirst du benachrichtigt wenn ein Richter benötigt wird. + + Images (*.png) + Bilder (*.png) - - Juror: - Jury: + + + + Click to edit... + Klicken zum bearbeiten... - - If checked, you will get alerts about case announcements if a juror spot is open. - Wenn angehakt wirst du benachrichtigt wenn eine Jury benötigt wird. + + Add new evidence... + Neues Beweisstück... - - Stenographer: - Stenograph: + + Evidence has been modified. + Beweise wurden verändert. - - If checked, you will get alerts about case announcements if a stenographer spot is open. - Wenn angehakt wirst du benachrichtigt wenn ein Stenograph benötigt wird. + + Do you want to save your changes? + Möchtest du deine Änderungen speichen? - - CM: - CM: + + Current evidence is global. Click to switch to private. + Beweise sind global. Klicken um zu eigenen zu wechseln. - - If checked, you will appear amongst the potential CMs on the server. - Wenn angehakt wirst du als potentielle CM angezeigt. + + Current evidence is private. Click to switch to global. + Beweise sind die eigenen. Klicken um zu global zu wechseln. - Witness: - Zeuge: + + "%1" has been transferred. + "%1" wurde übertragen. - If checked, you will appear amongst the potential witnesses on the server. - Wenn angehakt wirst du als potentielle Zeuge angezeigt. + + Save Inventory + Inventar speichen - - Hosting cases: - Fallleitung: + + + Ini Files (*.ini) + Ini Dateien (*.ini) - - If you're a CM, enter what cases you are willing to host. - Wenn du CM bist, gib ein welche Fälle du spielen möchtest. + + Open Inventory + Inventar öffnen - Courtroom - - - Password - Passwort - - - - Spectator - Zuschauer - - - - - Search - Suche - - - - Passworded - Gesperrt - - - - Taken - Benutzt - - - - Could not find character (char.ini) for %1 - - - - - Generating chars: -%1/%2 - Generiere Charaktere: -%1/%2 - - - Generating chars: - - Generiere Charaktere: - - - - Could not find %1 - Konnte %1 nicht finden - - - - Showname - Anzeigename - - - - Message - Nachricht - - - OOC Message - OOC Nachricht - - - - Name - Name - - - - Pre - Vor - + DemoServer - - Flip - Spiegeln + + + Load Demo + Demo laden - - Guard - Wache + + + Demo Files (*.demo) + Demos (*.demo) - Disable Modcalls - Deaktiviere Moderatorenrufe + + + Demo file loaded. Send /play or > in OOC to begin playback. + Demo geladen. Sende /play oder > in OOC um Wiedergabe zu beginnen. - - - Casing - Fall + + Resuming playback. + Wiedergabe fortsetzen. - - Shownames - Anzeigenamen + + Pausing playback. + Wiedergabe pausieren. - - Immediate - Keine Unterbrechung + + Setting max_wait to + Setze max_wait zu - White - Weiß + + + milliseconds. + millisekunden. - Green - Grün + + Not a valid integer! + Kein valider Integer! - Red - Rot + + Current max_wait is + Aktueller max_wait ist - Orange - Orange + + Current demo file reloaded. Send /play or > in OOC to begin playback. + Demo Datei neugeladen. Sende /play or > in OOC um die Wiedergabe zu beginnen. - Blue - Blau + + min_wait is deprecated. Use the client Settings for minimum wait instead! + min_wait ist veraltet. Benutze die Client Einstellung Standzeit! - Yellow - Gelb + + Setting debug mode to %1 + Setze Debug Modus zu %1 - - Music - Musik + + Valid values are 1 or 0! + Gültige Werte sind 1 oder 0! - - Sfx - Sfx + + 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. + - - Blips - Blips + + Available commands: +load, reload, play, pause, max_wait, debug, help + Verfügbate Kommandos: +load, reload, play, pause, max_wait, debug, help - Log limit - Verlaufsgrenze + + Reached the end of the demo file. Send /play or > in OOC to restart, or /load to open a new file. + Ende der Demo Datei erreicht. Sende /play oder > um die Wiedergabe neuzustarten oder /load um eine neue Datei zu öffnen. + + + Lobby - - - Server - Server + + Attorney Online %1 + Attorney Online %1 - - Change character - Charakter ändern + + Search + Suche - - Reload theme - Aussehen neu laden + + It doesn't look like your client is set up correctly. +Did you download all resources correctly from tiny.cc/getao, including the large 'base' folder? + Dein Client ist nicht korrekt eingerichtet. +Hast du ALLES von tiny.cc/getao heruntergeladen und entpackt, auch den großen 'base' Ordner? - - Call mod - Moderator rufen + + Version: %1 + Version: %1 - + Settings Einstellungen - - A/M - A/M - - - - Preanim - Voranimation - - - - Back to Lobby - Zurück zur Lobby - - - - You were granted the Disable Modcalls button. - Du hast nun den "Modcall deaktivieren" Knopf. - - - - You have been banned. - Du wurdest verbannt. - - - Too many arguments to save a case! You only need a filename without extension and the courtroom status. - Zu viele Argumente zum Speichern! Bitte gib nur den Dateinamen ohne Erweiterung und den Saalstatus an. - - - %1 has played a song: %2 - %1 hat ein Lied gespielt: %2 - - - Rainbow - Regenbogen - - - Pink - Pink - - - Cyan - Cyan - - - % offset - % Abstand - - - You were granted the Guard button. - Dir wurde der Wache Knopf gegeben. - - - This does nohing, but there you go. - Dies bewirkt nichts, aber egal. - - - This does nothing, but there you go. - Dies bewirkt nichts, aber egal. - - - You opened the settings menu. - Du hast die Einstellungen geöffnet. - - - You will now pair up with - Du wirst nun mit - - - if they also choose your character in return. - gepaart, wenn der andere dies auch tut. - - - - - None - Keine - - - - Additive - Hinzufügend - - - - % x offset - % Horizontaler Abstand - - - - % y offset - % Vertikaler Abstand - - - - To front - Vorne - - - - To behind - Hinten - - - - Log goes down - - - - - Log goes up - - - - - Select a character you wish to pair with. - Wähle einen Charakter mit dem du gepaart sein möchtest. - - - Change the percentage offset of your character's position from the center of the screen. - Ändere den Abstand des Charakters zur Mitte. - - - - Change the order of appearance for your character. - Ändere die Reihenfolge in der die Charaktere erscheinen. - - - - Display the list of characters to pair with. - Zeigt die Liste der paarbaren Charaktere. - - - - Oops, you're muted! - Ohje, du bist stumm! - - - - Set your character's emote to play on your next message. - Setzt den Ausdruck für die nächste Nachricht. - - - - Set your character's supplementary background. - Setzt die Position des Charakters. - - - Set an 'iniswap', or an alternative character folder to refer to from your current character. -Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters/<charname>/iniswaps.ini - Setz einen 'iniswap', oder einen anderen Charakterordner von deinem aktuellen Charakter. -Bearbeiten durch tippen und Enter drücken, [X] zum entfernen. Das wird in base/characters/<charname>/iniswaps.ini gespeichert. - - - - Change the horizontal percentage offset of your character's position from the center of the screen. - Ändert den Hoizontalen Abstand relativ zur Mitte. - - - - Change the vertical percentage offset of your character's position from the center of the screen. - Ändert den vertikalen Abstand relativ zur Mitte. - - - - Reset your character's supplementary background to its default. - Setzt den Zusatzhintergrund deines Charakters zurück. - - - - Set an 'iniswap', or an alternative character folder to refer to from your current character. -Edit by typing and pressing Enter, [X] to remove. This saves to your base/iniswaps.ini - Setz einen 'iniswap', oder einen anderen Charakterordner von deinem aktuellen Charakter. -Bearbeiten durch tippen und Enter drücken, [X] zum entfernen. Das wird in base/iniswaps.ini gespeichert. - - - - Remove the currently selected iniswap from the list and return to the original character folder. - Entfernt den aktuellen iniswap von der Liste und stellt den originalen Ordner wieder her. - - - - Set a sound effect to play on your next 'Preanim'. Leaving it on Default will use the emote-defined sound (if any). -Edit by typing and pressing Enter, [X] to remove. This saves to your base/characters/<charname>/soundlist.ini - Wähle einen Soundeffekt der bei der nächsten 'Preanim' gespielt wird. Lasse dies auf Standard um den emote-Sound zu verwenden. -Bearbeiten durch tippen und Enter drücken, [X] zum entfernen. Das wird in base/characters/<charname>/soundlist.ini gespeichert. - - - - Remove the currently selected sound effect. - Entfernt den aktuell ausgewählten Soundeffekt. - - - - Choose an effect to play on your next spoken message. -The effects are defined in your theme/effects/effects.ini. Your character can define custom effects by -char.ini [Options] category, effects = 'miscname' where it referes to misc/<miscname>/effects.ini to read the effects. - Wähle einen Effekt für die nächste Nachricht. -Die Effekte sind definiert in theme/effects/effects.ini. Dein Charakter kann eigene Effekte in der -char.ini [Options] Kategorie, effects = 'miscname' haben welcher dann misc/<miscname>/effects.ini liest. - - - - Hold It! - Moment mal! - - - - - - When this is turned on, your next in-character message will be a shout! - Wenn dies an ist, wird die Nächste Nachricht ein Zuruf! - - - - Objection! - Einspruch! - - - - Take That! - Nimm das! - - - - Toggle between server chat and global AO2 chat. - Wechselt zwischen Serverchat und AO2 Chat. - - - - - - - This will display the animation in the viewport as soon as it is pressed. - Dies zeigt die Animation im Spielfeld sobald es angeklickt wird. - - - - Guilty! - Schuldig! - - - - Bring up the Character Select Screen and change your character. - Zeige die Charakterauswahl und ändere deinen Charakter. - - - - Refresh the theme and update all of the ui elements to match. - Aktualisiert das Design und alle UI Elemente. - - - - Request the attention of the current server's moderator. - Fordere einen Moderator an. - - - + Allows you to change various aspects of the client. - Lässt dich verschiedene Dinge des Clients anpassen. - - - - An interface to help you announce a case (you have to be a CM first to be able to announce cases) - Ein Menü um einen Fall anzukündigen (du musst dafür erst CM sein) - - - - Switch between Areas and Music lists - Wechsel zwischen Areal- und Musikliste - - - - Play a single-shot animation as defined by the emote when checked. - Zeigt eine Animation vor dem Sprechen. - - - - If preanim is checked, display the input text immediately as the animation plays concurrently. - Starte sofort zu sprechen, ohne auf das Ende der Voranimation zu warten. + Erlaubt es verschiedene Aspekte des Clients zu ändern. - - Mirror your character's emotes when checked. - Spiegelt die Emotes deines Charakters. + + Loading + Laden - - Add text to your last spoken message when checked. - Füge Text zu deiner letzten Nachricht hinzu. + + Cancel + Abbrechen - - Do not listen to mod calls when checked, preventing them from playing sounds or focusing attention on the window. - Ignoriere Modcalls und spiel keinen Ton ab. + + <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<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 + - - Lets you receive case alerts when enabled. -(You can set your preferences in the Settings!) - Lässt dich Fallalarme erhalten. -(Du kannst dies in den Einstellungen anpassen!) + + Remove + Entfernen - - Display customized shownames for all users when checked. - Zeigt selbst einstellbare Namen für alle. + + Couldn't get the message of the day. + Fehler beim abrufen der Nachricht des Tages. - - Custom Shout! - Eigener Zwischenruf! + + Version: %1 (!) + Version: %1 (!) - - This will display the custom character-defined animation in the viewport as soon as it is pressed. -To make one, your character's folder must contain custom.[webp/apng/gif/png] and custom.[wav/ogg/opus] sound effect - Dies zeigt des Charakters eigenen Zwischenruf. -Um einen zu haben muss im Charakterordner eine custom.[webp/apng/gif/png] und ein custom.[wav/ogg/opus] Soundeffekt sein + + New version available: %1 + Neue Version verfügbar:%1 - - Play realization sound and animation in the viewport on the next spoken message when checked. - Spiele den Realisierung Sound und Animation mit der nächsten Nachricht. + + Yes + Ja - - Shake the screen on next spoken message when checked. - Schüttelt den Bildschirm bei der nächsten Nachricht. + + No + Nein - - Display the list of character folders you wish to mute. - Zeigt die Charakterliste um einen stumm zu schalten. + + About + Über - - - Increase the health bar. - Erhöhe die Gesundheit. + + Online: %1/%2 + Online: %1/%2 - - - Decrease the health bar. - Verringere die Gesundheit. + + + + Offline + Offline + + + NetworkManager - - Change the text color of the spoken message. -You can also select a part of your currently typed message and use the dropdown to change its color! - Ändert die Textfarbe. -Du kannst auch nur einen Teil der Nachricht auswählen und dessen Farbe ändern! + + No description provided. + Keine Beschreibung erhalten. + + + QDialogButtonBox - - Return back to the server list. - Zurück zur Serverliste. + + + OK + OK + + + QObject - - Become a spectator. You won't be able to interact with the in-character screen. - Werde ein Zuschauer. Es ist dir nicht möglich mit dem Spielfeld zu interagieren. + + [MISSING] Streaming disabled. + [FEHLT] Streaming deaktiviert. - - - - - - CLIENT - CLIENT + + + None + Keine - - Login unsuccessful. - + + [MISSING] %1 + [FEHLT] %1 - - You were logged out. - + + [STREAM] %1 + [STREAM] %1 + + + chatlogpiece - - HOLD IT! - MOMENT MAL! + + + + UNKNOWN + UNBEKANNT + + + debug_functions - - OBJECTION! - EINSPRUCH! + + Error: %1 + Fehler: %1 - - TAKE THAT! - NIMM DAS! + + Error + Fehler - - CUSTOM OBJECTION! - SPEZIALRUF! + + Notice + Hinweis + + + optionsdialogue - - - - - shouts - Zwischenruf + + Settings + Einstellungen - - - - has presented evidence - hat Beweis präsentiert + + Gameplay + Spiel - - - - has stopped the music - hat die Musik angehalten + + Stop music when double-clicking a category. If this is disabled, use the right-click context menu to stop music. + Stoppt die Musik wenn eine Kategorie doppelt geklickt wird. Wenn dies deaktiviert ist, benutze die Rechte Maustaste und das Kontextmenü um die Musik anzuhalten. - - [LOADING] %1 - + + Stop Music w/ Category: + Musik durch eine Kategorie stoppen: - - Debug + + Sets the default scaling method, if there is not one already defined specifically for the character. - [STREAM] %1 - [STREAM] %1 + + Scaling: + Skalierung: - [MISSING] %1 - [FEHLT] %1 + + Turn this on to allow characters to define their own custom chat box designs. + Charaktere können ihre eigenen Chatboxen verwenden. - - - has played a song - spielte ein Lied + + Custom Chatboxes: + Eigene Chatboxen: - You will now pair up with %1 if they also choose your character in return. - Du paarst dich nun mit %1 wenn diese deinen Charakter auch gewählt haben. + + Allows screen effects. Disable this if you have concerns or issues with photosensitivity and/or seizures. + Erlaubt Bildeffekte. Deaktiviere dies falls du Bedenken wegen Photosensitivität hast. - You are no longer paired with anyone. - Du bist nicht mehr gepaart. + + Allow Effects: + Effekte erlauben: - Are you sure you typed that well? The char ID could not be recognised. - Hast du dich vertippt? Die ID konnte nicht erkannt werden. + + Open the theme folder of the currently selected theme. + Öffnet den Ordner des aktuell ausgewählten Theme. - You have set your offset to %1%%. - Dein Abstand ist auf %1%% gesetzt. + + Open Theme Folder + Öffne Theme Ordner - You have set your offset to - Dein Abstand ist auf + + Overrides the base URL to retrieve server information from. + Überschreibt die Standard URL für den Abruf von Server Informationen. - Your offset must be between -100% and 100%! - Der Abstand muss zwischen -100% und 100% liegen! + + Alternate Server List: + Alternative Serverliste: - That offset does not look like one. - Das sieht nicht wie ein Abstand aus. + + Instant Objection: + Zwischenrufe sofort: - You have set your vertical offset to %1%%. - Du hast deinen vertikalen Abstand auf %1%% gesetzt. + + + + ms + ms - Your vertical offset must be between -100% and 100%! - Dein vertikaler Abstand muss zwischen -100% und 100% sein! + + Sets the theme used in-game. If the new theme changes the lobby's look as well, you'll need to reload the Lobby for the changes to take effect, such as by joining a server and leaving it. + - That vertical offset does not look like one. - Das sieht nicht wie ein Abstand aus. + + Theme: + Theme: - You switched your music and area list. - Du hast zwischen Musik- und Gebitsliste umgeschaltet. + + - Keep current setting - + - You have forcefully enabled features that the server may not support. You may not be able to talk IC, or worse, because of this. - Du hast Funktionen erzwungen die der Server eventuell nicht unterstützt. Möglicherweise wirst du nicht mehr sprechen können. + + - Default + - Your pre-animations interrupt again. - Deine Voranimation unterbrechen nun Text. + + en - English + - Your pre-animations will not interrupt text. - Deine Voranimation unterbrechen Text nicht. + + de - Deutsch + - Couldn't open chatlog.txt to write into. - Konnte chatlog.txt nicht öffnen. + + es - Español + - The IC chatlog has been saved. - Der IC Verlauf wurde gespeichert. + + pt - Português + - - 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. - Du hattest keinen 'base/cases' Ordner! Ich hab ihn nun angelegt aber bedenke das er leer sein wird. + + pl - Polskie + - - 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. -Cases you can load: %1 - Du musst einen Dateinamen angeben (ohne .ini). Stelle sicher das er im 'base/cases' Ordner ist und das er korrekt formatiert ist. -Verfügbare Fälle: %1 + + jp - 日本語 + - - Case made by %1. - Fall von %1. + + ru - Русский + - - Navigate to %1 for the CM doc. - Gehe zu %1 für das CM Dokument. + + Send screen-shaking, flashes and sounds as defined in the char.ini over the network. Only works for servers that support this functionality. + Sendet schüttel, Blitze und Geräusche aus der char.ini Datei über das Netzwerk. Funkioniert nur wenn der Server dies unterstützt. - - - - - UNKNOWN - UNBEKANNT + + Network Frame Effects: + Netzwerk Frame-Effekte: - - Your case "%1" was loaded! - Dein Fall "%1" wurde geladen! + + Chat Rate Limit: + Chat Rate Limit: - 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. -Cases you can load: - Du musst einen Dateinamen angeben (ohne .ini). Stelle sicher das er im 'base/cases' Ordner ist und das er korrekt formatiert ist. -Verfügbare Fälle: + + If ticked, themes will be allowed to have animated elements. + Aktiviert animierte Theme Elemente. - - Too many arguments to load a case! You only need one filename, without extension. - Zu viele Argumente! Du brauchst nur den Dateinamen, ohne Erweiterung. + + Animated Theme: + Animiertes Theme: - Case made by - Fall von + + Amount of time (in miliseconds) spent on each letter when the in-character text is being displayed. + Zeit (in Milisekunden) für jeden Buchstaben. - Navigate to - Gehe zu + + Text crawl: + Kriechender Text: - for the CM doc. - für das CM Dokument. + + Refresh the theme and update all of the ui elements to match. + Aktualisiert das Design und alle UI Elemente. - Your case " - Dein Fall " + + Reload Theme + Aussehen neu laden - " was loaded! - " wurde geladen! + + Your showname will be automatically set to this value when you join a server. + Dein Anzeigename wird automatisch gesetzt wenn du einem Server beitritts. - - 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. - Du hattest keinen 'base/cases' Ordner! Ich hab ihn nun angelegt aber bedenke das er leer sein wird. + + Default showname: + Standard Anzeigename: - - You need to give a filename to save (extension not needed) and the courtroom status! - Du musst einen Dateinamen (ohne Erweiterung) angebenn, sowie den Gebietsstatus! + + Turn this on to allow characters to define their own stickers (unique images that show up over the chatbox - like avatars or shownames). + An zeigt 'Sticker' an, kleine Bilder wie Avatare. - - Too many arguments to save a case! You only need a filename without extension and the courtroom status! - Zu viele Argumente! Du brauchst nur den Dateinamen, ohne Erweiterung sowie den Gebietsstatus! + + Stickers: + Sticker: - - Succesfully saved, edit doc and cmdoc link on the ini! - Erfolgreich gespeichert! + + Turn this on to prevent preanimation checkbox from clearing after playing the emote. + Aktiviere dies damit das Kontrollkästchen für die Voranimation nicht zurückspringt nachdem sie abgespielt wurde. - Master - Master + + Sticky Preanims: + Klebende Voranimation: - - Stop Current Song - Lied stoppen + + Gives the default value for the in-game 'Custom shownames' tickbox, which in turn determines whether the client should display custom in-character names. + Standardwert für die Anzeigename Box, welche den In-Charakter Namen bestimmt. - - Play Random Song - Zufälliges Lied + + Custom shownames: + Eigener Anzeigename: - - Expand All Categories - Alle Kategorien erweitern + + Turn this on to prevent the effects dropdown from clearing the effect after playing it. + Aktiviere dies damit die Effektauswahl nicht zurückspringt nachdem er abgespielt wurde. - - Collapse All Categories - Alle Kategorien verstecken + + Sticky Effects: + Klebende Effekt: - - Fade Out Previous - Vorheriges ausblenden + + Minimum amount of time (in miliseconds) an IC message must stay on screen before the next IC message is shown, acting as a 'queue'. Set to 0 to disable this behavior. + Minimale Zeit (in Milisekunden) die eine IC Nachricht auf dem Bildschirm bleibt bevore die nächste kommt, wie eine Art 'Warteschlange'. 0 deaktiviert das. - - Fade In - Einblenden + + Text Stay Time: + Standzeit: - - Synchronize - Synchronisieren + + Sets the language if you don't want to use your system language. + Setzte die Sprache falls du nicht die Systemsprache verwenden möchtest. - - Default - Standard + + Language: + Sprache: - - Reason: - Grund: + + If the SFX dropdown has an SFX selected, send the custom SFX alongside the message even if Preanim is OFF. + - - Call Moderator - Moderator rufen + + Always Send SFX: + SFX immer senden: - - - Error - Fehler + + Turn this on to prevent the sound dropdown from clearing the sound after playing it. + Aktiviere dies damit die Geräuschauswahl nicht zurückspringt nachdem es abgespielt wurde. - - You must provide a reason. - Du musst einen Grund angeben. + + Sticky Sounds: + Klebende Geräuschauswahl: - - The message is too long. - Die Nachricht ist zu lang. + + Your OOC name will be automatically set to this value when you join a server. + Dein OOC Name wird automatisch auf dies gesetzt. - - Choose.. - Wähle.. + + Default username: + Standard Benutzername: - Choose... - Wähle... + + Allows screenshaking. Disable this if you have concerns or issues with photosensitivity and/or seizures. + Erlaubt schütteln des Bildschirms. Deaktiviere dies falls du Bedenken wegen Photosensitivität hast. - - Present this piece of evidence to everyone on your next spoken message - Präsentiere dieses Beweisstück allen in der nächsten Nachricht + + Allow Screenshake: + Schütteln erlauben: - - Save evidence to an .ini file. - Speichere Beweise in einer .ini Datei. + + Allows others on Discord to see what server you are in, what character are you playing, and how long you have been playing for. + Erlaubt anderen auf Discord zu sehen auf welchem Server du spielst, welchen Charakter du spielst und wie lange. - - Load evidence from an .ini file. - Lade Beweise aus einer .ini Datei. + + Discord: + Discord: - - Destroy this piece of evidence - Zerstöre dieses Beweisstück + + Use the markup colors in the server IC chatlog. + Verwendet Farbe im IC Log so wie im Bild. - - Close the evidence display/editing overlay. -You will be prompted if there's any unsaved changes. - Schließe das Beweisfenster. -Du wirst gefragt wenn es ungespeicherte Änderungen gibt. + + Colors in IC Log: + Farben im IC Log: - - Save any changes made to this piece of evidence and send them to server. - Speichert alle Änderungen an diesem Beweisstück und schickt sie zum Server. + + Sets a 'subtheme', which will stack on top of the current theme and replace anything it can. Keep it at 'server' to let the server decide. Keep it at 'default' to keep it unchanging. + - Double-click to edit. Press [X] to update your changes. - Doppelklick zum bearbeiten. Klicke [X] um die Änderungen zu übernehmen. + + Subtheme: + Untertheme: - - Click to edit. Press [X] to update your changes. + + If ticked, Evidence needs a double-click to view rather than a single click. - - Bring up the Evidence screen. - Zeigt die Beweisliste. + + Evidence Double Click: + Doppelklick für Beweise: - - Switch evidence to private inventory. - Wechselt zum eigenen Inventar. + + Whether or not to resume playing animations from where they left off. Turning off might reduce lag. + Spielt Animationen wieder dort ab wo sie aufgehört haben. Ausschalten kann bei Lag helfen. - - Switch evidence to global inventory. - Wechselt zum globalen Inventar. + + Continuous Playback: + Durchgehendes Abspielen: - - - Transfer evidence to private inventory. - Übertrage Beweisstück zum eigenen Inventar. + + Callwords + Alarmwörter - - - Transfer evidence to global inventory. - Übertrage Beweisstück zum globalen Inventar. + + <html><head/><body><p>Enter as many callwords as you would like. These are case insensitive. Make sure to leave every callword in its own line!<br/><br/>Do not leave a line with a space at the end -- you will be alerted everytime someone uses a space in their messages.</p></body></html> + - - The piece of evidence you've been editing has changed. - Das Beweisstück das du bearbeitet hast hat sich verändert. + + Audio + Audio - - Do you wish to keep your changes? - Möchtest du deine Änderungen behalten? + + Audio device: + Audiogerät: - - Name: %1 -Image: %2 -Description: -%3 - Name: %1 -Bild: %2 -Beschreibung: -%3 + + Sets the music's default volume. + Setzt die Musiklautstärke. - - Images (*.png) - Bilder (*.png) + + Music: + Musik: - - - - Click to edit... + + + + + % - Double-click to edit... - Doppelklick zum bearbeiten... + + Sets the SFX's default volume. Interjections and actual sound effects count as 'SFX'. + Setzt die Lautstärke der Soundeffekte wie Einsprüche und die Geräusche der Charaktere. - - Add new evidence... - Neues Beweisstück... + + SFX: + SFX: - - Evidence has been modified. - Beweise wurden verändert. + + Sets the volume of the blips, the talking sound effects. + Setzt die Lautstärke der Blips, das ist das Geräusch das die Charaktere beim Reden machen. - - Do you want to save your changes? - Möchtest du deine Änderungen speichen? + + Blips: + Blips: - - Current evidence is global. Click to switch to private. - Beweise sind global. Klicken um zu eigenen zu wechseln. + + How much of the volume to suppress when client is not in focus. + - - Current evidence is private. Click to switch to global. - Beweise sind die eigenen. Klicken um zu global zu wechseln. + + Suppress Audio: + - - "%1" has been transferred. - "%1" wurde übertragen. + + Sets the delay between playing the blip sounds. + Setzt die Pause zwischen einzelnen Blips. - - Save Inventory - Inventar speichen + + Blip rate: + Bliprate: - - - Ini Files (*.ini) - Ini Dateien (*.ini) + + Play a blip sound \"once per every X symbols\", where X is the blip rate. 0 plays a blip sound only once. + - - Open Inventory - Inventar öffnen + + If true, the game will play a blip sound even when a space is 'being said'. + Wenn angehakt wird das Spiel auch bei einem Leerzeichen einen Blip machen. - - - DemoServer - - - Load Demo - Demo laden + + Blank blips: + Leere Blips: - - - Demo Files (*.demo) - Demos (*.demo) + + If true, the game will allow looping sound effects to play on preanimations. + Wenn aktiviert, werden wiederholende Soundeffekte bei den Voranimationen erlaubt. - - - Demo file loaded. Send /play or > in OOC to begin playback. - + + Enable Looping SFX: + Wiederholende Soundeffekte: - - Resuming playback. + + If true, AO2 will ask the server to stop music when you use 'Objection!' - - Pausing playback. - + + Kill Music On Objection: + Stoppe Musik bei Einspruch: - - Setting max_wait to + + If true, AO2 will not play any streamed audio and show that streaming is disabled. - - - milliseconds. + + Disable Music Streaming: - - Not a valid integer! + + + Casing - - Current max_wait is - + + Pretty self-explanatory. + Eigentlich selbsterklärend. - - Current demo file reloaded. Send /play or > in OOC to begin playback. - + + This server does not support case alerts. + Dieser Server unterstützt Fallalarme nicht. - - min_wait is deprecated. Use the client Settings for minimum wait instead! - + + If checked, you will get alerts about case announcements. + Wenn angehakt wirst du benachrichtigt wenn ein Fall angekündigt wird. - - Setting debug mode to %1 - + + If checked, you will get alerts about case announcements if a defense spot is open. + Wenn angehakt wirst du benachrichtigt wenn ein Verteidiger benötigt wird. - - Valid values are 1 or 0! + + Defense - - 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. - + + If checked, you will get alerts about case announcements if a juror spot is open. + Wenn angehakt wirst du benachrichtigt wenn eine Jury benötigt wird. - - Available commands: -load, reload, play, pause, max_wait, debug, help + + Juror - - Reached the end of the demo file. Send /play or > in OOC to restart, or /load to open a new file. - + + If checked, you will get alerts about case announcements if a stenographer spot is open. + Wenn angehakt wirst du benachrichtigt wenn ein Stenograph benötigt wird. - - - Discord - Objection! - Einspruch! + + Stenographer + - In Lobby - In Lobby + + If checked, you will appear amongst the potential CMs on the server. + Wenn angehakt wirst du als potentielle CM angezeigt. - Idle - Untätig + + Case Master + - In a Server - In einem Server + + If you're a CM, enter what cases you are willing to host. + Wenn du CM bist, gib ein welche Fälle du spielen möchtest. - Playing as %1 - Spielt als %1 + + Hosting cases: + Fallleitung: - Spectating - Zuschauend + + If checked, you will get alerts about case announcements if a prosecutor spot is open. + Wenn angehakt wirst du benachrichtigt wenn ein Kläger benötigt wird. - - - Lobby - Attorney Online - Attorney Online + + Prosecution + - - Attorney Online %1 - Attorney Online %1 + + If checked, you will get alerts about case announcements if the judge spot is open. + Wenn angehakt wirst du benachrichtigt wenn ein Richter benötigt wird. - - Search - Suche + + Judge + - Name - Name + + Assets + - - It doesn't look like your client is set up correctly. -Did you download all resources correctly from tiny.cc/getao, including the large 'base' folder? - Dein Client ist nicht korrekt eingerichtet. -Hast du ALLES von tiny.cc/getao heruntergeladen und entpackt, auch den großen 'base' Ordner? + + <html><head/><body><p>Add or remove base folders for use by assets.</p><p><br/>Base folders on the bottom are prioritized over those above them.</p></body></html> + - - Version: %1 - Version: %1 + + ↓ + - - Settings - Einstellungen + + Remove + - - Allows you to change various aspects of the client. - Erlaubt es verschiedene Aspekte des Clients zu ändern. + + ↑ + - - Loading - Laden + + Add... + - - Cancel - Abbrechen + + Clears the lookup cache for assets. +Use this when you have added an asset that takes precedence over another existing asset. + - - <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<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>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-2021 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 + + Clear Cache - - Couldn't get the message of the day. + + Logging - - Version: %1 (!) + + If ticked, new messages will appear at the bottom (like the OOC chatlog). The traditional (AO1) behaviour is equivalent to this being unticked. + Wenn angehakt werden neue Nachrichten unten erscheinen (wie beim OOC). Das traditionelle (AO1) Verhalten wäre nicht angehakt. + + + + Log goes downwards: + Verlauf geht nach unten: + + + + The amount of message lines the IC chatlog will keep before deleting older message lines. A value of 0 or below counts as 'infinite'. + Die menge an Zeilen die das IC Log behält bevor ältere Nachrichten gelöscht werden. 0 bedeutet unendlich. + + + + Log length: + Länge: + + + + entries - - New version available: %1 + + If ticked, new messages will appear separated, with the message coming on the next line after the name. +When unticked, it displays it as 'name: message'. - <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<p><b>Client development:</b><br>Cents02, in1tiate, raidensnake, windrammer<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>Special thanks:</b><br>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-2020 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 - <h2>Attorney Online %1</h2>Der Gerichtsdrama Simulator<p><b>Quelltext:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Leitende Entwicklung:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Crystalwarrior, Iamgoofball<p><b>Cliententwicklung:</b><br>Cents02, in1tiate, raidensnake, windrammer<p><b>Qualitätssicherung:</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>Danksagungen:</b><br>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, und FanatSors (AO1); Serverbetreiber, Gamemaster, Fallersteller, Inhaltsersteller und die ganze AO2 Community!<p>Das Attorney Online networked visual novel Projekt ist copyright (c) 2016-2020 Attorney Online Entwickler. Unter Open-Source Lizenz. Alle anderen Inhalte sind Eigentum ihrer Besitzer.<p>Läuft auf Qt version %2 mit der BASS Audio Engine.<br>APNG plugin geladen: %3<p>Built on %4 + + Log newline: + Absätze protokollieren: - - Yes - Ja + + The distance in pixels between each entry in the IC log. +Default: 0. + - - No - Nein + + Log margin: + Protokollabstand: - <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<p><b>2.8 Major Release development:</b><br>Crystalwarrior, Iamgoofball<p><b>2.8 Quality Assurance:</b><br>WillDean, Captain N, Mr M, Riel, Seimmet, Fury McFlurry,CedricDewitt, Chewable Tablets, Fantos, Futugaze,Geck, Minx, Pandae, Sierra, CrazyJC, CaseyMayCazy,GreenBowers, Robotic Overlord, Veritas, Gin-Gi<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, the AO2 community, server hosts, game masters,case makers, content creators and players! - <h2>Attorney Online %1</h2>Der Gerichtsdrama Simulator<p><b>Quelltext:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Leitende Entwicklung:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Version 2.8 Entwicklung:</b><br>Crystalwarrior, Iamgoofball<p><b>2.8 Qualitätskontrolle:</b><br>WillDean, Captain N, Mr M, Riel, Seimmet, Fury McFlurry,CedricDewitt, Chewable Tablets, Fantos, Futugaze,Geck, Minx, Pandae, Sierra, CrazyJC, CaseyMayCazy,GreenBowers, Robotic Overlord, Veritas, Gin-Gi<p><b>Danksagungen:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, die AO2 Community, Serverbetreiber, Gamemaster, Fallersteller, Inhaltersteller und Spieler! + + px + - - About - Über + + If ticked, log will contain a timestamp in UTC before the name. + Das Protokoll enthält vor dem Namen einen Zeitstempel in UTC. - <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, Cents02<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake - <h2>Attorney Online %1</h2>Der Gerichtsdrama Simulator<p><b>Quelltext:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Leitende Entwicklung:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, Cents02<p><b>Danksagungen:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy, Raidensnake + + Log timestamp: + Zeitstempel: - <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<p><b>Special thanks:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy - <h2>Attorney Online %1</h2>Der Gerichtsdrama Simulator<p><b>Quelltext:</b> <a href='https://github.com/AttorneyOnline/AO2-Client'>https://github.com/AttorneyOnline/AO2-Client</a><p><b>Leitende Entwicklung:</b><br>OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter<p><b>Danksagungen:</b><br>Remy, Iamgoofball, Hibiki, Qubrick (webAO), Ruekasu (UI design), Draxirch (UI design), Unishred, Argoneus (tsuserver), Fiercy, Noevain, Cronnicossy + + Log timestamp format: + + - - Online: %1/%2 - Online: %1/%2 + + h:mm:ss AP + - Attorney Online 2 is built using Qt 5.11. - -Lead development: -longbyte1 -OmniTroid - -stonedDiscord -Supporting development: -Fiercy - -UI design: -Ruekasu -Draxirch - -Special thanks: -Unishred -Argoneus -Noevain -Cronnicossy - Attorney Online 2 wurde gemacht mit Qt 5.11. - -Leitende Entwicklung: -longbyte1 -OmniTroid -stonedDiscord - -Unterstützende Entwicklung: -Fiercy - -UI Design: -Ruekasu -Draxirch - -Speziellen Dank: -Unishred -Argoneus -Noevain -Cronnicossy - - - - - Offline - Offline + + hh:mm:ss + - - - NetworkManager - - No description provided. + + h:mm AP - - - QDialogButtonBox - - - OK + + hh:mm - - - QObject - - None - Keine + + If ticked, log will show IC actions such as shouting and presenting evidence. + Protokolliert Charakteraktionen wie Zwischenrufe und Beweisstücke. - - [MISSING] %1 - [FEHLT] %1 + + Log IC actions: + Aktionen protokollieren: - - [STREAM] %1 - [STREAM] %1 + + If ticked, log will show messages as-received, while viewport will parse according to the queue (Text Stay Time). + Wenn angehakt werden die Nachrichten sofort im Protokoll angezeigt, ansonsten wartet es auf den Chat. - - - chatlogpiece - - - - UNKNOWN - UNBEKANNT + + Desynchronize IC Logs: + Protokoll desynchronisieren: - has played a song: - hat ein Lied gespielt: + + Text logs of gameplay will be automatically written in the /logs folder. + - - - debug_functions - - Error: %1 - Fehler: %1 + + Log to Text Files: + - - Error - Fehler + + Gameplay will be automatically recorded as demos in the /logs folder. + - - Notice - Hinweis + + Log to Demo Files: + + + + + Privacy + + + + + Do not include me in public player counts + diff --git a/resource/ui/options_dialog.ui b/resource/ui/options_dialog.ui new file mode 100644 index 000000000..d63643248 --- /dev/null +++ b/resource/ui/options_dialog.ui @@ -0,0 +1,1302 @@ + + + optionsdialogue + + + + 0 + 0 + 450 + 415 + + + + Qt::NoContextMenu + + + Settings + + + + + + Qt::NoFocus + + + 0 + + + + Gameplay + + + + + + true + + + + + 0 + 0 + 389 + 701 + + + + + + + + + + + + + + Stop music when double-clicking a category. If this is disabled, use the right-click context menu to stop music. + + + Stop Music w/ Category: + + + + + + + + + + + + + + + + + Sets the default scaling method, if there is not one already defined specifically for the character. + + + Scaling: + + + + + + + Turn this on to allow characters to define their own custom chat box designs. + + + Custom Chatboxes: + + + + + + + Allows screen effects. Disable this if you have concerns or issues with photosensitivity and/or seizures. + + + Allow Effects: + + + + + + + + + + + + + + Open the theme folder of the currently selected theme. + + + Open Theme Folder + + + + + + + Overrides the base URL to retrieve server information from. + + + Alternate Server List: + + + + + + + Instant Objection: + + + + + + + ms + + + 500 + + + + + + + Sets the theme used in-game. If the new theme changes the lobby's look as well, you'll need to reload the Lobby for the changes to take effect, such as by joining a server and leaving it. + + + Theme: + + + + + + + + en + + + + + de + + + + + es + + + + + pt + + + + + pl + + + + + jp + + + + + ru + + + + + + + + + + + Send screen-shaking, flashes and sounds as defined in the char.ini over the network. Only works for servers that support this functionality. + + + Network Frame Effects: + + + + + + + Chat Rate Limit: + + + Qt::AutoText + + + + + + + ms + + + 5000 + + + + + + + If ticked, themes will be allowed to have animated elements. + + + Animated Theme: + + + + + + + Amount of time (in miliseconds) spent on each letter when the in-character text is being displayed. + + + Text crawl: + + + + + + + Refresh the theme and update all of the ui elements to match. + + + Reload Theme + + + + + + + + + + + + + + + + + Your showname will be automatically set to this value when you join a server. + + + Default showname: + + + + + + + + + + + + + + + + + Turn this on to allow characters to define their own stickers (unique images that show up over the chatbox - like avatars or shownames). + + + Stickers: + + + + + + + Turn this on to prevent preanimation checkbox from clearing after playing the emote. + + + Sticky Preanims: + + + + + + + ms + + + 10000 + + + + + + + Gives the default value for the in-game 'Custom shownames' tickbox, which in turn determines whether the client should display custom in-character names. + + + Custom shownames: + + + + + + + Turn this on to prevent the effects dropdown from clearing the effect after playing it. + + + Sticky Effects: + + + + + + + + + + + + + + Minimum amount of time (in miliseconds) an IC message must stay on screen before the next IC message is shown, acting as a 'queue'. Set to 0 to disable this behavior. + + + Text Stay Time: + + + + + + + Sets the language if you don't want to use your system language. + + + Language: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + If the SFX dropdown has an SFX selected, send the custom SFX alongside the message even if Preanim is OFF. + + + Always Send SFX: + + + + + + + Turn this on to prevent the sound dropdown from clearing the sound after playing it. + + + Sticky Sounds: + + + + + + + + + + + + + + Your OOC name will be automatically set to this value when you join a server. + + + Default username: + + + + + + + Allows screenshaking. Disable this if you have concerns or issues with photosensitivity and/or seizures. + + + Allow Screenshake: + + + + + + + + + + + + + + Allows others on Discord to see what server you are in, what character are you playing, and how long you have been playing for. + + + Discord: + + + + + + + Use the markup colors in the server IC chatlog. + + + Colors in IC Log: + + + + + + + Sets a 'subtheme', which will stack on top of the current theme and replace anything it can. Keep it at 'server' to let the server decide. Keep it at 'default' to keep it unchanging. + + + Subtheme: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + QFrame::HLine + + + QFrame::Sunken + + + + + + + QFrame::HLine + + + QFrame::Sunken + + + + + + + + + + + + + + If ticked, Evidence needs a double-click to view rather than a single click. + + + Evidence Double Click: + + + + + + + QFrame::HLine + + + QFrame::Sunken + + + + + + + + + + + + + + Whether or not to resume playing animations from where they left off. Turning off might reduce lag. + + + Continuous Playback: + + + + + + + 30 + + + + + + + + + + + + Callwords + + + + + + + + + <html><head/><body><p>Enter as many callwords as you would like. These are case insensitive. Make sure to leave every callword in its own line!<br/><br/>Do not leave a line with a space at the end -- you will be alerted everytime someone uses a space in their messages.</p></body></html> + + + true + + + + + + + + Audio + + + + + + Audio device: + + + + + + + + + + Sets the music's default volume. + + + Music: + + + + + + + % + + + 100 + + + + + + + Sets the SFX's default volume. Interjections and actual sound effects count as 'SFX'. + + + SFX: + + + + + + + % + + + 100 + + + + + + + Sets the volume of the blips, the talking sound effects. + + + Blips: + + + + + + + % + + + 100 + + + + + + + How much of the volume to suppress when client is not in focus. + + + Suppress Audio: + + + + + + + % + + + 100 + + + + + + + Sets the delay between playing the blip sounds. + + + Blip rate: + + + + + + + Play a blip sound \"once per every X symbols\", where X is the blip rate. 0 plays a blip sound only once. + + + + + + + If true, the game will play a blip sound even when a space is 'being said'. + + + Blank blips: + + + + + + + + + + + + + + If true, the game will allow looping sound effects to play on preanimations. + + + Enable Looping SFX: + + + + + + + + + + + + + + If true, AO2 will ask the server to stop music when you use 'Objection!' + + + Kill Music On Objection: + + + + + + + + + + + + + + If true, AO2 will not play any streamed audio and show that streaming is disabled. + + + Music Streaming enabled: + + + + + + + + + + + + + + QFrame::HLine + + + QFrame::Sunken + + + + + + + QFrame::HLine + + + QFrame::Sunken + + + + + + + + Casing + + + + + + If checked, you will get alerts about case announcements. + + + Casing + + + true + + + false + + + + + + If checked, you will get alerts about case announcements if a defense spot is open. + + + Defense + + + + + + + If checked, you will get alerts about case announcements if a juror spot is open. + + + Juror + + + + + + + If checked, you will get alerts about case announcements if a stenographer spot is open. + + + Stenographer + + + + + + + If checked, you will appear amongst the potential CMs on the server. + + + Case Master + + + + + + + + + If you're a CM, enter what cases you are willing to host. + + + Hosting cases: + + + + + + + + + + + + If checked, you will get alerts about case announcements if a prosecutor spot is open. + + + Prosecution + + + + + + + If checked, you will get alerts about case announcements if the judge spot is open. + + + Judge + + + + + + + + + + Qt::Vertical + + + + 20 + 338 + + + + + + + + + + 0 + 0 + + + + Assets + + + + + + + 0 + 0 + + + + <html><head/><body><p>Add or remove base folders for use by assets.</p><p><br/>Base folders on the bottom are prioritized over those above them.</p></body></html> + + + true + + + + + + + + 0 + 0 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 40 + 16777215 + + + + + + + + + + + + 0 + 0 + + + + Remove + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 20 + + + + + + + + + 40 + 16777215 + + + + + + + + + + + + 0 + 0 + + + + Add... + + + + + + + + 0 + 0 + + + + Clears the lookup cache for assets. +Use this when you have added an asset that takes precedence over another existing asset. + + + Clear Cache + + + + + + + + + + Logging + + + + + + If ticked, new messages will appear at the bottom (like the OOC chatlog). The traditional (AO1) behaviour is equivalent to this being unticked. + + + Log goes downwards: + + + + + + + + + + + + + + The amount of message lines the IC chatlog will keep before deleting older message lines. A value of 0 or below counts as 'infinite'. + + + Log length: + + + + + + + entries + + + 10000 + + + + + + + If ticked, new messages will appear separated, with the message coming on the next line after the name. +When unticked, it displays it as 'name: message'. + + + Log newline: + + + + + + + + + + + + + + The distance in pixels between each entry in the IC log. +Default: 0. + + + Log margin: + + + + + + + px + + + 1000 + + + + + + + If ticked, log will contain a timestamp in UTC before the name. + + + Log timestamp: + + + + + + + + + + + + + + Log timestamp format: + + + + + + + + true + + + + h:mm:ss AP + + + + + hh:mm:ss + + + + + h:mm AP + + + + + hh:mm + + + + + + + + If ticked, log will show IC actions such as shouting and presenting evidence. + + + Log IC actions: + + + + + + + + + + + + + + If ticked, log will show messages as-received, while viewport will parse according to the queue (Text Stay Time). + + + Desynchronize IC Logs: + + + + + + + + + + + + + + Text logs of gameplay will be automatically written in the /logs folder. + + + Log to Text Files: + + + + + + + + + + + + + + Gameplay will be automatically recorded as demos in the /logs folder. + + + Log to Demo Files: + + + + + + + + + + + + + + + Privacy + + + + + + Do not include me in public player counts + + + + + + + QFrame::HLine + + + QFrame::Sunken + + + + + + + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::RestoreDefaults|QDialogButtonBox::Save + + + + + + + + diff --git a/resources.qrc b/resources.qrc index cca23ef6c..793a66bd8 100644 --- a/resources.qrc +++ b/resources.qrc @@ -9,5 +9,6 @@ resource/translations/ao_pl.qm resource/translations/ao_pt.qm resource/translations/ao_ru.qm + resource/ui/options_dialog.ui diff --git a/src/aoapplication.cpp b/src/aoapplication.cpp index 856b8adab..a162596f1 100644 --- a/src/aoapplication.cpp +++ b/src/aoapplication.cpp @@ -4,9 +4,10 @@ #include "debug_functions.h" #include "lobby.h" #include "networkmanager.h" +#include "options.h" #include "aocaseannouncerdialog.h" -#include "aooptionsdialog.h" +#include "widgets/aooptionsdialog.h" static QtMessageHandler original_message_handler; static AOApplication *message_handler_context; @@ -19,10 +20,6 @@ void message_handler(QtMsgType type, const QMessageLogContext &context, AOApplication::AOApplication(int &argc, char **argv) : QApplication(argc, argv) { - // Create the QSettings class that points to the config.ini. - configini = - new QSettings(get_base_path() + "config.ini", QSettings::IniFormat); - net_manager = new NetworkManager(this); discord = new AttorneyOnline::Discord(); @@ -40,7 +37,6 @@ AOApplication::~AOApplication() destruct_lobby(); destruct_courtroom(); delete discord; - delete configini; qInstallMessageHandler(original_message_handler); } @@ -60,7 +56,7 @@ void AOApplication::construct_lobby() int y = (geometry.height() - w_lobby->height()) / 2; w_lobby->move(x, y); - if (is_discord_enabled()) + if (Options::getInstance().discordEnabled()) discord->state_lobby(); if (demo_server) @@ -124,8 +120,6 @@ QString AOApplication::get_version_string() QString::number(MINOR_VERSION); } -void AOApplication::reload_theme() { current_theme = read_theme(); } - void AOApplication::load_favorite_list() { favorite_list = read_favorite_servers(); @@ -200,8 +194,18 @@ void AOApplication::loading_cancelled() void AOApplication::call_settings_menu() { - AOOptionsDialog settings(nullptr, this); - settings.exec(); + AOOptionsDialog* l_dialog = new AOOptionsDialog(nullptr, this); + if (courtroom_constructed) { + connect(l_dialog, &AOOptionsDialog::reloadThemeRequest, + w_courtroom, &Courtroom::on_reload_theme_clicked); + } + + if(lobby_constructed) { + connect(l_dialog, &AOOptionsDialog::reloadThemeRequest, + w_lobby, &Lobby::set_widgets); + } + l_dialog->exec(); + delete l_dialog; } void AOApplication::call_announce_menu(Courtroom *court) @@ -238,13 +242,13 @@ void AOApplication::initBASS() unsigned int a = 0; BASS_DEVICEINFO info; - if (get_audio_output_device() == "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 (get_audio_output_device() == info.name) { + if (Options::getInstance().audioOutputDevice() == info.name) { BASS_SetDevice(a); BASS_Init(static_cast(a), 48000, BASS_DEVICE_LATENCY, nullptr, nullptr); diff --git a/src/aobutton.cpp b/src/aobutton.cpp index 6d25a05f6..5ef2a066c 100644 --- a/src/aobutton.cpp +++ b/src/aobutton.cpp @@ -2,6 +2,7 @@ #include "debug_functions.h" #include "file_functions.h" +#include "options.h" AOButton::AOButton(QWidget *parent, AOApplication *p_ao_app) : QPushButton(parent) @@ -20,8 +21,8 @@ void AOButton::set_image(QString p_path, QString p_misc) { movie->stop(); QString p_image; - p_image = ao_app->get_image(p_path, ao_app->current_theme, ao_app->get_subtheme(), - ao_app->default_theme, p_misc, "", "", !ao_app->get_animated_theme()); + 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()); @@ -33,7 +34,7 @@ void AOButton::set_image(QString p_path, QString p_misc) movie->setFileName(p_image); // We double-check if the user wants animated themes, so even if an animated image slipped through, // we still set it static - if (ao_app->get_animated_theme() && movie->frameCount() > 1) { + if (Options::getInstance().animatedThemeEnabled() && movie->frameCount() > 1) { movie->start(); } else { diff --git a/src/aoimage.cpp b/src/aoimage.cpp index c488a0938..e737ffb3e 100644 --- a/src/aoimage.cpp +++ b/src/aoimage.cpp @@ -1,6 +1,7 @@ #include "file_functions.h" #include "aoimage.h" +#include "options.h" #include @@ -28,9 +29,9 @@ AOImage::~AOImage() {} bool AOImage::set_image(QString p_image, QString p_misc) { - QString p_image_resolved = ao_app->get_image(p_image, ao_app->current_theme, ao_app->get_subtheme(), + QString p_image_resolved = ao_app->get_image(p_image, Options::getInstance().theme(), Options::getInstance().subTheme(), ao_app->default_theme, p_misc, "", "", - is_static || !ao_app->get_animated_theme()); + is_static || !Options::getInstance().animatedThemeEnabled()); if (!file_exists(p_image_resolved)) { qWarning() << "could not find image" << p_image; @@ -41,11 +42,11 @@ bool AOImage::set_image(QString p_image, QString p_misc) if (!is_static) { movie->stop(); movie->setFileName(path); - if (ao_app->get_animated_theme() && movie->frameCount() > 1) { + if (Options::getInstance().animatedThemeEnabled() && movie->frameCount() > 1) { movie->start(); } } - if (is_static || !ao_app->get_animated_theme() || movie->frameCount() <= 1) { + if (is_static || !Options::getInstance().animatedThemeEnabled() || movie->frameCount() <= 1) { QPixmap f_pixmap(path); f_pixmap = diff --git a/src/aolayer.cpp b/src/aolayer.cpp index 27ebe48cd..71dd6c8da 100644 --- a/src/aolayer.cpp +++ b/src/aolayer.cpp @@ -2,6 +2,8 @@ #include "aoapplication.h" #include "file_functions.h" +#include "misc_functions.h" +#include "options.h" static QThreadPool *thread_pool; @@ -233,7 +235,7 @@ 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, ao_app->current_theme, ao_app->get_subtheme(), ao_app->default_theme, p_miscname, p_charname, "placeholder"); + QString final_image = ao_app->get_image(p_filename, Options::getInstance().theme(), Options::getInstance().subTheme(), ao_app->default_theme, p_miscname, p_charname, "placeholder"); start_playback(final_image); play(); } @@ -256,7 +258,7 @@ void InterfaceLayer::load_image(QString p_filename, QString p_miscname) { last_path = ""; stretch = true; - QString final_image = ao_app->get_image(p_filename, ao_app->current_theme, ao_app->get_subtheme(), ao_app->default_theme, p_miscname); + QString final_image = ao_app->get_image(p_filename, Options::getInstance().theme(), Options::getInstance().subTheme(), ao_app->default_theme, p_miscname); start_playback(final_image); play(); } @@ -264,10 +266,10 @@ void InterfaceLayer::load_image(QString p_filename, QString p_miscname) void StickerLayer::load_image(QString p_charname) { QString p_miscname; - if (ao_app->is_customchat_enabled()) + 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, ao_app->current_theme, ao_app->get_subtheme(), ao_app->default_theme, 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); play(); } @@ -296,7 +298,7 @@ void AOLayer::start_playback(QString p_image) QMutexLocker locker(&mutex); this->show(); - if (!ao_app->is_continuous_enabled()) { + if (!Options::getInstance().continuousPlaybackEnabled()) { continuous = false; force_continuous = true; } @@ -335,11 +337,7 @@ void AOLayer::start_playback(QString p_image) frame = 0; continuous = false; } -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) frame_loader = QtConcurrent::run(thread_pool, this, &AOLayer::populate_vectors); -#else - frame_loader = QtConcurrent::run(thread_pool, &AOLayer::populate_vectors, this); -#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 diff --git a/src/aomusicplayer.cpp b/src/aomusicplayer.cpp index f29e0cf99..c7090e67c 100644 --- a/src/aomusicplayer.cpp +++ b/src/aomusicplayer.cpp @@ -1,4 +1,5 @@ #include "aomusicplayer.h" +#include "options.h" AOMusicPlayer::AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app) { @@ -30,7 +31,7 @@ QString AOMusicPlayer::play(QString p_song, int channel, bool loop, DWORD newstream; if (f_path.startsWith("http")) { - if (ao_app->is_streaming_disabled()) { + if (!Options::getInstance().streamingEnabled()) { BASS_ChannelStop(m_stream_list[channel]); return QObject::tr("[MISSING] Streaming disabled."); } @@ -56,7 +57,7 @@ QString AOMusicPlayer::play(QString p_song, int channel, bool loop, int error_code = BASS_ErrorGetCode(); - if (ao_app->get_audio_output_device() != "default") + if (Options::getInstance().audioOutputDevice() != "default") BASS_ChannelSetDevice(m_stream_list[channel], BASS_GetDevice()); QString d_path = f_path + ".txt"; diff --git a/src/courtroom.cpp b/src/courtroom.cpp index a08b5e138..ebbf2c0ec 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1,4 +1,5 @@ #include "courtroom.h" +#include "options.h" Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() { @@ -114,15 +115,15 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_ic_chatlog->setReadOnly(true); ui_ic_chatlog->setObjectName("ui_ic_chatlog"); - log_maximum_blocks = ao_app->get_max_log_size(); - log_goes_downwards = ao_app->get_log_goes_downwards(); - log_colors = ao_app->is_colorlog_enabled(); - log_newline = ao_app->get_log_newline(); - log_margin = ao_app->get_log_margin(); - log_timestamp = ao_app->get_log_timestamp(); - log_timestamp_format = ao_app->get_log_timestamp_format(); + log_maximum_blocks = Options::getInstance().maxLogSize(); + 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(); - ui_debug_log = new AOTextArea(this, ao_app->get_max_log_size()); + ui_debug_log = new AOTextArea(this, Options::getInstance().maxLogSize()); ui_debug_log->setReadOnly(true); ui_debug_log->setOpenExternalLinks(true); ui_debug_log->hide(); @@ -176,7 +177,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_ic_chat_name = new QLineEdit(this); ui_ic_chat_name->setFrame(false); ui_ic_chat_name->setPlaceholderText(tr("Showname")); - ui_ic_chat_name->setText(p_ao_app->get_default_showname()); + ui_ic_chat_name->setText(Options::getInstance().shownameOnJoin()); ui_ic_chat_name->setObjectName("ui_ic_chat_name"); ui_ic_chat_message = new QLineEdit(this); @@ -200,7 +201,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_ooc_chat_name->setFrame(false); ui_ooc_chat_name->setPlaceholderText(tr("Name")); ui_ooc_chat_name->setMaxLength(30); - ui_ooc_chat_name->setText(p_ao_app->get_default_username()); + ui_ooc_chat_name->setText(Options::getInstance().username()); ui_ooc_chat_name->setObjectName("ui_ooc_chat_name"); // ui_area_password = new QLineEdit(this); @@ -316,13 +317,13 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_additive->setObjectName("ui_additive"); ui_casing = new QCheckBox(this); - ui_casing->setChecked(ao_app->get_casing_enabled()); + ui_casing->setChecked(Options::getInstance().casingAlertEnabled()); ui_casing->setText(tr("Casing")); ui_casing->hide(); ui_casing->setObjectName("ui_casing"); ui_showname_enable = new QCheckBox(this); - ui_showname_enable->setChecked(ao_app->get_showname_enabled_by_default()); + ui_showname_enable->setChecked(Options::getInstance().customShownameEnabled()); ui_showname_enable->setText(tr("Shownames")); ui_showname_enable->setObjectName("ui_showname_enable"); @@ -365,17 +366,17 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_music_slider = new QSlider(Qt::Horizontal, this); ui_music_slider->setRange(0, 100); - ui_music_slider->setValue(ao_app->get_default_music()); + ui_music_slider->setValue(Options::getInstance().musicVolume()); ui_music_slider->setObjectName("ui_music_slider"); ui_sfx_slider = new QSlider(Qt::Horizontal, this); ui_sfx_slider->setRange(0, 100); - ui_sfx_slider->setValue(ao_app->get_default_sfx()); + ui_sfx_slider->setValue(Options::getInstance().sfxVolume()); ui_sfx_slider->setObjectName("ui_sfx_slider"); ui_blip_slider = new QSlider(Qt::Horizontal, this); ui_blip_slider->setRange(0, 100); - ui_blip_slider->setValue(ao_app->get_default_blip()); + ui_blip_slider->setValue(Options::getInstance().blipVolume()); ui_blip_slider->setObjectName("ui_blip_slider"); ui_mute_list = new QListWidget(this); @@ -584,7 +585,7 @@ void Courtroom::on_application_state_changed(Qt::ApplicationState state) suppress_audio = 0; if (state != Qt::ApplicationActive) { // Suppressed audio setting - suppress_audio = ao_app->get_default_suppress_audio(); + suppress_audio = Options::getInstance().defaultSuppressAudio(); } update_audio_volume(); } @@ -668,9 +669,6 @@ void Courtroom::set_pair_list() void Courtroom::set_widgets() { QString filename = "courtroom_design.ini"; - // Update the default theme from the courtroom_design.ini, if it's not defined it will be 'default'. - QSettings settings(ao_app->get_real_path(ao_app->get_theme_path(filename, ao_app->current_theme)), QSettings::IniFormat); - ao_app->default_theme = settings.value("default_theme", "default").toString(); set_fonts(); set_size_and_pos(ui_viewport, "viewport"); @@ -748,20 +746,20 @@ void Courtroom::set_widgets() ui_vp_objection->move_and_center(ui_viewport->x(), ui_viewport->y()); ui_vp_objection->combo_resize(ui_viewport->width(), ui_viewport->height()); - log_maximum_blocks = ao_app->get_max_log_size(); - - bool regenerate = log_goes_downwards != ao_app->get_log_goes_downwards() || - log_colors != ao_app->is_colorlog_enabled() || - log_newline != ao_app->get_log_newline() || - log_margin != ao_app->get_log_margin() || - log_timestamp != ao_app->get_log_timestamp() || - log_timestamp_format != ao_app->get_log_timestamp_format(); - log_goes_downwards = ao_app->get_log_goes_downwards(); - log_colors = ao_app->is_colorlog_enabled(); - log_newline = ao_app->get_log_newline(); - log_margin = ao_app->get_log_margin(); - log_timestamp = ao_app->get_log_timestamp(); - log_timestamp_format = ao_app->get_log_timestamp_format(); + 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(); + 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) { regenerate_ic_chatlog(); } @@ -1390,7 +1388,7 @@ 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 (ao_app->is_sticker_enabled() && chatbox_always_show) { + if (Options::getInstance().characterStickerEnabled() && chatbox_always_show) { ui_vp_sticker->load_image(m_chatmessage[CHAR_NAME]); } // Hide the face sticker @@ -1486,7 +1484,7 @@ void Courtroom::update_character(int p_cid, QString char_name, bool reset_emote) QString f_char; if (m_cid == -1) { - if (ao_app->is_discord_enabled()) + if (Options::getInstance().discordEnabled()) ao_app->discord->state_spectate(); f_char = ""; } @@ -1496,7 +1494,7 @@ void Courtroom::update_character(int p_cid, QString char_name, bool reset_emote) f_char = char_list.at(m_cid).name; } - if (ao_app->is_discord_enabled()) + if (Options::getInstance().discordEnabled()) ao_app->discord->state_character(f_char.toStdString()); } @@ -1814,7 +1812,7 @@ void Courtroom::append_server_chatmessage(QString p_name, QString p_message, ui_server_chatlog->append_chatmessage(p_name, p_message, color); - if (ao_app->get_text_logging_enabled() && !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); } @@ -1841,7 +1839,7 @@ void Courtroom::on_chat_return_pressed() return; ui_ic_chat_message->blockSignals(true); - QTimer::singleShot(ao_app->get_chat_ratelimit(), this, + QTimer::singleShot(Options::getInstance().chatRateLimit(), this, [this] { ui_ic_chat_message->blockSignals(false); }); // MS# // deskmod# @@ -1945,7 +1943,7 @@ void Courtroom::on_chat_return_pressed() 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 (ao_app->get_sfx_on_idle() && (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 @@ -1985,7 +1983,7 @@ void Courtroom::on_chat_return_pressed() f_obj_state = QString::number(objection_state); // We're doing an Objection (custom objections not yet supported) - if (objection_state == 2 && ao_app->objection_stop_music()) + if (objection_state == 2 && Options::getInstance().objectionStopMusic()) music_stop(true); packet_contents.append(f_obj_state); @@ -2078,7 +2076,7 @@ void Courtroom::on_chat_return_pressed() QString packet; foreach (QString f_emote, emotes_to_check) { packet += f_emote; - if (ao_app->is_frame_network_enabled()) { + if (Options::getInstance().networkedFrameSfxEnabled()) { QString sfx_frames = ao_app ->read_ini_tags( @@ -2109,7 +2107,7 @@ void Courtroom::on_chat_return_pressed() } packet_contents.append(effect + "|" + p_effect_folder + "|" + fx_sound); - if (!ao_app->is_stickyeffects_enabled() && !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); @@ -2138,14 +2136,14 @@ 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 (!ao_app->is_stickysounds_enabled() && (ao_app->get_sfx_on_idle() || 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(); custom_sfx = ""; } // If sticky preanims is disabled - if (!ao_app->is_stickypres_enabled()) + if (!Options::getInstance().clearPreOnPlayEnabled()) // Turn off our Preanim checkbox ui_pre->setChecked(false); } @@ -2190,17 +2188,17 @@ void Courtroom::chatmessage_enqueue(QStringList p_contents) reset_ui(); } // If we determine we sent this message, or we have desync enabled - if (sender || ao_app->is_desyncrhonized_logs_enabled()) { + 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 || ao_app->is_desyncrhonized_logs_enabled()); + p_contents[TEXT_COLOR].toInt(), QUEUED, sender || Options::getInstance().desynchronisedLogsEnabled()); } bool is_objection = false; // If the user wants to clear queue on objection - if (ao_app->is_instant_objection_enabled()) + if (Options::getInstance().objectionSkipQueueEnabled()) { int objection_mod = p_contents[OBJECTION_MOD].split("&")[0].toInt(); is_objection = objection_mod >= 1 && objection_mod <= 5; @@ -2217,7 +2215,7 @@ void Courtroom::chatmessage_enqueue(QStringList p_contents) chatmessage_queue.enqueue(p_contents); // Our settings disabled queue, or no message is being parsed right now and we're not waiting on one - bool start_queue = ao_app->stay_time() <= 0 || (text_state >= 2 && !text_queue_timer->isActive()); + 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 @@ -2242,7 +2240,7 @@ void Courtroom::skip_chatmessage_queue() 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 = ao_app->is_desyncrhonized_logs_enabled() || p_contents[CHAR_ID].toInt() == m_cid; + bool sender = Options::getInstance().desynchronisedLogsEnabled() || p_contents[CHAR_ID].toInt() == m_cid; 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(), DISPLAY_ONLY, sender); } } @@ -2265,7 +2263,7 @@ void Courtroom::unpack_chatmessage(QStringList p_contents) } // if the char ID matches our client's char ID (most likely, this is our message coming back to us) - bool sender = ao_app->is_desyncrhonized_logs_enabled() || m_chatmessage[CHAR_ID].toInt() == m_cid; + bool sender = Options::getInstance().desynchronisedLogsEnabled() || m_chatmessage[CHAR_ID].toInt() == m_cid; // We have logs displaying as soon as we reach the message in our queue, which is a less confusing but also less accurate experience for the user. log_chatmessage(m_chatmessage[MESSAGE], m_chatmessage[CHAR_ID].toInt(), m_chatmessage[SHOWNAME], m_chatmessage[CHAR_NAME], m_chatmessage[OBJECTION_MOD], m_chatmessage[EVIDENCE_ID].toInt(), m_chatmessage[TEXT_COLOR].toInt(), DISPLAY_ONLY, sender); @@ -2501,7 +2499,7 @@ void Courtroom::display_character() ui_vp_message->hide(); ui_vp_chatbox->setVisible(chatbox_always_show); // Show it if chatbox always shows - if (ao_app->is_sticker_enabled() && chatbox_always_show) { + if (Options::getInstance().characterStickerEnabled() && chatbox_always_show) { ui_vp_sticker->load_image(m_chatmessage[CHAR_NAME]); } // Hide the face sticker @@ -2513,7 +2511,7 @@ void Courtroom::display_character() // Arrange the netstrings of the frame SFX for the character to know about if (!m_chatmessage[FRAME_SFX].isEmpty() && - ao_app->is_frame_network_enabled()) { + Options::getInstance().networkedFrameSfxEnabled()) { // ORDER IS IMPORTANT!! QStringList netstrings = {m_chatmessage[FRAME_SCREENSHAKE], m_chatmessage[FRAME_REALIZATION], @@ -2672,7 +2670,7 @@ void Courtroom::handle_ic_message() } // if we have instant objections disabled, and queue is not empty, check if next message after this is an objection. - if (!ao_app->is_instant_objection_enabled() && chatmessage_queue.size() > 0) + if (!Options::getInstance().objectionSkipQueueEnabled() && chatmessage_queue.size() > 0) { QStringList p_contents = chatmessage_queue.head(); int objection_mod = p_contents[OBJECTION_MOD].split("&")[0].toInt(); @@ -2685,7 +2683,7 @@ void Courtroom::handle_ic_message() void Courtroom::do_screenshake() { - if (!ao_app->is_shake_enabled()) + if (!Options::getInstance().shakeEnabled()) return; // This way, the animation is reset in such a way that last played screenshake @@ -2734,7 +2732,7 @@ void Courtroom::do_screenshake() void Courtroom::do_flash() { - if (!ao_app->is_effects_enabled()) + if (!Options::getInstance().effectsEnabled()) return; QString f_char = m_chatmessage[CHAR_NAME]; @@ -2758,7 +2756,7 @@ void Courtroom::do_effect(QString fx_path, QString fx_sound, QString p_char, } // Only check if effects are disabled after playing the sound if it exists - if (!ao_app->is_effects_enabled()) { + if (!Options::getInstance().effectsEnabled()) { return; } ui_vp_effect->transform_mode = ao_app->get_scaling( @@ -2855,7 +2853,7 @@ void Courtroom::initialize_chatbox() ui_vp_showname->setText(m_chatmessage[SHOWNAME]); } QString customchar; - if (ao_app->is_customchat_enabled()) + if (Options::getInstance().customChatboxEnabled()) customchar = m_chatmessage[CHAR_NAME]; QString p_misc = ao_app->get_chat(customchar); @@ -2966,8 +2964,8 @@ void Courtroom::handle_callwords() { // Quickly check through the message for the word_call (callwords) sfx QString f_message = m_chatmessage[MESSAGE]; - // Obtain the current call words (Really? It does File I/O on every single message???) - QStringList call_words = ao_app->get_call_words(); + //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)) { // If our message contains that specific call word @@ -3297,7 +3295,7 @@ void Courtroom::log_ic_text(QString p_name, QString p_showname, { chatlogpiece log_entry(p_name, p_showname, p_message, p_action, p_color, p_selfname); ic_chatlog_history.append(log_entry); - if (ao_app->get_text_logging_enabled() && !ao_app->log_filename.isEmpty()) + 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 && @@ -3616,7 +3614,7 @@ void Courtroom::start_chat_ticking() ui_vp_chatbox->setVisible(chatbox_always_show); ui_vp_message->hide(); // Show it if chatbox always shows - if (ao_app->is_sticker_enabled() && chatbox_always_show) + if (Options::getInstance().characterStickerEnabled() && chatbox_always_show) ui_vp_sticker->load_image(m_chatmessage[CHAR_NAME]); // Hide the face sticker else { @@ -3624,7 +3622,7 @@ void Courtroom::start_chat_ticking() } } // 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 = ao_app->stay_time(); + int delay = Options::getInstance().textStayTime(); if (delay > 0 && !text_queue_timer->isActive()) text_queue_timer->start(delay); return; @@ -3633,7 +3631,7 @@ void Courtroom::start_chat_ticking() ui_vp_chatbox->show(); ui_vp_message->show(); - if (ao_app->is_sticker_enabled()) + if (Options::getInstance().characterStickerEnabled()) ui_vp_sticker->load_image(m_chatmessage[CHAR_NAME]); if (m_chatmessage[ADDITIVE] != "1") { @@ -3644,9 +3642,9 @@ void Courtroom::start_chat_ticking() tick_pos = 0; blip_ticker = 0; - text_crawl = ao_app->get_text_crawl(); - blip_rate = ao_app->read_blip_rate(); - blank_blip = ao_app->get_blank_blip(); + text_crawl = Options::getInstance().textCrawlSpeed(); + blip_rate = Options::getInstance().blipRate(); + blank_blip = Options::getInstance().blankBlip(); // At the start of every new message, we set the text speed to the default. current_display_speed = 3; @@ -3707,7 +3705,7 @@ void Courtroom::chat_tick() anim_state = 3; QString f_char; QString f_custom_theme; - if (ao_app->is_customchat_enabled()) { + if (Options::getInstance().customChatboxEnabled()) { f_char = m_chatmessage[CHAR_NAME]; f_custom_theme = ao_app->get_chat(f_char); } @@ -3723,12 +3721,12 @@ void Courtroom::chat_tick() // 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 = ao_app->stay_time(); + 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 (!ao_app->is_instant_objection_enabled() && chatmessage_queue.size() > 0) + if (!Options::getInstance().objectionSkipQueueEnabled() && chatmessage_queue.size() > 0) { QStringList p_contents = chatmessage_queue.head(); int objection_mod = p_contents[OBJECTION_MOD].split("&")[0].toInt(); @@ -3944,7 +3942,7 @@ void Courtroom::play_sfx() return; sfx_player->play(sfx_name); - if (ao_app->get_looping_sfx()) + if (Options::getInstance().loopingSfx()) sfx_player->set_looping( ao_app->get_sfx_looping(current_char, current_emote) == "1"); } @@ -5013,7 +5011,7 @@ void Courtroom::on_music_list_double_clicked(QTreeWidgetItem *p_item, { if (is_muted) return; - if (!ao_app->is_category_stop_enabled() && p_item->parent() == nullptr) + 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); @@ -5388,7 +5386,7 @@ void Courtroom::on_text_color_context_menu_requested(const QPoint &pos) menu->addAction(QString("Open currently used chat_config.ini"), this, [=] { - QString p_path = ao_app->get_asset("chat_config.ini", ao_app->current_theme, ao_app->get_subtheme(), ao_app->default_theme, ao_app->get_chat(current_char)); + 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; } @@ -5578,8 +5576,6 @@ void Courtroom::on_change_character_clicked() void Courtroom::on_reload_theme_clicked() { - ao_app->reload_theme(); - set_courtroom_size(); set_widgets(); update_character(m_cid, ui_iniswap_dropdown->itemText(ui_iniswap_dropdown->currentIndex())); @@ -5758,14 +5754,14 @@ void Courtroom::on_casing_clicked() if (ui_casing->isChecked()) { QStringList f_packet; - f_packet.append(ao_app->get_casing_can_host_cases()); - f_packet.append(QString::number(ao_app->get_casing_cm_enabled())); - f_packet.append(QString::number(ao_app->get_casing_defence_enabled())); + f_packet.append(Options::getInstance().casingCanHostCases()); + f_packet.append(QString::number(Options::getInstance().casingCmEnabled())); + f_packet.append(QString::number(Options::getInstance().casingDefenceEnabled())); f_packet.append( - QString::number(ao_app->get_casing_prosecution_enabled())); - f_packet.append(QString::number(ao_app->get_casing_judge_enabled())); - f_packet.append(QString::number(ao_app->get_casing_juror_enabled())); - f_packet.append(QString::number(ao_app->get_casing_steno_enabled())); + QString::number(Options::getInstance().casingProsecutionEnabled())); + f_packet.append(QString::number(Options::getInstance().casingJudgeEnabled())); + f_packet.append(QString::number(Options::getInstance().casingJurorEnabled())); + f_packet.append(QString::number(Options::getInstance().casingStenoEnabled())); ao_app->send_server_packet(new AOPacket("SETCASE", f_packet)); } diff --git a/src/emotes.cpp b/src/emotes.cpp index 2a1d5066f..899ae4e94 100644 --- a/src/emotes.cpp +++ b/src/emotes.cpp @@ -1,6 +1,7 @@ #include "courtroom.h" #include "aoemotebutton.h" +#include "options.h" void Courtroom::initialize_emotes() { @@ -200,7 +201,7 @@ void Courtroom::select_emote(int p_id) if (old_emote == current_emote) { ui_pre->setChecked(!ui_pre->isChecked()); } - else if (!ao_app->is_stickypres_enabled()) { + else if (!Options::getInstance().clearPreOnPlayEnabled()) { if (emote_mod == PREANIM || emote_mod == PREANIM_ZOOM) { ui_pre->setChecked(true); } diff --git a/src/evidence.cpp b/src/evidence.cpp index 337e8303d..5face62d9 100644 --- a/src/evidence.cpp +++ b/src/evidence.cpp @@ -1,4 +1,5 @@ #include "courtroom.h" +#include "options.h" void Courtroom::initialize_evidence() { @@ -416,7 +417,7 @@ void Courtroom::on_evidence_image_button_clicked() return; QString filename = filenames.at(0); - QStringList bases = ao_app->get_mount_paths(); + QStringList bases = Options::getInstance().mountPaths(); bases.prepend(ao_app->get_base_path()); for (const QString &base : bases) { QDir baseDir(base); @@ -453,7 +454,7 @@ void Courtroom::on_evidence_clicked(int p_id) else if (f_real_id > local_evidence_list.size()) return; - if (!ao_app->get_evidence_double_click()){ + if (!Options::getInstance().evidenceDoubleClickEdit()){ on_evidence_double_clicked(p_id); return; } diff --git a/src/lobby.cpp b/src/lobby.cpp index c4eecb4bf..29f8ecd82 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -113,8 +113,6 @@ Lobby::Lobby(AOApplication *p_ao_app) : QMainWindow() // sets images, position and size void Lobby::set_widgets() { - ao_app->reload_theme(); - QString filename = "lobby_design.ini"; pos_size_type f_lobby = ao_app->get_element_dimensions("lobby", filename); diff --git a/src/main.cpp b/src/main.cpp index e8ffe67ec..9ec52f27c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -24,8 +24,6 @@ int main(int argc, char *argv[]) while (it.hasNext()) fontDatabase.addApplicationFont(it.next()); - QSettings *configini = main_app.configini; - QPluginLoader apngPlugin("qapng"); if (!apngPlugin.load()) qCritical() << "QApng plugin could not be loaded"; @@ -35,7 +33,7 @@ int main(int argc, char *argv[]) qCritical() << "QWebp plugin could not be loaded"; QString p_language = - configini->value("language", QLocale::system().name()).toString(); + Options::getInstance().language(); if (p_language == " " || p_language == "") p_language = QLocale::system().name(); diff --git a/src/networkmanager.cpp b/src/networkmanager.cpp index 6d01a30ea..12e118472 100644 --- a/src/networkmanager.cpp +++ b/src/networkmanager.cpp @@ -3,6 +3,7 @@ #include "datatypes.h" #include "debug_functions.h" #include "lobby.h" +#include "options.h" #include #include @@ -17,7 +18,7 @@ NetworkManager::NetworkManager(AOApplication *parent) : QObject(parent) heartbeat_timer = new QTimer(this); QString master_config = - ao_app->configini->value("master", "").value(); + Options::getInstance().alternativeMasterserver(); if (!master_config.isEmpty() && QUrl(master_config).scheme().startsWith("http")) { qInfo() << "using alternate master server" << master_config; ms_baseurl = master_config; @@ -81,7 +82,7 @@ void NetworkManager::send_heartbeat() // within a 5 minute window, so that the the number of people playing within // 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 (ao_app->get_player_count_optout()) + if (Options::getInstance().playerCountOptout()) return; QNetworkRequest req(QUrl(ms_baseurl + "/playing")); @@ -105,7 +106,7 @@ void NetworkManager::request_document(MSDocumentType document_type, req.setRawHeader("User-Agent", get_user_agent().toUtf8()); QString language = - ao_app->configini->value("language").toString(); + Options::getInstance().language(); if (language.trimmed().isEmpty()) language = QLocale::system().name(); diff --git a/src/options.cpp b/src/options.cpp new file mode 100644 index 000000000..7efaf9f6a --- /dev/null +++ b/src/options.cpp @@ -0,0 +1,620 @@ +#include "options.h" + +#include +#include +#include +#include +#include +#include + +void Options::migrateCallwords() +{ + // Bla bla, evil boilerplate. + QStringList l_callwords; + + QFile l_file; + l_file.setFileName(QCoreApplication::applicationDirPath() + + "/base/callwords.ini"); + + if (!l_file.open(QIODevice::ReadOnly)) { + qWarning() << "Unable to migrate callwords : File not open."; + } + + QTextStream in(&l_file); + in.setCodec("UTF-8"); + + while (!in.atEnd()) { + QString line = in.readLine(); + l_callwords.append(line); + } + l_file.close(); + l_file.remove(); + + setCallwords(l_callwords); +} + +Options::Options() + : config(QCoreApplication::applicationDirPath() + "/base/config.ini", + QSettings::IniFormat) +{ + config.setIniCodec("UTF-8"); + migrate(); +} + +/*! Migrate old configuration keys/values to a relevant format. */ +void Options::migrate() +{ + if (config.contains("show_custom_shownames")) { + config.remove("show_custom_shownames"); + } + if (QFile::exists(QCoreApplication::applicationDirPath() + + "/base/callwords.ini")) { + migrateCallwords(); + } + if (config.contains("ooc_name")) { + if (username().isEmpty()) { + config.setValue("default_username", config.value("ooc_name")); + } + config.remove("ooc_name"); + } +} + +QString Options::theme() const +{ + return config.value("theme", "default").toString(); +} + +void Options::setTheme(QString value) { config.setValue("theme", value); } + +int Options::blipRate() const { return config.value("blip_rate", 2).toInt(); } + +void Options::setBlipRate(int value) { config.setValue("blip_rate", value); } + +int Options::musicVolume() const +{ + return config.value("default_music", 50).toInt(); +} + +void Options::setMusicVolume(int value) +{ + config.setValue("default_music", value); +} + +int Options::sfxVolume() const +{ + return config.value("default_sfx", 50).toInt(); +} + +void Options::setSfxVolume(int value) { config.setValue("default_sfx", value); } + +int Options::blipVolume() const +{ + return config.value("default_blip", 50).toInt(); +} + +void Options::setBlipVolume(int value) +{ + config.setValue("default_blip", value); +} + +int Options::defaultSuppressAudio() const +{ + return config.value("suppress_audio", 50).toInt(); +} + +void Options::setDefaultSupressedAudio(int value) +{ + config.setValue("suppress_audio", value); +} + +int Options::maxLogSize() const +{ + return config.value("log_maximum", 200).toInt(); +} + +void Options::setMaxLogSize(int value) +{ + config.setValue("log_maximum", value); +} + +int Options::textStayTime() const +{ + return config.value("stay_time", 200).toInt(); +} + +void Options::setTextStayTime(int value) +{ + config.setValue("stay_time", value); +} + +int Options::textCrawlSpeed() const +{ + return config.value("text_crawl", 40).toInt(); +} + +void Options::setTextCrawlSpeed(int value) +{ + config.setValue("text_crawl", value); +} + +int Options::chatRateLimit() const +{ + return config.value("chat_ratelimit", 300).toInt(); +} + +void Options::setChatRateLimit(int value) +{ + config.setValue("chat_ratelimit", value); +} + +bool Options::logDirectionDownwards() const +{ + return config.value("log_goes_downwards", true).toBool(); +} + +void Options::setLogDirectionDownwards(bool value) +{ + config.setValue("log_goes_downwards", value); +} + +bool Options::logNewline() const +{ + return config.value("log_newline", false).toBool(); +} + +void Options::setLogNewline(bool value) +{ + config.setValue("log_newline", value); +} + +int Options::logMargin() const { return config.value("log_margin", 0).toInt(); } + +void Options::setLogMargin(int value) { config.setValue("log_margin", value); } + +bool Options::logTimestampEnabled() const +{ + return config.value("log_timestamp", false).toBool(); +} + +void Options::setLogTimestampEnabled(bool value) +{ + config.setValue("log_timestamp", value); +} + +QString Options::logTimestampFormat() const +{ + return config.value("log_timestamp_format", "h:mm:ss AP").toString(); +} + +void Options::setLogTimestampFormat(QString value) +{ + config.setValue("log_timestamp_format", value); +} + +bool Options::logIcActions() const +{ + return config.value("log_ic_actions", true).toBool(); +} + +void Options::setLogIcActions(bool value) +{ + config.setValue("log_ic_actions", value); +} + +bool Options::customShownameEnabled() const +{ + return config.value("show_custom_shownames", true).toBool(); +} + +void Options::setCustomShownameEnabled(bool value) +{ + config.setValue("show_custom_shownames", value); +} + +QString Options::username() const +{ + return config.value("default_username", "").value(); +} + +void Options::setUsername(QString value) +{ + config.setValue("default_username", value); +} + +QString Options::shownameOnJoin() const +{ + return config.value("default_showname", "").toString(); +} + +void Options::setShownameOnJoin(QString value) +{ + config.setValue("default_showname", value); +} + +QString Options::audioOutputDevice() const +{ + return config.value("default_audio_device", "default").toString(); +} + +void Options::setAudioOutputDevice(QString value) +{ + config.setValue("default_audio_device", value); +} + +bool Options::blankBlip() const +{ + return config.value("blank_blip", false).toBool(); +} + +void Options::setBlankBlip(bool value) { config.setValue("blank_blip", value); } + +bool Options::loopingSfx() const +{ + return config.value("looping_sfx", true).toBool(); +} + +void Options::setLoopingSfx(bool value) +{ + config.setValue("looping_sfx", value); +} + +bool Options::objectionStopMusic() const +{ + return config.value("objection_stop_music", false).toBool(); +} + +void Options::setObjectionStopMusic(bool value) +{ + config.setValue("objection_stop_music", value); +} + +bool Options::streamingEnabled() const +{ + return config.value("streaming_enabled", true).toBool(); +} + +void Options::setStreamingEnabled(bool value) +{ + config.setValue("streaming_enabled", value); +} + +bool Options::objectionSkipQueueEnabled() const +{ + return config.value("instant_objection", true).toBool(); +} + +void Options::setObjectionSkipQueueEnabled(bool value) +{ + config.setValue("instant_objection", value); +} + +bool Options::desynchronisedLogsEnabled() const +{ + return config.value("desync_logs", false).toBool(); +} + +void Options::setDesynchronisedLogsEnabled(bool value) +{ + config.setValue("desync_logs", value); +} + +bool Options::discordEnabled() const +{ + return config.value("discord", true).toBool(); +} + +void Options::setDiscordEnabled(bool value) +{ + config.setValue("discord", value); +} + +bool Options::shakeEnabled() const +{ + return config.value("shake", true).toBool(); +} + +void Options::setShakeEnabled(bool value) { config.setValue("shake", value); } + +bool Options::effectsEnabled() const +{ + return config.value("effects", true).toBool(); +} + +void Options::setEffectsEnabled(bool value) +{ + config.setValue("effects", value); +} + +bool Options::networkedFrameSfxEnabled() const +{ + return config.value("framenetwork", true).toBool(); +} + +void Options::setNetworkedFrameSfxEnabled(bool value) +{ + config.setValue("framenetwork", value); +} + +bool Options::colorLogEnabled() const +{ + return config.value("colorlog", true).toBool(); +} + +void Options::setColorLogEnabled(bool value) +{ + config.setValue("colorlog", value); +} + +bool Options::clearSoundsDropdownOnPlayEnabled() const +{ + return config.value("stickysounds", true).toBool(); +} + +void Options::setClearSoundsDropdownOnPlayEnabled(bool value) +{ + config.setValue("stickysounds", value); +} + +bool Options::clearEffectsDropdownOnPlayEnabled() const +{ + return config.value("stickyeffects", true).toBool(); +} + +void Options::setClearEffectsDropdownOnPlayEnabled(bool value) +{ + config.setValue("stickyeffects", value); +} + +bool Options::clearPreOnPlayEnabled() const +{ + return config.value("stickypres", true).toBool(); +} + +void Options::setClearPreOnPlayEnabled(bool value) +{ + config.setValue("stickypres", value); +} + +bool Options::customChatboxEnabled() const +{ + return config.value("customchat", true).toBool(); +} + +void Options::setCustomChatboxEnabled(bool value) +{ + config.setValue("customchat", value); +} + +bool Options::characterStickerEnabled() const +{ + return config.value("sticker", true).toBool(); +} + +void Options::setCharacterStickerEnabled(bool value) +{ + config.setValue("sticker", value); +} + +bool Options::continuousPlaybackEnabled() const +{ + return config.value("continuous_playback", true).toBool(); +} + +void Options::setContinuousPlaybackEnabled(bool value) +{ + config.setValue("continuous_playback", value); +} + +bool Options::stopMusicOnCategoryEnabled() const +{ + return config.value("category_stop", true).toBool(); +} + +void Options::setStopMusicOnCategoryEnabled(bool value) +{ + config.setValue("category_stop", value); +} + +bool Options::casingAlertEnabled() const +{ + return config.value("casing_enabled", false).toBool(); +} + +void Options::setCasingAlertEnabled(bool value) +{ + config.setValue("casing_enabled", value); +} + +bool Options::casingDefenceEnabled() const +{ + return config.value("casing_defence_enabled", false).toBool(); +} + +void Options::setcasingDefenceEnabled(bool value) +{ + config.setValue("casing_defence_enabled", value); +} + +bool Options::casingProsecutionEnabled() const +{ + return config.value("casing_prosecution_enabled", false).toBool(); +} + +void Options::setCasingProseuctionEnabled(bool value) +{ + config.setValue("casing_prosecution_enabled", value); +} + +bool Options::casingJudgeEnabled() const +{ + return config.value("casing_judge_enabled", false).toBool(); +} + +void Options::setCasingJudgeEnabled(bool value) +{ + config.setValue("casing_judge_enabled", value); +} + +bool Options::casingJurorEnabled() const +{ + return config.value("casing_juror_enabled", false).toBool(); +} + +void Options::setCasingJurorEnabled(bool value) +{ + config.setValue("casing_juror_enabled", value); +} + +bool Options::casingStenoEnabled() const +{ + return config.value("casing_steno_enabled", false).toBool(); +} + +void Options::setCasingStenoEnabled(bool value) +{ + config.setValue("casing_steno_enabled", value); +} + +bool Options::casingCmEnabled() const +{ + return config.value("casing_cm_enabled", false).toBool(); +} + +void Options::setCasingCmEnabled(bool value) +{ + config.setValue("casing_cm_enabled", value); +} + +QString Options::casingCanHostCases() const +{ + return config.value("casing_can_host_cases", "Turnabout Check Your Settings") + .toString(); +} + +void Options::setCasingCanHostCases(QString value) +{ + config.setValue("casing_can_host_cases", value); +} + +bool Options::logToTextFileEnabled() const +{ + return config.value("automatic_logging_enabled", true).toBool(); +} + +void Options::setLogToTextFileEnabled(bool value) +{ + config.setValue("automatic_logging_enabled", value); +} + +bool Options::logToDemoFileEnabled() const +{ + return config.value("demo_logging_enabled", true).toBool(); +} + +void Options::setLogToDemoFileEnabled(bool value) +{ + config.setValue("demo_logging_enabled", value); +} + +QString Options::subTheme() const +{ + return config.value("subtheme", "server").toString(); +} + +void Options::setSubTheme(QString value) { config.setValue("subtheme", value); } + +bool Options::animatedThemeEnabled() const +{ + return config.value("animated_theme", true).toBool(); +} + +void Options::setAnimatedThemeEnabled(bool value) +{ + config.setValue("animated_theme", value); +} + +QString Options::defaultScalingMode() const +{ + return config.value("default_scaling", "fast").toString(); +} + +void Options::setDefaultScalingMode(QString value) +{ + config.setValue("default_scaling", value); +} + +QStringList Options::mountPaths() const +{ + return config.value("mount_paths").value(); +} + +void Options::setMountPaths(QStringList value) +{ + config.setValue("mount_paths", value); +} + +bool Options::playerCountOptout() const +{ + return config.value("player_count_optout", false).toBool(); +} + +void Options::setPlayerCountOptout(bool value) +{ + config.setValue("player_count_optout", value); +} + +bool Options::playSelectedSFXOnIdle() const +{ + return config.value("sfx_on_idle", false).toBool(); +} + +void Options::setPlaySelectedSFXOnIdle(bool value) +{ + config.setValue("sfx_on_idle", value); +} + +bool Options::evidenceDoubleClickEdit() const +{ + return config.value("evidence_double_click", true).toBool(); +} + +void Options::setEvidenceDoubleClickEdit(bool value) +{ + config.setValue("evidence_double_click", value); +} + +QString Options::alternativeMasterserver() const +{ + return config.value("master", "").toString(); +} + +void Options::setAlternativeMasterserver(QString value) +{ + config.setValue("master", value); +} + +QString Options::language() const +{ + return config.value("language", QLocale::system().name()).toString(); +} + +void Options::setLanguage(QString value) { config.setValue("language", value); } + +QStringList Options::callwords() const +{ + 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; +} + +void Options::setCallwords(QStringList value) +{ + config.setValue("callwords", value); +} + +void Options::clearConfig() { config.clear(); } diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index 9c05b65f3..e075ec909 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -5,10 +5,11 @@ #include "hardware_functions.h" #include "lobby.h" #include "networkmanager.h" +#include "options.h" void AOApplication::append_to_demofile(QString packet_string) { - if (get_demo_logging_enabled() && !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()) @@ -214,7 +215,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet) // Remove any characters not accepted in folder names for the server_name // here - if (AOApplication::get_demo_logging_enabled() && server_name != "Demo playback") { + 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'"); @@ -228,7 +229,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet) QCryptographicHash hash(QCryptographicHash::Algorithm::Sha256); hash.addData(server_address.toUtf8()); - if (is_discord_enabled()) + if (Options::getInstance().discordEnabled()) discord->state_server(server_name.toStdString(), hash.result().toBase64().toStdString()); log_to_demo = false; @@ -603,7 +604,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet) subtheme = f_contents.at(0); // Check if we have subthemes set to "server" - QString p_st = configini->value("subtheme").value(); + QString p_st = Options::getInstance().subTheme(); if (p_st.toLower() != "server") // We don't. Simply acknowledge the subtheme sent by the server, but don't do anything else. return; diff --git a/src/path_functions.cpp b/src/path_functions.cpp index 2128ad93c..8cbe5afa4 100644 --- a/src/path_functions.cpp +++ b/src/path_functions.cpp @@ -1,6 +1,7 @@ #include "aoapplication.h" #include "courtroom.h" #include "file_functions.h" +#include "options.h" #include #include @@ -45,14 +46,13 @@ QString AOApplication::get_base_path() #else base_path = applicationDirPath() + "/base/"; #endif - return base_path; } VPath AOApplication::get_theme_path(QString p_file, QString p_theme) { if (p_theme == "") - p_theme = current_theme; + p_theme = Options::getInstance().theme(); return VPath("themes/" + p_theme + "/" + p_file); } @@ -280,9 +280,9 @@ QString AOApplication::get_sfx(QString p_sfx, QString p_misc, QString p_characte { QVector pathlist; // Sounds subfolder is prioritized for organization sake - pathlist += get_asset_paths("sounds/" + p_sfx, current_theme, get_subtheme(), default_theme, p_misc, p_character); + pathlist += get_asset_paths("sounds/" + p_sfx, Options::getInstance().theme(), Options::getInstance().subTheme(), default_theme, p_misc, p_character); // If sound subfolder not found, search just for SFX - pathlist += get_asset_paths(p_sfx, current_theme, get_subtheme(), default_theme, p_misc, p_character); + pathlist += get_asset_paths(p_sfx, Options::getInstance().theme(), Options::getInstance().subTheme(), default_theme, p_misc, p_character); // If SFX not found, search base/sounds/general/ folder pathlist += get_sounds_path(p_sfx); QString ret = get_sfx_path(pathlist); @@ -346,7 +346,7 @@ QString AOApplication::get_real_path(const VPath &vpath, } // Cache miss; try all known mount paths - QStringList bases = get_mount_paths(); + QStringList bases = Options::getInstance().mountPaths(); bases.prepend(get_base_path()); // base // content 1 diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index f3dc0cb97..543fa6173 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -1,147 +1,6 @@ #include "text_file_functions.h" #include "aoutils.h" - -QString AOApplication::read_theme() -{ - QString result = configini->value("theme", "default").value(); - return result; -} - -int AOApplication::read_blip_rate() -{ - int result = configini->value("blip_rate", 2).toInt(); - - if (result < 0) - return 0; - - return result; -} - -QString AOApplication::get_ooc_name() -{ - QString result = configini->value("ooc_name").value(); - return result; -} - -int AOApplication::get_default_music() -{ - int result = configini->value("default_music", 50).toInt(); - return result; -} - -int AOApplication::get_default_sfx() -{ - int result = configini->value("default_sfx", 50).toInt(); - return result; -} - -int AOApplication::get_default_blip() -{ - int result = configini->value("default_blip", 50).toInt(); - return result; -} - -int AOApplication::get_default_suppress_audio() -{ - int result = configini->value("suppress_audio", 50).toInt(); - return result; -} - -int AOApplication::get_max_log_size() -{ - int result = configini->value("log_maximum", 1000).toInt(); - return result; -} - -int AOApplication::stay_time() -{ - int result = configini->value("stay_time", 200).toInt(); - return result; -} - -int AOApplication::get_text_crawl() -{ - int result = configini->value("text_crawl", 40).toInt(); - return result; -} - -int AOApplication::get_chat_ratelimit() -{ - int result = configini->value("chat_ratelimit", 300).toInt(); - return result; -} - -bool AOApplication::get_log_goes_downwards() -{ - QString result = - configini->value("log_goes_downwards", "true").value(); - return result.startsWith("true"); -} - -bool AOApplication::get_log_newline() -{ - QString result = configini->value("log_newline", "false").value(); - return result.startsWith("true"); -} - -int AOApplication::get_log_margin() -{ - int result = configini->value("log_margin", 0).toInt(); - return result; -} - -bool AOApplication::get_log_timestamp() -{ - QString result = configini->value("log_timestamp", "false").value(); - return result.startsWith("true"); -} - -QString AOApplication::get_log_timestamp_format() -{ - QString result = configini->value("log_timestamp_format", "h:mm:ss AP").value(); - return result; -} - -bool AOApplication::get_log_ic_actions() -{ - QString result = - configini->value("log_ic_actions", "true").value(); - return result.startsWith("true"); -} - -bool AOApplication::get_showname_enabled_by_default() -{ - QString result = - configini->value("show_custom_shownames", "true").value(); - return result.startsWith("true"); -} - -QString AOApplication::get_default_username() -{ - QString result = configini->value("default_username", "").value(); - if (result.isEmpty()) - return get_ooc_name(); - else - return result; -} - -QString AOApplication::get_default_showname() -{ - QString result = configini->value("default_showname", "").value(); - return result; -} - -QString AOApplication::get_audio_output_device() -{ - QString result = - configini->value("default_audio_device", "default").value(); - return result; -} - -QStringList AOApplication::get_call_words() -{ - return get_list_file(get_base_path() + "callwords.ini"); -} +#include "options.h" QStringList AOApplication::get_list_file(VPath path) { @@ -202,9 +61,8 @@ bool AOApplication::write_to_file(QString p_text, QString p_file, bool make_dir) if (f_log.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) { QTextStream out(&f_log); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + out.setCodec("UTF-8"); -#endif out << p_text; f_log.flush(); @@ -233,9 +91,8 @@ bool AOApplication::append_to_file(QString p_text, QString p_file, QFile f_log(p_file); if (f_log.open(QIODevice::WriteOnly | QIODevice::Append)) { QTextStream out(&f_log); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + out.setCodec("UTF-8"); -#endif out << "\r\n" << p_text; f_log.flush(); @@ -264,9 +121,7 @@ QVector AOApplication::read_favorite_servers() } else { QSettings fav_servers_ini(fav_servers_ini_path, QSettings::IniFormat); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) fav_servers_ini.setIniCodec("UTF-8"); -#endif auto grouplist = fav_servers_ini.childGroups(); { // remove all negative and non-numbers @@ -312,9 +167,7 @@ QVector AOApplication::read_legacy_favorite_servers() qWarning() << "failed to open serverlist.txt"; } else { QTextStream stream(&serverlist_txt); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) stream.setCodec("UTF-8"); -#endif while (!stream.atEnd()) { @@ -352,9 +205,7 @@ 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) { return value.toStringList().join(","); @@ -368,7 +219,7 @@ QString AOApplication::read_design_ini(QString p_identifier, Qt::TransformationMode AOApplication::get_scaling(QString p_scaling) { if (p_scaling.isEmpty()) - p_scaling = get_default_scaling(); + p_scaling = Options::getInstance().defaultScalingMode(); if (p_scaling == "smooth") return Qt::SmoothTransformation; @@ -377,7 +228,7 @@ Qt::TransformationMode AOApplication::get_scaling(QString p_scaling) QPoint AOApplication::get_button_spacing(QString p_identifier, QString p_file) { - QString value = get_config_value(p_identifier, p_file, current_theme, get_subtheme(), default_theme); + QString value = get_config_value(p_identifier, p_file, Options::getInstance().theme(), Options::getInstance().subTheme(), default_theme); QPoint return_value; return_value.setX(0); @@ -423,7 +274,7 @@ pos_size_type AOApplication::get_element_dimensions(QString p_identifier, QString AOApplication::get_design_element(QString p_identifier, QString p_file, QString p_misc) { - QString value = get_config_value(p_identifier, p_file, current_theme, get_subtheme(), default_theme, 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 ""; @@ -432,7 +283,7 @@ QString AOApplication::get_design_element(QString p_identifier, QString p_file, // 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, current_theme, get_subtheme(), default_theme); + 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; @@ -440,7 +291,7 @@ int AOApplication::get_font_size(QString p_identifier, QString p_file) QColor AOApplication::get_color(QString p_identifier, QString p_file) { - QString value = get_config_value(p_identifier, p_file, current_theme, get_subtheme(), default_theme); + 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()) @@ -460,7 +311,7 @@ QColor AOApplication::get_color(QString p_identifier, QString p_file) QString AOApplication::get_stylesheet(QString p_file) { - QString path = get_asset(p_file, current_theme, get_subtheme(), default_theme); + 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)) @@ -480,7 +331,7 @@ QString AOApplication::get_stylesheet(QString p_file) QString AOApplication::get_tagged_stylesheet(QString target_tag, QString p_file) { - QString path = get_asset(p_file, current_theme, get_subtheme(), default_theme); + 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)) @@ -514,7 +365,7 @@ QString AOApplication::get_tagged_stylesheet(QString target_tag, QString p_file) QString AOApplication::get_chat_markup(QString p_identifier, QString p_chat) { // New Chadly method - QString value = get_config_value(p_identifier, "chat_config.ini", current_theme, get_subtheme(), default_theme, p_chat); + 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(); @@ -557,14 +408,14 @@ 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", current_theme, - get_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", current_theme, get_subtheme(), default_theme, 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 ""; @@ -616,9 +467,7 @@ QString AOApplication::read_char_ini(QString p_char, QString p_search_line, QSettings settings(get_real_path(get_character_path(p_char, "char.ini")), QSettings::IniFormat); settings.beginGroup(target_tag); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) settings.setIniCodec("UTF-8"); -#endif QString value = settings.value(p_search_line).value(); settings.endGroup(); return value; @@ -629,9 +478,7 @@ void AOApplication::set_char_ini(QString p_char, QString value, { 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(); @@ -642,9 +489,7 @@ QStringList AOApplication::read_ini_tags(VPath p_path, QString target_tag) { QStringList r_values; QSettings settings(get_real_path(p_path), QSettings::IniFormat); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) settings.setIniCodec("UTF-8"); -#endif if (!target_tag.isEmpty()) settings.beginGroup(target_tag); QStringList keys = settings.allKeys(); @@ -927,8 +772,8 @@ int AOApplication::get_text_delay(QString p_char, QString p_emote) QStringList AOApplication::get_effects(QString p_char) { const QStringList l_filepath_list{ - get_asset("effects/effects.ini", current_theme, get_subtheme(), default_theme, ""), - get_asset("effects.ini", current_theme, get_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; @@ -940,9 +785,7 @@ QStringList AOApplication::get_effects(QString p_char) } QSettings l_effects_ini(i_filepath, QSettings::IniFormat); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) l_effects_ini.setIniCodec("UTF-8"); -#endif // port legacy effects if (!l_effects_ini.contains("version/major") || l_effects_ini.value("version/major").toInt() < 2) @@ -998,8 +841,8 @@ QString AOApplication::get_effect(QString effect, QString p_char, p_folder = read_char_ini(p_char, "effects", "Options"); QStringList paths { - get_image("effects/" + effect, current_theme, get_subtheme(), default_theme, ""), - get_image(effect, current_theme, get_subtheme(), default_theme, p_folder) + 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) @@ -1014,17 +857,15 @@ QString AOApplication::get_effect_property(QString fx_name, QString p_char, if (p_folder == "") p_folder = read_char_ini(p_char, "effects", "Options"); - const auto paths = get_asset_paths("effects/effects.ini", current_theme, get_subtheme(), default_theme, ""); - const auto misc_paths = get_asset_paths("effects.ini", current_theme, get_subtheme(), default_theme, p_folder); + 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) { 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"); -#endif QStringList char_effects = settings.childGroups(); for (int i = 0; i < char_effects.size(); ++i) { QString effect = settings.value(char_effects[i] + "/name").toString(); @@ -1060,230 +901,3 @@ bool AOApplication::get_pos_is_judge(const QString &p_pos) } return positions.contains(p_pos.trimmed()); } - -bool AOApplication::get_blank_blip() -{ - QString result = configini->value("blank_blip", "false").value(); - return result.startsWith("true"); -} - -bool AOApplication::get_looping_sfx() -{ - QString result = configini->value("looping_sfx", "true").value(); - return result.startsWith("true"); -} - -bool AOApplication::objection_stop_music() -{ - QString result = - configini->value("objection_stop_music", "false").value(); - return result.startsWith("true"); -} - -bool AOApplication::is_streaming_disabled() -{ - return configini->value("streaming_disabled", false).toBool(); -} - -bool AOApplication::is_instant_objection_enabled() -{ - QString result = configini->value("instant_objection", "true").value(); - return result.startsWith("true"); -} - -bool AOApplication::is_desyncrhonized_logs_enabled() -{ - QString result = configini->value("desync_logs", "true").value(); - return result.startsWith("true"); -} - -bool AOApplication::is_discord_enabled() -{ - QString result = configini->value("discord", "true").value(); - return result.startsWith("true"); -} - -bool AOApplication::is_shake_enabled() -{ - QString result = configini->value("shake", "true").value(); - return result.startsWith("true"); -} - -bool AOApplication::is_effects_enabled() -{ - QString result = configini->value("effects", "true").value(); - return result.startsWith("true"); -} - -bool AOApplication::is_frame_network_enabled() -{ - QString result = configini->value("framenetwork", "true").value(); - return result.startsWith("true"); -} - -bool AOApplication::is_colorlog_enabled() -{ - QString result = configini->value("colorlog", "true").value(); - return result.startsWith("true"); -} - -bool AOApplication::is_stickysounds_enabled() -{ - QString result = configini->value("stickysounds", "false").value(); - return result.startsWith("true"); -} - -bool AOApplication::is_stickyeffects_enabled() -{ - QString result = configini->value("stickyeffects", "false").value(); - return result.startsWith("true"); -} - -bool AOApplication::is_stickypres_enabled() -{ - QString result = configini->value("stickypres", "false").value(); - return result.startsWith("true"); -} - -bool AOApplication::is_customchat_enabled() -{ - QString result = configini->value("customchat", "true").value(); - return result.startsWith("true"); -} - -bool AOApplication::is_sticker_enabled() -{ - QString result = configini->value("sticker", "true").value(); - return result.startsWith("true"); -} - -bool AOApplication::is_continuous_enabled() -{ - QString result = configini->value("continuous_playback", "false").value(); - return result.startsWith("true"); -} - -bool AOApplication::is_category_stop_enabled() -{ - QString result = configini->value("category_stop", "false").value(); - return result.startsWith("true"); -} - -bool AOApplication::get_casing_enabled() -{ - QString result = configini->value("casing_enabled", "false").value(); - return result.startsWith("true"); -} - -bool AOApplication::get_casing_defence_enabled() -{ - QString result = - configini->value("casing_defence_enabled", "false").value(); - return result.startsWith("true"); -} - -bool AOApplication::get_casing_prosecution_enabled() -{ - QString result = - configini->value("casing_prosecution_enabled", "false").value(); - return result.startsWith("true"); -} - -bool AOApplication::get_casing_judge_enabled() -{ - QString result = - configini->value("casing_judge_enabled", "false").value(); - return result.startsWith("true"); -} - -bool AOApplication::get_casing_juror_enabled() -{ - QString result = - configini->value("casing_juror_enabled", "false").value(); - return result.startsWith("true"); -} - -bool AOApplication::get_casing_steno_enabled() -{ - QString result = - configini->value("casing_steno_enabled", "false").value(); - return result.startsWith("true"); -} - -bool AOApplication::get_casing_cm_enabled() -{ - QString result = - configini->value("casing_cm_enabled", "false").value(); - return result.startsWith("true"); -} - -QString AOApplication::get_casing_can_host_cases() -{ - QString result = - configini->value("casing_can_host_cases", "Turnabout Check Your Settings") - .value(); - return result; -} - -bool AOApplication::get_text_logging_enabled() -{ - QString result = - configini->value("automatic_logging_enabled", "true").value(); - return result.startsWith("true"); -} - -bool AOApplication::get_demo_logging_enabled() -{ - QString result = - configini->value("demo_logging_enabled", "true").value(); - return result.startsWith("true"); -} - -QString AOApplication::get_subtheme() -{ - QString result = - configini->value("subtheme", "server").value(); - // Server means we want the server to decide for us - if (result == "server") - // 'subtheme' variable is affected by the server - result = subtheme; - // Default means we don't want any subthemes - else if (result == "default") - result = ""; - return result; -} - -bool AOApplication::get_animated_theme() -{ - QString result = - configini->value("animated_theme", "false").value(); - return result.startsWith("true"); -} - -QString AOApplication::get_default_scaling() -{ - return configini->value("default_scaling", "fast").value(); -} - -QStringList AOApplication::get_mount_paths() -{ - return configini->value("mount_paths").value(); -} - -bool AOApplication::get_player_count_optout() -{ - return configini->value("player_count_optout", "false").value() - .startsWith("true"); -} - -bool AOApplication::get_sfx_on_idle() -{ - return configini->value("sfx_on_idle", "true").value() - .startsWith("true"); -} - -bool AOApplication::get_evidence_double_click() -{ - return configini->value("evidence_double_click", "false").value() - .startsWith("true"); -} diff --git a/src/widgets/aooptionsdialog.cpp b/src/widgets/aooptionsdialog.cpp new file mode 100644 index 000000000..e9fbcaf39 --- /dev/null +++ b/src/widgets/aooptionsdialog.cpp @@ -0,0 +1,651 @@ +#include "widgets/aooptionsdialog.h" +#include "aoapplication.h" +#include "bass.h" +#include "file_functions.h" +#include "QDesktopServices" +#include "networkmanager.h" +#include "options.h" + +#include + +#define FROM_UI(type, name) \ + ; \ + ui_##name = findChild(#name); + +AOOptionsDialog::AOOptionsDialog(QDialog *parent, AOApplication *p_ao_app) + : QDialog(parent) +{ + ao_app = p_ao_app; + + QUiLoader l_loader(this); + QFile l_uiFile(":/resource/ui/options_dialog.ui"); + if (!l_uiFile.open(QFile::ReadOnly)) { + qWarning() << "Unable to open file " << l_uiFile.fileName(); + return; + } + + ui_settings_widget = l_loader.load(&l_uiFile, this); + + auto l_layout = new QVBoxLayout(this); + l_layout->addWidget(ui_settings_widget); + + // 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); + + // Gameplay Tab + FROM_UI(QComboBox, theme_combobox) + registerOption("theme_combobox", &Options::theme, + &Options::setTheme); + + FROM_UI(QComboBox, subtheme_combobox) + connect(ui_theme_combobox, + QOverload::of(&QComboBox::currentIndexChanged), this, + &AOOptionsDialog::themeChanged); + registerOption("subtheme_combobox", &Options::subTheme, + &Options::setSubTheme); + + FROM_UI(QPushButton, theme_reload_button) + connect(ui_theme_reload_button, &QPushButton::clicked, this, + &::AOOptionsDialog::onReloadThemeClicked); + + 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)) { + return; + } + QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); + }); + + 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("animated_theme_cb", + &Options::animatedThemeEnabled, + &Options::setAnimatedThemeEnabled); + registerOption("stay_time_spinbox", &Options::textStayTime, + &Options::setTextStayTime); + registerOption("instant_objection_cb", + &Options::objectionSkipQueueEnabled, + &Options::setObjectionSkipQueueEnabled); + registerOption("text_crawl_spinbox", &Options::textCrawlSpeed, + &Options::setTextCrawlSpeed); + registerOption("chat_ratelimit_spinbox", + &Options::chatRateLimit, + &Options::setChatRateLimit); + registerOption("username_textbox", &Options::username, + &Options::setUsername); + registerOption("showname_cb", + &Options::customShownameEnabled, + &Options::setCustomShownameEnabled); + registerOption("default_showname_textbox", + &Options::shownameOnJoin, + &Options::setShownameOnJoin); + registerOption("ms_textbox", + &Options::alternativeMasterserver, + &Options::setAlternativeMasterserver); + registerOption("discord_cb", &Options::discordEnabled, + &Options::setDiscordEnabled); + registerOption("language_combobox", &Options::language, + &Options::setLanguage); + registerOption("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("shake_cb", &Options::shakeEnabled, + &Options::setShakeEnabled); + registerOption("effects_cb", &Options::effectsEnabled, + &Options::setEffectsEnabled); + registerOption("framenetwork_cb", + &Options::networkedFrameSfxEnabled, + &Options::setNetworkedFrameSfxEnabled); + registerOption("colorlog_cb", &Options::colorLogEnabled, + &Options::setColorLogEnabled); + registerOption( + "stickysounds_cb", &Options::clearSoundsDropdownOnPlayEnabled, + &Options::setClearSoundsDropdownOnPlayEnabled); + registerOption( + "stickyeffects_cb", &Options::clearEffectsDropdownOnPlayEnabled, + &Options::setClearEffectsDropdownOnPlayEnabled); + registerOption("stickypres_cb", + &Options::clearPreOnPlayEnabled, + &Options::setClearPreOnPlayEnabled); + registerOption("customchat_cb", + &Options::customChatboxEnabled, + &Options::setCustomChatboxEnabled); + registerOption("sticker_cb", + &Options::characterStickerEnabled, + &Options::setCharacterStickerEnabled); + registerOption("continuous_cb", + &Options::continuousPlaybackEnabled, + &Options::setContinuousPlaybackEnabled); + registerOption("category_stop_cb", + &Options::stopMusicOnCategoryEnabled, + &Options::setStopMusicOnCategoryEnabled); + registerOption("sfx_on_idle_cb", + &Options::playSelectedSFXOnIdle, + &Options::setPlaySelectedSFXOnIdle); + registerOption("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( + "callwords_textbox", &Options::callwords, &Options::setCallwords); + + // Audio tab. + FROM_UI(QComboBox, audio_device_combobox) + populateAudioDevices(); + registerOption("audio_device_combobox", + &Options::audioOutputDevice, + &Options::setAudioOutputDevice); + + FROM_UI(QSpinBox, music_volume_spinbox) + FROM_UI(QSpinBox, sfx_volume_spinbox) + FROM_UI(QSpinBox, blips_volume_spinbox) + 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("music_volume_spinbox", &Options::musicVolume, + &Options::setMusicVolume); + registerOption("sfx_volume_spinbox", &Options::sfxVolume, + &Options::setSfxVolume); + registerOption("blips_volume_spinbox", &::Options::blipVolume, + &Options::setBlipVolume); + registerOption("suppress_audio_spinbox", + &::Options::defaultSuppressAudio, + &Options::setDefaultSupressedAudio); + registerOption("bliprate_spinbox", &::Options::blipRate, + &Options::setBlipRate); + registerOption("blank_blips_cb", &Options::blankBlip, + &Options::setBlankBlip); + registerOption("loopsfx_cb", &Options::loopingSfx, + &Options::setLoopingSfx); + registerOption("objectmusic_cb", + &Options::objectionStopMusic, + &Options::setObjectionStopMusic); + registerOption("disablestreams_cb", + &Options::streamingEnabled, + &Options::setStreamingEnabled); + + // Casing tab. + FROM_UI(QGroupBox, casing_enabled_box) + FROM_UI(QCheckBox, casing_def_cb) + FROM_UI(QCheckBox, casing_pro_cb) + FROM_UI(QCheckBox, casing_jud_cb) + FROM_UI(QCheckBox, casing_jur_cb) + FROM_UI(QCheckBox, casing_steno_cb) + FROM_UI(QCheckBox, casing_cm_cb) + FROM_UI(QLineEdit, casing_cm_cases_textbox) + + registerOption("casing_enabled_box", + &Options::casingAlertEnabled, + &Options::setCasingAlertEnabled); + registerOption("casing_def_cb", + &Options::casingDefenceEnabled, + &Options::setcasingDefenceEnabled); + registerOption("casing_pro_cb", + &Options::casingProsecutionEnabled, + &::Options::setCasingProseuctionEnabled); + registerOption("casing_jud_cb", &Options::casingJudgeEnabled, + &::Options::setCasingJudgeEnabled); + registerOption("casing_jur_cb", &Options::casingJurorEnabled, + &Options::setCasingJurorEnabled); + registerOption("casing_steno_cb", + &Options::casingStenoEnabled, + &Options::setCasingStenoEnabled); + registerOption("casing_cm_cb", &Options::casingCmEnabled, + &Options::setCasingCmEnabled); + registerOption("casing_cm_cases_textbox", + &Options::casingCanHostCases, + &Options::setCasingCanHostCases); + + // Asset tab + FROM_UI(QListWidget, mount_list) + auto *defaultMount = + new QListWidgetItem(tr("%1 (default)").arg(ao_app->get_base_path())); + defaultMount->setFlags(Qt::ItemFlag::NoItemFlags); + ui_mount_list->addItem(defaultMount); + registerOption("mount_list", &Options::mountPaths, + &Options::setMountPaths); + + 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()) { + return; + } + QDir dir(QApplication::applicationDirPath()); + QString relative = dir.relativeFilePath(path); + if (!relative.contains("../")) { + path = relative; + } + QListWidgetItem *dir_item = new QListWidgetItem(path); + ui_mount_list->addItem(dir_item); + ui_mount_list->setCurrentItem(dir_item); + + // quick hack to update buttons + emit ui_mount_list->itemSelectionChanged(); + }); + + FROM_UI(QPushButton, mount_remove) + connect(ui_mount_remove, &QPushButton::clicked, this, [this] { + auto selected = ui_mount_list->selectedItems(); + if (selected.isEmpty()) return; + delete selected[0]; + emit ui_mount_list->itemSelectionChanged(); + asset_cache_dirty = true; + }); + + FROM_UI(QPushButton, mount_up) + connect(ui_mount_up, &QPushButton::clicked, this, [this] { + auto selected = ui_mount_list->selectedItems(); + if (selected.isEmpty()) return; + auto *item = selected[0]; + int row = ui_mount_list->row(item); + ui_mount_list->takeItem(row); + int new_row = qMax(1, row - 1); + ui_mount_list->insertItem(new_row, item); + ui_mount_list->setCurrentRow(new_row); + asset_cache_dirty = true; + }); + + FROM_UI(QPushButton, mount_down) + connect(ui_mount_down, &QPushButton::clicked, this, [this] { + auto selected = ui_mount_list->selectedItems(); + if (selected.isEmpty()) return; + auto *item = selected[0]; + int row = ui_mount_list->row(item); + ui_mount_list->takeItem(row); + int new_row = qMin(ui_mount_list->count() + 1, row + 1); + ui_mount_list->insertItem(new_row, item); + ui_mount_list->setCurrentRow(new_row); + asset_cache_dirty = true; + }); + + 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); + }); + + connect(ui_mount_list, &QListWidget::itemSelectionChanged, this, [this] { + auto selected_items = ui_mount_list->selectedItems(); + bool row_selected = !ui_mount_list->selectedItems().isEmpty(); + ui_mount_remove->setEnabled(row_selected); + ui_mount_up->setEnabled(row_selected); + ui_mount_down->setEnabled(row_selected); + + if (!row_selected) return; + + int row = ui_mount_list->row(selected_items[0]); + if (row <= 1) ui_mount_up->setEnabled(false); + if (row >= ui_mount_list->count() - 1) ui_mount_down->setEnabled(false); + }); + + // 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("downwards_cb", + &Options::logDirectionDownwards, + &Options::setLogDirectionDownwards); + registerOption("length_spinbox", &Options::maxLogSize, + &Options::setMaxLogSize); + registerOption("log_newline_cb", &Options::logNewline, + &Options::setLogNewline); + registerOption("log_margin_spinbox", &Options::logMargin, + &Options::setLogMargin); + + FROM_UI(QCheckBox, log_timestamp_cb) + registerOption("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("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(); + + ui_log_timestamp_format_combobox->setCurrentText(l_current_format); + + 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) + + registerOption("log_ic_actions_cb", &Options::logIcActions, + &Options::setLogIcActions); + registerOption("desync_logs_cb", + &Options::desynchronisedLogsEnabled, + &Options::setDesynchronisedLogsEnabled); + registerOption("log_text_cb", &Options::logToTextFileEnabled, + &Options::setLogToTextFileEnabled); + registerOption("log_demo_cb", &Options::logToDemoFileEnabled, + &Options::setLogToDemoFileEnabled); + + // DSGVO/Privacy tab + + FROM_UI(QTextBrowser, privacy_policy) + ui_privacy_policy->setPlainText(tr("Getting privacy policy...")); + + updateValues(); +} + +void AOOptionsDialog::populateAudioDevices() +{ + ui_audio_device_combobox->clear(); + if (needsDefaultAudioDevice()) { + ui_audio_device_combobox->addItem("default"); + } + + BASS_DEVICEINFO info; + for (int a = 0; BASS_GetDeviceInfo(a, &info); a++) { + ui_audio_device_combobox->addItem(info.name); + } +} + +template <> +void AOOptionsDialog::setWidgetData(QCheckBox *widget, const bool &value) +{ + widget->setChecked(value); +} + +template <> bool AOOptionsDialog::widgetData(QCheckBox *widget) const +{ + return widget->isChecked(); +} + +template <> +void AOOptionsDialog::setWidgetData(QLineEdit *widget, const QString &value) +{ + widget->setText(value); +} + +template <> QString AOOptionsDialog::widgetData(QLineEdit *widget) const +{ + return widget->text(); +} + +template <> +void AOOptionsDialog::setWidgetData(QLineEdit *widget, const uint16_t &value) +{ + widget->setText(QString::number(value)); +} + +template <> uint16_t AOOptionsDialog::widgetData(QLineEdit *widget) const +{ + return widget->text().toUShort(); +} + +template <> +void AOOptionsDialog::setWidgetData(QPlainTextEdit *widget, + const QStringList &value) +{ + widget->setPlainText(value.join('\n')); +} + +template <> +QStringList AOOptionsDialog::widgetData(QPlainTextEdit *widget) const +{ + return widget->toPlainText().trimmed().split('\n'); +} + +template <> +void AOOptionsDialog::setWidgetData(QSpinBox *widget, const int &value) +{ + widget->setValue(value); +} + +template <> int AOOptionsDialog::widgetData(QSpinBox *widget) const +{ + return widget->value(); +} + +template <> +void AOOptionsDialog::setWidgetData(QComboBox *widget, const QString &value) +{ + for (auto i = 0; i < widget->count(); i++) { + if (widget->itemText(i) == value) { + widget->setCurrentIndex(i); + return; + } + } + qWarning() << "value" << value << "not found for widget" + << widget->objectName(); +} + +template <> QString AOOptionsDialog::widgetData(QComboBox *widget) const +{ + return widget->currentText(); +} + +template <> +void AOOptionsDialog::setWidgetData(QGroupBox *widget, const bool &value) +{ + widget->setChecked(value); +} + +template <> bool AOOptionsDialog::widgetData(QGroupBox *widget) const +{ + return widget->isChecked(); +} + +template <> +void AOOptionsDialog::setWidgetData(QListWidget *widget, + const QStringList &value) +{ + widget->addItems(value); +} + +template <> QStringList AOOptionsDialog::widgetData(QListWidget *widget) const +{ + QStringList paths; + for (auto i = 1; i < widget->count(); i++) { + paths.append(widget->item(i)->text()); + } + return paths; +} + +template +void AOOptionsDialog::registerOption(const QString &widgetName, + V (Options::*getter)() const, + void (Options::*setter)(V)) +{ + auto *widget = findChild(widgetName); + if (!widget) { + qWarning() << "could not find widget" << widgetName; + return; + } + + OptionEntry entry; + entry.load = [=] { + setWidgetData(widget, (Options::getInstance().*getter)()); + }; + entry.save = [=] { + (Options::getInstance().*setter)(widgetData(widget)); + }; + + optionEntries.append(entry); +} + +void AOOptionsDialog::updateValues() +{ + for (const OptionEntry &entry : qAsConst(optionEntries)) + entry.load(); + + QSet themes; + QStringList bases = Options::getInstance().mountPaths(); + bases.push_front(ao_app->get_base_path()); + for (const QString &base : bases) { + QDirIterator it(base + "/themes", QDir::Dirs | QDir::NoDotAndDotDot, + QDirIterator::NoIteratorFlags); + while (it.hasNext()) { + QString actualname = QDir(it.next()).dirName(); + if (!themes.contains(actualname)) { + ui_theme_combobox->addItem(actualname); + themes.insert(actualname); + } + } + } + int l_theme_index = + ui_theme_combobox->findText(Options::getInstance().theme()); + if (l_theme_index != -1) // Data found + ui_theme_combobox->setCurrentIndex(l_theme_index); + + QDirIterator it2(ao_app->get_real_path(ao_app->get_theme_path("")), + QDir::Dirs, QDirIterator::NoIteratorFlags); + while (it2.hasNext()) { + QString actualname = QDir(it2.next()).dirName(); + if (actualname != "." && actualname != ".." && + actualname.toLower() != "server" && actualname.toLower() != "default" && + actualname.toLower() != "effects" && actualname.toLower() != "misc") { + ui_subtheme_combobox->addItem(actualname); + } + } + int l_subTheme_index = + ui_subtheme_combobox->findText(Options::getInstance().subTheme()); + if (l_theme_index != -1) // Data found + ui_subtheme_combobox->setCurrentIndex(l_subTheme_index); + + 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); + }); +} + +void AOOptionsDialog::savePressed() +{ + for (const OptionEntry &entry : qAsConst(optionEntries)) + entry.save(); + this->close(); +} + +void AOOptionsDialog::discardPressed() { this->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) { + // Destructive operation. + Options::getInstance().clearConfig(); + updateValues(); + } + } +} + +void AOOptionsDialog::onReloadThemeClicked() +{ + Options::getInstance().setTheme(ui_theme_combobox->currentText()); + Options::getInstance().setSubTheme(ui_subtheme_combobox->currentText()); + Options::getInstance().setAnimatedThemeEnabled( + ui_animated_theme_cb->isChecked()); + emit reloadThemeRequest(); +} + +void AOOptionsDialog::themeChanged(int i) +{ + ui_subtheme_combobox->clear(); + // Fill the combobox with the names of the themes. + ui_subtheme_combobox->addItem("server"); + ui_subtheme_combobox->addItem("default"); + QDirIterator it(ao_app->get_real_path(ao_app->get_theme_path( + "", ui_theme_combobox->itemText(i))), + QDir::Dirs, QDirIterator::NoIteratorFlags); + while (it.hasNext()) { + QString actualname = QDir(it.next()).dirName(); + if (actualname != "." && actualname != ".." && + actualname.toLower() != "server" && actualname.toLower() != "default" && + actualname.toLower() != "effects" && actualname.toLower() != "misc") + ui_subtheme_combobox->addItem(actualname); + } +} + +void AOOptionsDialog::onTimestampFormatEdited() +{ + ui_log_timestamp_format_lbl->setText( + tr("Log timestamp format:\n") + + QDateTime::currentDateTime().toString( + ui_log_timestamp_format_combobox->currentText())); +} + +void AOOptionsDialog::timestampCbChanged(int state) +{ + ui_log_timestamp_format_combobox->setDisabled(state == 0); +} + +#if (defined(_WIN32) || defined(_WIN64)) +bool AOOptionsDialog::needsDefaultAudioDevice() { return true; } +#elif (defined(LINUX) || defined(__linux__)) +bool AOOptionsDialog::needsDefaultAudioDevice() { return false; } +#elif defined __APPLE__ +bool AOOptionsDialog::needsDefaultAudioDevice() { return true; } +#else +#error This operating system is not supported. +#endif From fbec20e3083aa4f23002e4bbecdb7b0b67120656 Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Fri, 4 Nov 2022 20:12:06 +0000 Subject: [PATCH 02/61] Cleanup lobby (#880) * Remove config loading from AOApplications Removes most, but not all config functions from AOApplication and moves them into their own class. Not even remotely done here. but holy shit I'm tired. * First steps towards UI file * Fixed your UI layout issue * Leifa bullies me * Set all the setters Reminder : Figure out why username and ooc_name exist. Are they the same? Maybe. Maybe not. Gonna have to look at it and migrate the key. Todo : Cleanup key naming. Most of these are terrible, imprecise or I just don't like them. * Make layout appear proper * Minor option dialog update * Hookup AOOptionsdialogue to Options Getter/setter Not done yet, but parts of the options interactions work again. * More settings menu working * Mostly working settings dialogue Restore default and cancel still need work * Fix asset widget * Tooltips Also removes the commented out tooltip code * Finish Tooltips Move widget implementation to its own folder * Migrate callwords to config.ini Also correct sleep deprived code. * Fix widget translation * Language dropdown changes We might want to look into doing this a bit better. * Remove QSettings from AOApplication Try cleaning up stray references to said object anymore * Fix constructor order to prevent runtime crash * Slightly sort implementation file * Remove unused label declarations from header Fix some comments * Formatting * Fix buttons Also fixes restore settings when a restore to default is aborted. * Raise pair list after courtroom construction (#859) * Don't reset evidence selection (#860) They are defaulted in the header. This SHOULD not affect the client negatively. * Hitting the emergency exit (#861) Don't change the widget state when the ID exceeds the current widget list due to pages being changed while evidence is being edited. * add CI and license badge * add contributors * Handle config.temp after confirmation * Deletes config.temp when the user has confirmed they want to keep the current settings. * Make reset to default destructive Don't worry, we ask first! :) * Fix case of self_offset received without a y offset (#864) caused by typos in #701 it's possible for older clients to send x offsets without a y offset. if you think this case is annoying you can remove it in the next version and handle it server-side instead * Change default settings (#839) * Make default config enable features for most cases except for Continuous Playback due to it introducing performance issues according to tooltip and confirmed in testing * Increase log size to 1000 * Default disable animated themes Co-authored-by: Salanto <62221668+Salanto@users.noreply.github.com> Co-authored-by: stonedDiscord * Make it a singleton? Maybe? I dunno? Ask Longbyte * Commit suggestions * More suggestions Also try fixing a memory leak. Not going to well. * Return to dialog Otherwise we don't have Exec. * Cleanup * Deprecate ooc_name, implement username * Remove ooc_name key and copy its value to default_showname if its empty. * Consistent naming in AOOptionsDialog * Clang format * Don't write the username to the showname * Fix theme dropdown being incorrectly set * Bandaid callword playing every message * Remove unused or duplicate includes * More include removals Removes lobby and courtroom direct includes from the dialog source * Burn baby, burn! * Remove reload_theme function * Remove "Case Alert Supported Message" All servers I tested on master supported it. The text is redundant in operation. * Create preliminary lobby design Attempts to slightly modernize the aging lobby to a scheme more akin to modern server browsers. * Fix missing header, add necessary search lineedits * More UI changes * Start hooking up new UI elements * Hookup Serverbrowser to new UI frontend Still need to fix the favorites AND implement the NEW demolist * Fixup demo ui and make demoserver functional * More demoserver cleanup * Remove jarring ao_app pointer shenigans Still a bit to do before we can safely remove that pointer, but hey, its something. * *unholy screeches* Tried to untangle the tange of dependencies that is connection behaviour * Rip out loading screen Some servers are not even sending proper values anymore, like vanilla, so why keep it? * Optimise includes, format header Lobby should not even have to know what an AOPacket is, smh * Formatting fixes and turn settings menu opening into a signal * Why does netmanager never emit when the server is connected * Fixup final parts About as well implemented as I can do rn. Missing the load screen, but that was more flair than anything else * Correct start page * demo qol Co-authored-by: TrickyLeifa Co-authored-by: stonedDiscord Co-authored-by: oldmud0 Co-authored-by: Crystalwarrior --- include/aoapplication.h | 13 + include/demoserver.h | 3 + include/lobby.h | 113 +++--- include/networkmanager.h | 4 + resource/ui/lobby.ui | 569 ++++++++++++++++++++++++++++ resources.qrc | 1 + src/aoapplication.cpp | 10 +- src/charselect.cpp | 13 - src/demoserver.cpp | 10 +- src/lobby.cpp | 717 +++++++++++++----------------------- src/networkmanager.cpp | 6 + src/packet_distribution.cpp | 45 +-- src/text_file_functions.cpp | 27 +- 13 files changed, 927 insertions(+), 604 deletions(-) create mode 100644 resource/ui/lobby.ui diff --git a/include/aoapplication.h b/include/aoapplication.h index 252693627..66399f0db 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -209,6 +209,19 @@ class AOApplication : public QApplication { */ QVector read_legacy_favorite_servers(); + /** + * @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 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); diff --git a/include/demoserver.h b/include/demoserver.h index bb0baed45..877d5ccfd 100644 --- a/include/demoserver.h +++ b/include/demoserver.h @@ -22,6 +22,8 @@ class DemoServer : public QObject int port = 27088; int max_wait = -1; + void set_demo_file(QString filepath); + private: void handle_packet(AOPacket *packet); void load_demo(QString filename); @@ -39,6 +41,7 @@ class DemoServer : public QObject QString p_path; QTimer *timer; int elapsed_time = 0; + QString filename; private slots: void accept_connection(); diff --git a/include/lobby.h b/include/lobby.h index d39d7f9b5..85693c249 100644 --- a/include/lobby.h +++ b/include/lobby.h @@ -1,22 +1,16 @@ #ifndef LOBBY_H #define LOBBY_H -#include "aobutton.h" -#include "aoimage.h" -#include "aopacket.h" -#include "aotextarea.h" - +#include #include #include -#include #include -#include -#include +#include #include #include -#include -#include -#include + +#include "networkmanager.h" + #ifdef ANDROID #include #endif @@ -27,89 +21,74 @@ class Lobby : public QMainWindow { Q_OBJECT public: - Lobby(AOApplication *p_ao_app); + Lobby(AOApplication *p_ao_app, NetworkManager *p_net_man = nullptr); + ~Lobby(); - void set_widgets(); - void list_servers(); - void list_favorites(); - void get_motd(); - void check_for_updates(); - void append_chatmessage(QString f_name, QString f_message); - void append_error(QString f_message); void set_player_count(int players_online, int max_players); - void set_server_description(const QString& server_description); - void set_stylesheet(QWidget *widget); - void set_stylesheets(); - void set_fonts(); - void set_font(QWidget *widget, QString p_identifier); - void set_loading_text(QString p_text); - void show_loading_overlay() { ui_loading_background->show(); } - void hide_loading_overlay() { ui_loading_background->hide(); } - QString get_chatlog(); + void set_server_description(const QString &server_description); + void list_servers(); int get_selected_server(); - void enable_connect_button(); - void reset_selection(); - - void set_loading_value(int p_value); - bool public_servers_selected = true; - bool doubleclicked = false; +signals: + void settings_requested(); - ~Lobby(); private: AOApplication *ao_app; + NetworkManager *net_manager; - AOImage *ui_background; + void list_favorites(); + void list_demos(); + void get_motd(); + void check_for_updates(); + void reset_selection(); - AOButton *ui_public_servers; - AOButton *ui_favorites; + int last_index = -1; - AOButton *ui_refresh; - AOButton *ui_add_to_fav; - AOButton *ui_remove_from_fav; - AOButton *ui_connect; + enum TabPage { SERVER, FAVORITES, DEMOS }; - QLabel *ui_version; - AOButton *ui_about; + // UI-file Lobby - AOButton *ui_settings; + // Top Row + QLabel *ui_game_version_lbl; + QPushButton *ui_settings_button; + QPushButton *ui_about_button; - QTreeWidget *ui_server_list; - QLineEdit *ui_server_search; + // Server, Favs and Demo lists + QTabWidget *ui_connections_tabview; - QLabel *ui_player_count; - AOTextArea *ui_description; + QTreeWidget *ui_serverlist_tree; + QLineEdit *ui_serverlist_search; - AOTextArea *ui_chatbox; + QTreeWidget *ui_favorites_tree; + QLineEdit *ui_favorites_search; - AOImage *ui_loading_background; - QTextEdit *ui_loading_text; - QProgressBar *ui_progress_bar; - AOButton *ui_cancel; + QTreeWidget *ui_demo_tree; + QLineEdit *ui_demo_search; - int last_index = -1; + QPushButton *ui_add_to_favorite_button; + QPushButton *ui_remove_from_favorites_button; + QPushButton *ui_refresh_button; - void set_size_and_pos(QWidget *p_widget, QString p_identifier); + // Serverinfo / MOTD Horizontal Row + QTextBrowser *ui_motd_text; -private slots: - void on_public_servers_clicked(); - void on_favorites_clicked(); + QLabel *ui_server_player_count_lbl; + QTextBrowser *ui_server_description_text; + QPushButton *ui_connect_button; - void on_refresh_pressed(); +private slots: + void on_tab_changed(int index); void on_refresh_released(); - void on_add_to_fav_pressed(); void on_add_to_fav_released(); - void on_remove_from_fav_pressed(); void on_remove_from_fav_released(); - void on_connect_pressed(); - void on_connect_released(); void on_about_clicked(); - void on_settings_clicked(); void on_server_list_clicked(QTreeWidgetItem *p_item, int column); - void on_server_list_doubleclicked(QTreeWidgetItem *p_item, int column); - void on_server_list_context_menu_requested(const QPoint &point); + void on_list_doubleclicked(QTreeWidgetItem *p_item, int column); + void on_favorite_list_context_menu_requested(const QPoint &point); + 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); }; #endif // LOBBY_H diff --git a/include/networkmanager.h b/include/networkmanager.h index 705fb9ea3..052bc9bff 100644 --- a/include/networkmanager.h +++ b/include/networkmanager.h @@ -51,9 +51,13 @@ class NetworkManager : public QObject { void connect_to_server(server_type p_server); void disconnect_from_server(); +signals: + void server_connected(bool state); + public slots: void get_server_list(const std::function &cb); void ship_server_packet(QString p_packet); + void join_to_server(); void handle_server_packet(const QString& p_data); void request_document(MSDocumentType document_type, diff --git a/resource/ui/lobby.ui b/resource/ui/lobby.ui new file mode 100644 index 000000000..29a561f19 --- /dev/null +++ b/resource/ui/lobby.ui @@ -0,0 +1,569 @@ + + + lobby_form + + + + 0 + 0 + 600 + 550 + + + + + 0 + 0 + + + + + 600 + 550 + + + + + + + QWidget#lobby { + background-color: gray; +} + + + + 0 + + + 4 + + + 2 + + + 4 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Version: 2.11.0 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Settings + + + + + + + About + + + + + + + + + + Game Lobby + + + + + + + + + + + 0 + 0 + + + + + + + + 3 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + false + + + + Qt::CustomContextMenu + + + Qt::LeftToRight + + + 0 + + + true + + + + Public Servers + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QTreeWidget { + background-color:black; + color:white; +} + + + Qt::ElideNone + + + true + + + + # + + + + + Name + + + + + + + + Search + + + + + + + + Favorites + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::CustomContextMenu + + + QTreeWidget { + background-color:black; + color:white; +} + + + Qt::ElideNone + + + true + + + + # + + + + + Name + + + + + + + + + Demos + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QTreeWidget { + background-color:black; + color:white; +} + + + Qt::ElideNone + + + 0 + + + true + + + + Server + + + + + Name + + + + + + + + + + + + + 2 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Refresh + + + + + + + Add To Favorites + + + + + + + Remove From Favorites + + + + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 5 + 20 + + + + + + + + + 2 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 5 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Server Info + + + Qt::AlignCenter + + + + + + + Offline + + + Qt::AlignCenter + + + + + + + QTextBrowser { + background-color:back; + color:white; +} + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">No description provided.</p></body></html> + + + + + + + false + + + Connect + + + + + + + + + + + 0 + 4 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Message of the Day + + + Qt::AlignCenter + + + + + + + QTextBrowser { + background-color:back; + color:white; +} + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + + + true + + + + + + + + + + + + + + + + + diff --git a/resources.qrc b/resources.qrc index 793a66bd8..5194097f7 100644 --- a/resources.qrc +++ b/resources.qrc @@ -10,5 +10,6 @@ resource/translations/ao_pt.qm resource/translations/ao_ru.qm resource/ui/options_dialog.ui + resource/ui/lobby.ui diff --git a/src/aoapplication.cpp b/src/aoapplication.cpp index a162596f1..c444b77ab 100644 --- a/src/aoapplication.cpp +++ b/src/aoapplication.cpp @@ -48,7 +48,7 @@ void AOApplication::construct_lobby() } load_favorite_list(); - w_lobby = new Lobby(this); + w_lobby = new Lobby(this, net_manager); lobby_constructed = true; QRect geometry = QGuiApplication::primaryScreen()->geometry(); @@ -63,6 +63,7 @@ void AOApplication::construct_lobby() demo_server->deleteLater(); demo_server = new DemoServer(this); + connect(w_lobby, &Lobby::settings_requested, this, &AOApplication::call_settings_menu); w_lobby->show(); } @@ -133,8 +134,7 @@ void AOApplication::save_favorite_list() #endif favorite_servers_ini.clear(); - // skip demo server entry, demo server entry is always at index 0 - for(int i = 1; i < favorite_list.size(); ++i) { + for(int i = 0; i < favorite_list.size(); ++i) { auto fav_server = favorite_list.at(i); favorite_servers_ini.beginGroup(QString::number(i)); favorite_servers_ini.setValue("name", fav_server.name); @@ -188,8 +188,6 @@ void AOApplication::server_disconnected() void AOApplication::loading_cancelled() { destruct_courtroom(); - - w_lobby->hide_loading_overlay(); } void AOApplication::call_settings_menu() @@ -201,8 +199,6 @@ void AOApplication::call_settings_menu() } if(lobby_constructed) { - connect(l_dialog, &AOOptionsDialog::reloadThemeRequest, - w_lobby, &Lobby::set_widgets); } l_dialog->exec(); delete l_dialog; diff --git a/src/charselect.cpp b/src/charselect.cpp index a9770048f..1a380febb 100644 --- a/src/charselect.cpp +++ b/src/charselect.cpp @@ -324,19 +324,6 @@ void Courtroom::character_loading_finished() // still running, it is just loading the pictures of the characters. if (ao_app->lobby_constructed) { ao_app->generated_chars++; - int total_loading_size = ao_app->char_list_size * 2 + - ao_app->evidence_list_size + - ao_app->music_list_size; - int loading_value = - int(((ao_app->loaded_chars + ao_app->generated_chars + - ao_app->loaded_music + ao_app->loaded_evidence) / - static_cast(total_loading_size)) * - 100); - ao_app->w_lobby->set_loading_value(loading_value); - ao_app->w_lobby->set_loading_text( - tr("Generating chars:\n%1/%2").arg( - QString::number(ao_app->generated_chars), - QString::number(ao_app->char_list_size))); } } ui_char_list->expandAll(); diff --git a/src/demoserver.cpp b/src/demoserver.cpp index bc7da1c10..16d2b46e6 100644 --- a/src/demoserver.cpp +++ b/src/demoserver.cpp @@ -12,6 +12,11 @@ DemoServer::DemoServer(QObject *parent) : QObject(parent) connect(timer, &QTimer::timeout, this, &DemoServer::playback); } +void DemoServer::set_demo_file(QString filepath) +{ + filename = filepath; +} + void DemoServer::start_server() { if (server_started) return; @@ -35,13 +40,12 @@ void DemoServer::destroy_connection() void DemoServer::accept_connection() { - QString path = QFileDialog::getOpenFileName(nullptr, tr("Load Demo"), "logs/", tr("Demo Files (*.demo)")); - if (path.isEmpty()) + if (filename.isEmpty()) { destroy_connection(); return; } - load_demo(path); + load_demo(filename); if (demo_data.isEmpty()) { diff --git a/src/lobby.cpp b/src/lobby.cpp index 29f8ecd82..5e3d032b6 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -1,420 +1,187 @@ #include "lobby.h" #include "aoapplication.h" -#include "aosfxplayer.h" -#include "debug_functions.h" #include "demoserver.h" #include "networkmanager.h" #include #include #include +#include -Lobby::Lobby(AOApplication *p_ao_app) : QMainWindow() +#define FROM_UI(type, name) \ + ; \ + ui_##name = findChild(#name); + +Lobby::Lobby(AOApplication *p_ao_app, NetworkManager *p_net_manager) + : QMainWindow() { ao_app = p_ao_app; + net_manager = p_net_manager; - 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) & ~Qt::WindowMaximizeButtonHint); - - ui_background = new AOImage(this, ao_app); - ui_background->setObjectName("ui_background"); - ui_public_servers = new AOButton(this, ao_app); - ui_public_servers->setObjectName("ui_public_servers"); - ui_favorites = new AOButton(this, ao_app); - ui_favorites->setObjectName("ui_favorites"); - ui_refresh = new AOButton(this, ao_app); - ui_refresh->setObjectName("ui_refresh"); - ui_add_to_fav = new AOButton(this, ao_app); - ui_add_to_fav->setObjectName("ui_add_to_fav"); - ui_remove_from_fav = new AOButton(this, ao_app); - ui_remove_from_fav->setObjectName("ui_remove_from_fav"); - ui_remove_from_fav->hide(); - ui_connect = new AOButton(this, ao_app); - ui_connect->setObjectName("ui_connect"); - ui_version = new QLabel(this); - ui_version->setObjectName("ui_version"); - ui_about = new AOButton(this, ao_app); - ui_about->setObjectName("ui_about"); - ui_settings = new AOButton(this, ao_app); - ui_settings->setObjectName("ui_settings"); - - ui_server_list = new QTreeWidget(this); - ui_server_list->setHeaderLabels({"#", "Name"}); - ui_server_list->setTextElideMode(Qt::ElideNone); - ui_server_list->header()->setMinimumSectionSize(24); - ui_server_list->header()->setSectionsMovable(false); - ui_server_list->setColumnWidth(0, 0); - ui_server_list->setIndentation(0); - ui_server_list->setObjectName("ui_server_list"); - ui_server_list->setContextMenuPolicy(Qt::CustomContextMenu); - - ui_server_search = new QLineEdit(this); - ui_server_search->setFrame(false); - ui_server_search->setPlaceholderText(tr("Search")); - ui_server_search->setObjectName("ui_server_search"); - - ui_player_count = new QLabel(this); - ui_player_count->setObjectName("ui_player_count"); - ui_description = new AOTextArea(this); - ui_description->setOpenExternalLinks(true); - ui_description->setObjectName("ui_description"); - ui_chatbox = new AOTextArea(this); - ui_chatbox->setOpenExternalLinks(true); - ui_chatbox->setObjectName("ui_chatbox"); - ui_loading_background = new AOImage(this, ao_app); - ui_loading_background->setObjectName("ui_loading_background"); - ui_loading_text = new QTextEdit(ui_loading_background); - ui_loading_text->setObjectName("ui_loading_text"); - ui_progress_bar = new QProgressBar(ui_loading_background); - ui_progress_bar->setMinimum(0); - ui_progress_bar->setMaximum(100); - ui_progress_bar->setObjectName("ui_progress_bar"); - ui_cancel = new AOButton(ui_loading_background, ao_app); - ui_cancel->setObjectName("ui_cancel"); - - connect(ui_public_servers, &AOButton::clicked, this, - &Lobby::on_public_servers_clicked); - connect(ui_favorites, &AOButton::clicked, this, &Lobby::on_favorites_clicked); - connect(ui_refresh, &AOButton::pressed, this, &Lobby::on_refresh_pressed); - connect(ui_refresh, &AOButton::released, this, &Lobby::on_refresh_released); - connect(ui_add_to_fav, &AOButton::pressed, this, - &Lobby::on_add_to_fav_pressed); - connect(ui_add_to_fav, &AOButton::released, this, - &Lobby::on_add_to_fav_released); - connect(ui_remove_from_fav, &AOButton::pressed, this, - &Lobby::on_remove_from_fav_pressed); - connect(ui_remove_from_fav, &AOButton::released, this, - &Lobby::on_remove_from_fav_released); - connect(ui_connect, &AOButton::pressed, this, &Lobby::on_connect_pressed); - connect(ui_connect, &AOButton::released, this, &Lobby::on_connect_released); - connect(ui_about, &AOButton::clicked, this, &Lobby::on_about_clicked); - connect(ui_settings, &AOButton::clicked, this, &Lobby::on_settings_clicked); - connect(ui_server_list, &QTreeWidget::itemClicked, this, - &Lobby::on_server_list_clicked); - connect(ui_server_list, &QTreeWidget::itemDoubleClicked, - this, &Lobby::on_server_list_doubleclicked); - connect(ui_server_list, &QTreeWidget::customContextMenuRequested, this, - &Lobby::on_server_list_context_menu_requested); - connect(ui_server_search, &QLineEdit::textChanged, this, - &Lobby::on_server_search_edited); - connect(ui_cancel, &AOButton::clicked, ao_app, &AOApplication::loading_cancelled); - - ui_connect->setEnabled(false); - - list_servers(); - get_motd(); - check_for_updates(); - - set_widgets(); -} - -// sets images, position and size -void Lobby::set_widgets() -{ - QString filename = "lobby_design.ini"; + this->setWindowFlags((this->windowFlags() | Qt::CustomizeWindowHint)); - pos_size_type f_lobby = ao_app->get_element_dimensions("lobby", filename); - - if (f_lobby.width < 0 || f_lobby.height < 0) { - qWarning() << "did not find lobby width or height in " << filename; - - #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 - - // Most common symptom of bad config files and missing assets. - call_notice( - tr("It doesn't look like your client is set up correctly.\n" - "Did you download all resources correctly from tiny.cc/getao, " - "including the large 'base' folder?")); - - this->setFixedSize(517, 666); - } - else { - this->setFixedSize(f_lobby.width, f_lobby.height); + QUiLoader l_loader(this); + QFile l_uiFile(":/resource/ui/lobby.ui"); + if (!l_uiFile.open(QFile::ReadOnly)) { + qCritical() << "Unable to open file " << l_uiFile.fileName(); + return; } - set_size_and_pos(ui_background, "lobby"); - ui_background->set_image("lobbybackground"); - - set_size_and_pos(ui_public_servers, "public_servers"); - ui_public_servers->set_image("publicservers_selected"); + l_loader.load(&l_uiFile, this); - set_size_and_pos(ui_favorites, "favorites"); - ui_favorites->set_image("favorites"); + FROM_UI(QLabel, game_version_lbl); + ui_game_version_lbl->setText( + tr("Version: %1").arg(ao_app->get_version_string())); - set_size_and_pos(ui_refresh, "refresh"); - ui_refresh->set_image("refresh"); + FROM_UI(QPushButton, settings_button); + connect(ui_settings_button, &QPushButton::clicked, this, + &Lobby::settings_requested); - set_size_and_pos(ui_add_to_fav, "add_to_fav"); - ui_add_to_fav->set_image("addtofav"); + FROM_UI(QPushButton, about_button); + connect(ui_about_button, &QPushButton::clicked, this, + &Lobby::on_about_clicked); - set_size_and_pos(ui_remove_from_fav, "remove_from_fav"); - ui_remove_from_fav->set_image("removefromfav"); + // Serverlist elements + FROM_UI(QTabWidget, connections_tabview); + ui_connections_tabview->tabBar()->setExpanding(true); + connect(ui_connections_tabview, &QTabWidget::currentChanged, this, + &Lobby::on_tab_changed); - set_size_and_pos(ui_connect, "connect"); - ui_connect->set_image("connect"); - - set_size_and_pos(ui_version, "version"); - ui_version->setText(tr("Version: %1").arg(ao_app->get_version_string())); - - set_size_and_pos(ui_about, "about"); - ui_about->set_image("about"); - - set_size_and_pos(ui_settings, "settings"); - ui_settings->setText(tr("Settings")); - ui_settings->set_image("lobby_settings"); - ui_settings->setToolTip( - tr("Allows you to change various aspects of the client.")); - - set_size_and_pos(ui_server_list, "server_list"); - - set_size_and_pos(ui_server_search, "server_search"); - - set_size_and_pos(ui_player_count, "player_count"); - ui_player_count->setText(tr("Offline")); - - set_size_and_pos(ui_description, "description"); - ui_description->setReadOnly(true); - - set_size_and_pos(ui_chatbox, "chatbox"); - ui_chatbox->setReadOnly(true); - - ui_loading_background->resize(this->width(), this->height()); - ui_loading_background->set_image("loadingbackground"); - - set_size_and_pos(ui_loading_text, "loading_label"); - ui_loading_text->setFont(QFont("Arial", 20, QFont::Bold)); - ui_loading_text->setReadOnly(true); - ui_loading_text->setAlignment(Qt::AlignCenter); - ui_loading_text->setFrameStyle(QFrame::NoFrame); - ui_loading_text->append(tr("Loading")); - - set_size_and_pos(ui_progress_bar, "progress_bar"); - set_size_and_pos(ui_cancel, "cancel"); - ui_cancel->setText(tr("Cancel")); - - ui_loading_background->hide(); - - set_fonts(); - set_stylesheets(); -} - -void Lobby::set_size_and_pos(QWidget *p_widget, QString p_identifier) -{ - QString filename = "lobby_design.ini"; + 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); - pos_size_type design_ini_result = - ao_app->get_element_dimensions(p_identifier, filename); + 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::customContextMenuRequested, this, + &Lobby::on_favorite_list_context_menu_requested); + + 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); + + FROM_UI(QPushButton, refresh_button); + connect(ui_refresh_button, &QPushButton::released, this, + &Lobby::on_refresh_released); + + FROM_UI(QPushButton, add_to_favorite_button) + connect(ui_add_to_favorite_button, &QPushButton::released, this, + &Lobby::on_add_to_fav_released); - if (design_ini_result.width < 0 || design_ini_result.height < 0) { - qWarning() << "could not find" << p_identifier << "in" << filename; - p_widget->hide(); - } - else { - p_widget->move(design_ini_result.x, design_ini_result.y); - p_widget->resize(design_ini_result.width, design_ini_result.height); - } -} + 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); -void Lobby::set_fonts() -{ - set_font(ui_version, "version"); - set_font(ui_player_count, "player_count"); - set_font(ui_description, "description"); - set_font(ui_chatbox, "chatbox"); - set_font(ui_loading_text, "loading_text"); - set_font(ui_server_list, "server_list"); -} + 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(net_manager, &NetworkManager::server_connected, + ui_connect_button, &QPushButton::setEnabled); -void Lobby::set_stylesheet(QWidget *widget) -{ - QString f_file = "lobby_stylesheets.css"; - QString style_sheet_string = ao_app->get_stylesheet(f_file); - if (style_sheet_string != "") - widget->setStyleSheet(style_sheet_string); -} + FROM_UI(QTextBrowser, motd_text); -void Lobby::set_stylesheets() -{ - set_stylesheet(this); - this->setStyleSheet( - "QFrame { background-color:transparent; } " - "QAbstractItemView { background-color: transparent; color: black; } " - "QLineEdit { background-color:transparent; }" - + this->styleSheet() - ); + list_servers(); + list_favorites(); + list_demos(); + get_motd(); + check_for_updates(); } -void Lobby::set_font(QWidget *widget, QString p_identifier) -{ - QString design_file = "lobby_fonts.ini"; - int f_weight = ao_app->get_font_size(p_identifier, design_file); - QString class_name = widget->metaObject()->className(); - QString font_name = - ao_app->get_design_element(p_identifier + "_font", design_file); - QFont font(font_name, f_weight); - bool use = ao_app->get_font_size("use_custom_fonts", design_file) == 1; - if (use) { - bool bold = ao_app->get_font_size(p_identifier + "_bold", design_file) == - 1; // is the font bold or not? - font.setBold(bold); - widget->setFont(font); - QColor f_color = ao_app->get_color(p_identifier + "_color", design_file); - bool center = - ao_app->get_font_size(p_identifier + "_center", design_file) == - 1; // should it be centered? - QString is_center = ""; - if (center) - is_center = "qproperty-alignment: AlignCenter;"; - QString style_sheet_string = - class_name + " { background-color: rgba(0, 0, 0, 0);\n" + - "color: rgba(" + QString::number(f_color.red()) + ", " + - QString::number(f_color.green()) + ", " + - QString::number(f_color.blue()) + ", 255);\n" + is_center + "}"; - widget->setStyleSheet(style_sheet_string); +void Lobby::on_tab_changed(int index) +{ + switch (index) { // Implicit conversion cause FUCK ALL OF YOU. + case SERVER: + ui_add_to_favorite_button->setVisible(true); + ui_remove_from_favorites_button->setVisible(false); + reset_selection(); + break; + case FAVORITES: + ui_add_to_favorite_button->setVisible(false); + ui_remove_from_favorites_button->setVisible(true); + reset_selection(); + break; + case DEMOS: + ui_add_to_favorite_button->setVisible(false); + ui_remove_from_favorites_button->setVisible(false); + reset_selection(); + break; + default: + break; } - return; -} - -void Lobby::set_loading_text(QString p_text) -{ - ui_loading_text->clear(); - ui_loading_text->setAlignment(Qt::AlignCenter); - ui_loading_text->append(p_text); -} - -QString Lobby::get_chatlog() -{ - QString return_value = ui_chatbox->toPlainText(); - - return return_value; } int Lobby::get_selected_server() { - if (auto item = ui_server_list->currentItem()) { - return item->text(0).toInt(); + switch (ui_connections_tabview->currentIndex()) { + case SERVER: + if (auto item = ui_serverlist_tree->currentItem()) { + return item->text(0).toInt(); + } + case FAVORITES: + if (auto item = ui_favorites_tree->currentItem()) { + return item->text(0).toInt(); + } + default: + break; } return -1; } -void Lobby::set_loading_value(int p_value) -{ - ui_progress_bar->setValue(p_value); -} - -void Lobby::on_public_servers_clicked() -{ - ui_public_servers->set_image("publicservers_selected"); - ui_favorites->set_image("favorites"); - ui_add_to_fav->show(); - ui_remove_from_fav->hide(); - - reset_selection(); - - public_servers_selected = true; - - list_servers(); -} - -void Lobby::on_favorites_clicked() -{ - ui_public_servers->set_image("publicservers"); - ui_favorites->set_image("favorites_selected"); - ui_add_to_fav->hide(); - ui_remove_from_fav->show(); - - reset_selection(); - - ao_app->load_favorite_list(); - - public_servers_selected = false; - - list_favorites(); -} - void Lobby::reset_selection() { last_index = -1; - ui_server_list->clearSelection(); - ui_player_count->setText(tr("Offline")); - ui_description->clear(); + ui_server_player_count_lbl->setText(tr("Offline")); + ui_server_description_text->clear(); - ui_connect->setEnabled(false); + ui_connect_button->setEnabled(false); } -void Lobby::on_refresh_pressed() { ui_refresh->set_image("refresh_pressed"); } - void Lobby::on_refresh_released() { - ui_refresh->set_image("refresh"); - - if (public_servers_selected) { - ao_app->net_manager->get_server_list(std::bind(&Lobby::list_servers, this)); - get_motd(); - } else { - ao_app->load_favorite_list(); - list_favorites(); - } -} - -void Lobby::on_add_to_fav_pressed() -{ - ui_add_to_fav->set_image("addtofav_pressed"); + net_manager->get_server_list(std::bind(&Lobby::list_servers, this)); + get_motd(); + ao_app->load_favorite_list(); + list_favorites(); } void Lobby::on_add_to_fav_released() { - ui_add_to_fav->set_image("addtofav"); - if (public_servers_selected) { - int selection = get_selected_server(); - if (selection > -1) { - ao_app->add_favorite_server(selection); - } + int selection = get_selected_server(); + if (selection > -1) { + ao_app->add_favorite_server(selection); + list_favorites(); } } -void Lobby::on_remove_from_fav_pressed() -{ - ui_remove_from_fav->set_image("removefromfav_pressed"); -} - void Lobby::on_remove_from_fav_released() { - ui_remove_from_fav->set_image("removefromfav"); - if (public_servers_selected) { - return; - } - int selection = get_selected_server(); - if (selection > 0) { + if (selection >= 0) { ao_app->remove_favorite_server(selection); list_favorites(); } } -void Lobby::on_connect_pressed() { ui_connect->set_image("connect_pressed"); } - -void Lobby::on_connect_released() -{ - ui_connect->set_image("connect"); - - AOPacket *f_packet; - - f_packet = new AOPacket("askchaa"); - - ao_app->send_server_packet(f_packet); -} - void Lobby::on_about_clicked() { const bool hasApng = QImageReader::supportedImageFormats().contains("apng"); - QString msg = tr("

Attorney Online %1

" "The courtroom drama simulator." @@ -432,11 +199,13 @@ void Lobby::on_about_clicked() "Robotic Overlord, Shadowlions (aka Shali), Sierra, SomeGuy, " "Veritas, Wiso" "

Translations:
" - "k-emiko (Русский), Pyraq (Polski), scatterflower (日本語), vintprox (Русский), " + "k-emiko (Русский), Pyraq (Polski), scatterflower (日本語), vintprox " + "(Русский), " "windrammer (Español, Português)" "

Special thanks:
" "Wiso, dyviacat (2.10 release); " - "CrazyJC (2.8 release director) and MaximumVolty (2.8 release promotion); " + "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); " @@ -450,100 +219,103 @@ void Lobby::on_about_clicked() "

Running on Qt version %2 with the BASS audio engine.
" "APNG plugin loaded: %3" "

Built on %4") - .arg(ao_app->get_version_string()) - .arg(QLatin1String(QT_VERSION_STR)) - .arg(hasApng ? tr("Yes") : tr("No")) - .arg(QLatin1String(__DATE__)); + .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); } -void Lobby::on_settings_clicked() { ao_app->call_settings_menu(); } - // clicked on an item in the serverlist void Lobby::on_server_list_clicked(QTreeWidgetItem *p_item, int column) { column = 0; - if (p_item->text(column).toInt() != last_index || !public_servers_selected) { - server_type f_server; - int n_server = p_item->text(column).toInt(); - last_index = n_server; + server_type f_server; + int n_server = p_item->text(column).toInt(); - if (n_server < 0) - return; + if (n_server == last_index) { + return; + } + last_index = n_server; - if (public_servers_selected) { - QVector f_server_list = ao_app->get_server_list(); + if (n_server < 0) return; - if (n_server >= f_server_list.size()) - return; + QVector f_server_list = ao_app->get_server_list(); - f_server = f_server_list.at(n_server); - } - else { - if (n_server >= ao_app->get_favorite_list().size()) - return; + if (n_server >= f_server_list.size()) return; - f_server = ao_app->get_favorite_list().at(n_server); - } - - set_server_description(f_server.desc); + f_server = f_server_list.at(n_server); - ui_description->moveCursor(QTextCursor::Start); - ui_description->ensureCursorVisible(); + set_server_description(f_server.desc); - ui_player_count->setText(tr("Offline")); + ui_server_description_text->moveCursor(QTextCursor::Start); + ui_server_description_text->ensureCursorVisible(); + ui_server_player_count_lbl->setText(tr("Connecting...")); - ui_connect->setEnabled(false); + ui_connect_button->setEnabled(false); - if (f_server.port == 99999 && f_server.ip == "127.0.0.1") { - // Demo playback server selected - 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; - ao_app->net_manager->connect_to_server(demo_server); - } - else ao_app->net_manager->connect_to_server(f_server); - } + net_manager->connect_to_server(f_server); } // doubleclicked on an item in the serverlist so we'll connect right away -void Lobby::on_server_list_doubleclicked(QTreeWidgetItem *p_item, int column) +void Lobby::on_list_doubleclicked(QTreeWidgetItem *p_item, int column) { - doubleclicked = true; - on_server_list_clicked(p_item, column); - //on_connect_released(); + Q_UNUSED(p_item) + Q_UNUSED(column) + net_manager->join_to_server(); } -void Lobby::on_server_list_context_menu_requested(const QPoint &point) +void Lobby::on_favorite_list_context_menu_requested(const QPoint &point) { - if (public_servers_selected) { - return; - } - - auto *item = ui_server_list->itemAt(point); + auto *item = ui_favorites_tree->itemAt(point); if (item == nullptr) { qInfo() << "no favorite server item; skipping context menu"; return; } const int server_index = item->data(0, Qt::DisplayRole).toInt(); - if (server_index == 0) { - qInfo() << "demo server has no context menu to display"; - return; - } auto *menu = new QMenu(this); - menu->addAction(tr("Remove"), ao_app, [this,server_index](){ + menu->addAction(tr("Remove"), ao_app, [this, server_index]() { ao_app->remove_favorite_server(server_index); list_favorites(); }); - menu->popup(ui_server_list->mapToGlobal(point)); + menu->popup(ui_favorites_tree->mapToGlobal(point)); } +void Lobby::on_favorite_tree_clicked(QTreeWidgetItem *p_item, int column) +{ + column = 0; + server_type f_server; + int n_server = p_item->text(column).toInt(); + + if (n_server == last_index) { + return; + } + last_index = n_server; + + if (n_server < 0) return; + + QVector f_server_list = ao_app->get_favorite_list(); + + if (n_server >= f_server_list.size()) return; + + f_server = f_server_list.at(n_server); + + set_server_description(f_server.desc); + + ui_server_description_text->moveCursor(QTextCursor::Start); + ui_server_description_text->ensureCursorVisible(); + ui_server_player_count_lbl->setText(tr("Connecting...")); + + ui_connect_button->setEnabled(false); + + net_manager->connect_to_server(f_server); + } + void Lobby::on_server_search_edited(QString p_text) { // Iterate through all QTreeWidgetItem items - QTreeWidgetItemIterator it(ui_server_list); + QTreeWidgetItemIterator it(ui_serverlist_tree); while (*it) { (*it)->setHidden(p_text != ""); ++it; @@ -551,8 +323,9 @@ void Lobby::on_server_search_edited(QString p_text) if (p_text != "") { // Search in metadata - QList clist = ui_server_list->findItems( - ui_server_search->text(), Qt::MatchContains | Qt::MatchRecursive, 1); + QList 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); @@ -561,98 +334,116 @@ void Lobby::on_server_search_edited(QString p_text) } } -void Lobby::list_servers() +void Lobby::on_demo_clicked(QTreeWidgetItem *item, int column) { - if (!public_servers_selected) { + Q_UNUSED(column) + + if (item == nullptr) { return; } - ui_favorites->set_image("favorites"); - ui_public_servers->set_image("publicservers_selected"); - ui_server_list->setSortingEnabled(false); - ui_server_list->clear(); + 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; + ao_app->demo_server->set_demo_file(l_filepath); + net_manager->connect_to_server(demo_server); +} + +void Lobby::list_servers() +{ + ui_serverlist_tree->setSortingEnabled(false); + ui_serverlist_tree->clear(); - ui_server_search->setText(""); + ui_serverlist_search->setText(""); int i = 0; for (const server_type &i_server : qAsConst(ao_app->get_server_list())) { - QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_server_list); + QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_serverlist_tree); treeItem->setData(0, Qt::DisplayRole, i); treeItem->setText(1, i_server.name); i++; } - ui_server_list->setSortingEnabled(true); - ui_server_list->sortItems(0, Qt::SortOrder::AscendingOrder); + ui_serverlist_tree->setSortingEnabled(true); + ui_serverlist_tree->sortItems(0, Qt::SortOrder::AscendingOrder); } void Lobby::list_favorites() { - if (public_servers_selected) { - return; - } - ui_server_list->setSortingEnabled(false); - ui_server_list->clear(); + ui_favorites_tree->setSortingEnabled(false); + ui_favorites_tree->clear(); int i = 0; for (const server_type &i_server : qAsConst(ao_app->get_favorite_list())) { - QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_server_list); + QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_favorites_tree); treeItem->setData(0, Qt::DisplayRole, i); treeItem->setText(1, i_server.name); - // treeItem->setText(2, "-"); i++; } - ui_server_list->setSortingEnabled(true); + ui_favorites_tree->setSortingEnabled(true); + ui_favorites_tree->sortItems(0, Qt::SortOrder::AscendingOrder); } -void Lobby::get_motd() +void Lobby::list_demos() { - ao_app->net_manager->request_document(MSDocumentType::Motd, - [this](QString document) { - if (document.isEmpty()) { - document = tr("Couldn't get the message of the day."); + ui_demo_tree->setSortingEnabled(false); + ui_demo_tree->clear(); + + QMultiMap 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)) { + QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_demo_tree); + treeItem->setData(0, Qt::DisplayRole, l_key); + treeItem->setData(1, Qt::DisplayRole, l_entry); } - ui_chatbox->setHtml(document); - }); + } + ui_demo_tree->setSortingEnabled(true); + ui_demo_tree->sortItems(0, Qt::SortOrder::AscendingOrder); } -void Lobby::check_for_updates() +void Lobby::get_motd() { - ao_app->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_version->setText(tr("Version: %1 (!)").arg(current_version)); - ui_version->setToolTip(tr("New version available: %1").arg(version)); + net_manager->request_document(MSDocumentType::Motd, [this](QString document) { + if (document.isEmpty()) { + document = tr("Couldn't get the message of the day."); } + ui_motd_text->setHtml(document); }); } -void Lobby::append_chatmessage(QString f_name, QString f_message) -{ - ui_chatbox->append_chatmessage( - f_name, f_message, - ao_app->get_color("ooc_default_color", "courtroom_design.ini").name()); -} - -void Lobby::append_error(QString f_message) +void Lobby::check_for_updates() { - ui_chatbox->append_error(f_message); + 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)); - ui_player_count->setText(f_string); + 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) +void Lobby::set_server_description(const QString &server_description) { - ui_description->clear(); - ui_description->append_linked(server_description); + ui_server_description_text->clear(); + QString result = server_description.toHtmlEscaped() + .replace("\n", "
") + .replace(QRegExp("\\b(https?://\\S+\\.\\S+)\\b"), + "\\1"); + ui_server_description_text->insertHtml(result); } -void Lobby::enable_connect_button() { ui_connect->setEnabled(true); } - Lobby::~Lobby() {} diff --git a/src/networkmanager.cpp b/src/networkmanager.cpp index 12e118472..96e262a5c 100644 --- a/src/networkmanager.cpp +++ b/src/networkmanager.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include NetworkManager::NetworkManager(AOApplication *parent) : QObject(parent) @@ -193,6 +194,11 @@ void NetworkManager::connect_to_server(server_type p_server) active_connection_type = p_server.socket_type; } +void NetworkManager::join_to_server() +{ + ship_server_packet(AOPacket("askchaa").to_string()); +} + void NetworkManager::disconnect_from_server() { if (!connected) diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index e075ec909..bc9c7eaae 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -72,8 +72,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet) client_id = f_contents.at(0).toInt(); server_software = f_contents.at(1); - if (lobby_constructed) - w_lobby->enable_connect_button(); + net_manager->server_connected(true); QStringList f_contents = {"AO2", get_version_string()}; send_server_packet(new AOPacket("ID", f_contents)); @@ -151,10 +150,6 @@ void AOApplication::server_packet_received(AOPacket *p_packet) w_lobby->set_server_description(f_contents.at(2)); } - if (w_lobby->doubleclicked) { - send_server_packet(new AOPacket("askchaa")); - w_lobby->doubleclicked = false; - } log_to_demo = false; } else if (header == "SI") { @@ -182,7 +177,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet) int selected_server = w_lobby->get_selected_server(); QString server_address = "", server_name = ""; - if (w_lobby->public_servers_selected) { + if (true) { if (selected_server >= 0 && selected_server < server_list.size()) { auto info = server_list.at(selected_server); server_name = info.name; @@ -204,10 +199,6 @@ void AOApplication::server_packet_received(AOPacket *p_packet) if (courtroom_constructed) w_courtroom->set_window_title(window_title); - w_lobby->show_loading_overlay(); - w_lobby->set_loading_text(tr("Loading")); - w_lobby->set_loading_value(0); - AOPacket *f_packet; f_packet = new AOPacket("RC"); @@ -265,21 +256,6 @@ void AOApplication::server_packet_received(AOPacket *p_packet) f_char.taken = false; w_courtroom->append_char(f_char); - - if (!courtroom_loaded) { - ++loaded_chars; - w_lobby->set_loading_text(tr("Loading chars:\n%1/%2") - .arg(QString::number(loaded_chars)) - .arg(QString::number(char_list_size))); - - int total_loading_size = - char_list_size * 2 + evidence_list_size + music_list_size; - int loading_value = int( - ((loaded_chars + generated_chars + loaded_music + loaded_evidence) / - static_cast(total_loading_size)) * - 100); - w_lobby->set_loading_value(loading_value); - } } if (!courtroom_loaded) @@ -296,11 +272,6 @@ void AOApplication::server_packet_received(AOPacket *p_packet) for (int n_element = 0; n_element < f_contents.size(); ++n_element) { ++loaded_music; - - w_lobby->set_loading_text(tr("Loading music:\n%1/%2") - .arg(QString::number(loaded_music)) - .arg(QString::number(music_list_size))); - if (musics_time) { w_courtroom->append_music(f_contents.at(n_element)); } @@ -320,14 +291,6 @@ void AOApplication::server_packet_received(AOPacket *p_packet) areas++; } } - - int total_loading_size = - char_list_size * 2 + evidence_list_size + music_list_size; - int loading_value = int( - ((loaded_chars + generated_chars + loaded_music + loaded_evidence) / - static_cast(total_loading_size)) * - 100); - w_lobby->set_loading_value(loading_value); } for (int area_n = 0; area_n < areas; area_n++) { @@ -371,10 +334,6 @@ void AOApplication::server_packet_received(AOPacket *p_packet) if (!courtroom_constructed) goto end; - if (lobby_constructed) - w_courtroom->append_server_chatmessage(tr("[Global log]"), - w_lobby->get_chatlog(), "0"); - w_courtroom->character_loading_finished(); w_courtroom->done_received(); diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 543fa6173..8d48d3f81 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -106,14 +106,6 @@ QVector AOApplication::read_favorite_servers() { QVector serverlist; - // demo server is always at the top - server_type demo_server; - demo_server.ip = "127.0.0.1"; - demo_server.port = 99999; - demo_server.name = tr("Demo playback"); - demo_server.desc = tr("Play back demos you have previously recorded"); - serverlist.append(demo_server); - QString fav_servers_ini_path(get_base_path() + "favorite_servers.ini"); if (!QFile::exists(fav_servers_ini_path)) { qWarning() << "failed to locate favorite_servers.ini, falling back to legacy serverlist.txt"; @@ -195,6 +187,25 @@ QVector AOApplication::read_legacy_favorite_servers() return serverlist; } +QMultiMap 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); + + QMultiMap 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); + } + } + return l_demo_logs; +} + QString AOApplication::read_design_ini(QString p_identifier, VPath p_design_path) { From a5c9657abee1b47d636ba1e27aa70ef517a2d169 Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Sun, 22 Jan 2023 03:47:20 +0100 Subject: [PATCH 03/61] Delete rebase artifact --- src/aooptionsdialog.cpp | 1449 --------------------------------------- 1 file changed, 1449 deletions(-) delete mode 100644 src/aooptionsdialog.cpp diff --git a/src/aooptionsdialog.cpp b/src/aooptionsdialog.cpp deleted file mode 100644 index f8a8cfe3c..000000000 --- a/src/aooptionsdialog.cpp +++ /dev/null @@ -1,1449 +0,0 @@ -#include "aooptionsdialog.h" -#include "aoapplication.h" -#include "courtroom.h" -#include "lobby.h" -#include "bass.h" -#include "networkmanager.h" - -#include - -AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app) - : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint) -{ - ao_app = p_ao_app; - - // Setting up the basics. - setWindowFlag(Qt::WindowCloseButtonHint); - setWindowTitle(tr("Settings")); - resize(450, 408); - - ui_settings_buttons = new QDialogButtonBox(this); - - QSizePolicy sizePolicy1(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); - sizePolicy1.setHorizontalStretch(0); - sizePolicy1.setVerticalStretch(0); - sizePolicy1.setHeightForWidth( - ui_settings_buttons->sizePolicy().hasHeightForWidth()); - ui_settings_buttons->setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Maximum)); - ui_settings_buttons->setOrientation(Qt::Horizontal); - ui_settings_buttons->setStandardButtons(QDialogButtonBox::Cancel | - QDialogButtonBox::Save | - QDialogButtonBox::RestoreDefaults); - - connect(ui_settings_buttons, &QDialogButtonBox::accepted, this, - &AOOptionsDialog::save_pressed); - connect(ui_settings_buttons, &QDialogButtonBox::rejected, this, - &AOOptionsDialog::discard_pressed); - connect(ui_settings_buttons, &QDialogButtonBox::clicked, this, - &AOOptionsDialog::button_clicked); - - // We'll stop updates so that the window won't flicker while it's being made. - setUpdatesEnabled(false); - - // First of all, we want a tabbed dialog, so let's add some layout. - ui_vertical_layout = new QVBoxLayout(this); - ui_settings_tabs = new QTabWidget(this); - - ui_vertical_layout->addWidget(ui_settings_tabs); - ui_vertical_layout->addWidget(ui_settings_buttons); - - // Let's add the tabs one by one. - // First, we'll start with 'Gameplay'. - ui_gameplay_tab = new QWidget(this); - ui_gameplay_tab->setSizePolicy(sizePolicy1); - ui_settings_tabs->addTab(ui_gameplay_tab, tr("Gameplay")); - ui_form_layout_widget = new QWidget(ui_gameplay_tab); - ui_form_layout_widget->setSizePolicy(sizePolicy1); - - ui_gameplay_form = new QFormLayout(ui_form_layout_widget); - ui_gameplay_form->setLabelAlignment(Qt::AlignLeading | Qt::AlignLeft | - Qt::AlignVCenter); - ui_gameplay_form->setFormAlignment(Qt::AlignLeading | Qt::AlignLeft | - Qt::AlignTop); - ui_gameplay_form->setContentsMargins(0, 0, 0, 0); - ui_gameplay_form->setSpacing(4); - - int row = 0; - - ui_theme_label = new QLabel(ui_form_layout_widget); - ui_theme_label->setText(tr("Theme:")); - ui_theme_label->setToolTip( - tr("Sets the theme used in-game. If the new theme changes " - "the lobby's look as well, you'll need to reload the " - "lobby for the changes to take effect, such as by joining " - "a server and leaving it.")); - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_theme_label); - ui_theme_combobox = new QComboBox(ui_form_layout_widget); - - // Fill the combobox with the names of the themes. - QSet themes; - QStringList bases = ao_app->get_mount_paths(); - bases.push_front(ao_app->get_base_path()); - for (const QString &base : bases) { - QDirIterator it(base + "/themes", QDir::Dirs | QDir::NoDotAndDotDot, - QDirIterator::NoIteratorFlags); - while (it.hasNext()) { - QString actualname = QDir(it.next()).dirName(); - if (!themes.contains(actualname)) { - ui_theme_combobox->addItem(actualname); - themes.insert(actualname); - } - } - } - - connect(ui_theme_combobox, QOverload::of(&QComboBox::currentIndexChanged), this, - &AOOptionsDialog::theme_changed); - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_theme_combobox); - - row += 1; - - ui_subtheme_label = new QLabel(ui_form_layout_widget); - ui_subtheme_label->setText(tr("Subtheme:")); - ui_subtheme_label->setToolTip( - tr("Sets a 'subtheme', which will stack on top of the current theme and replace anything it can." - "Keep it at 'server' to let the server decide. Keep it at 'default' to keep it unchanging.")); - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_subtheme_label); - ui_subtheme_combobox = new QComboBox(ui_form_layout_widget); - - // Fill the combobox with the names of the themes. - ui_subtheme_combobox->addItem("server"); - ui_subtheme_combobox->addItem("default"); - QDirIterator it2(ao_app->get_real_path(ao_app->get_theme_path("")), QDir::Dirs, - QDirIterator::NoIteratorFlags); - while (it2.hasNext()) { - QString actualname = QDir(it2.next()).dirName(); - if (actualname != "." && actualname != ".." && actualname.toLower() != "server" && actualname.toLower() != "default" && actualname.toLower() != "effects" && actualname.toLower() != "misc") { - ui_subtheme_combobox->addItem(actualname); - } - } - - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_subtheme_combobox); - - row += 1; - ui_theme_reload_button = new QPushButton(ui_form_layout_widget); - ui_theme_reload_button->setText(tr("Reload Theme")); - ui_theme_reload_button->setToolTip( - tr("Refresh the theme and update all of the ui elements to match.")); - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_theme_reload_button); - connect(ui_theme_reload_button, &QPushButton::clicked, this, - &AOOptionsDialog::on_reload_theme_clicked); - - row += 1; - ui_theme_folder_button = new QPushButton(ui_form_layout_widget); - ui_theme_folder_button->setText(tr("Open Theme Folder")); - ui_theme_folder_button->setToolTip( - tr("Open the theme folder of the currently selected theme.")); - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_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)) { - return; - } - QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); - } - ); - - row += 1; - ui_animated_theme_lbl = new QLabel(ui_form_layout_widget); - ui_animated_theme_lbl->setText(tr("Animated Theme:")); - ui_animated_theme_lbl->setToolTip( - tr("If ticked, themes will be allowed to have animated elements.")); - - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_animated_theme_lbl); - - ui_animated_theme_cb = new QCheckBox(ui_form_layout_widget); - - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_animated_theme_cb); - - row += 1; - ui_theme_log_divider = new QFrame(ui_form_layout_widget); - ui_theme_log_divider->setMidLineWidth(0); - ui_theme_log_divider->setFrameShape(QFrame::HLine); - ui_theme_log_divider->setFrameShadow(QFrame::Sunken); - - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, - ui_theme_log_divider); - - row += 1; - ui_stay_time_lbl = new QLabel(ui_form_layout_widget); - ui_stay_time_lbl->setText(tr("Text Stay Time:")); - ui_stay_time_lbl->setToolTip(tr( - "Minimum amount of time (in miliseconds) an IC message must stay on screen before " - "the next IC message is shown, acting as a 'queue'. Set to 0 to disable this behavior.")); - - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_stay_time_lbl); - - ui_stay_time_spinbox = new QSpinBox(ui_form_layout_widget); - ui_stay_time_spinbox->setSuffix(" ms"); - ui_stay_time_spinbox->setMaximum(10000); - - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_stay_time_spinbox); - - row += 1; - ui_instant_objection_lbl = new QLabel(ui_form_layout_widget); - ui_instant_objection_lbl->setText(tr("Instant Objection:")); - ui_instant_objection_lbl->setToolTip( - tr("If Text Stay Time is more than 0, instant objection will skip queued messages instead of waiting to catch up.")); - - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_instant_objection_lbl); - - ui_instant_objection_cb = new QCheckBox(ui_form_layout_widget); - - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_instant_objection_cb); - - row += 1; - ui_text_crawl_lbl = new QLabel(ui_form_layout_widget); - ui_text_crawl_lbl->setText(tr("Text crawl:")); - ui_text_crawl_lbl->setToolTip(tr( - "Amount of time (in miliseconds) spent on each letter when the in-character text is being displayed.")); - - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_text_crawl_lbl); - - ui_text_crawl_spinbox = new QSpinBox(ui_form_layout_widget); - ui_text_crawl_spinbox->setSuffix(" ms"); - ui_text_crawl_spinbox->setMaximum(500); - - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_text_crawl_spinbox); - - row += 1; - ui_chat_ratelimit_lbl = new QLabel(ui_form_layout_widget); - ui_chat_ratelimit_lbl->setText(tr("Chat Rate Limit:")); - ui_chat_ratelimit_lbl->setToolTip(tr( - "Minimum amount of time (in miliseconds) that must pass before the next Enter key press will send your IC message.")); - - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_chat_ratelimit_lbl); - - ui_chat_ratelimit_spinbox = new QSpinBox(ui_form_layout_widget); - ui_chat_ratelimit_spinbox->setSuffix(" ms"); - ui_chat_ratelimit_spinbox->setMaximum(5000); - - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_chat_ratelimit_spinbox); - - row += 1; - ui_log_names_divider = new QFrame(ui_form_layout_widget); - ui_log_names_divider->setFrameShape(QFrame::HLine); - ui_log_names_divider->setFrameShadow(QFrame::Sunken); - - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, - ui_log_names_divider); - - row += 1; - ui_username_lbl = new QLabel(ui_form_layout_widget); - ui_username_lbl->setText(tr("Default username:")); - ui_username_lbl->setToolTip( - tr("Your OOC name will be automatically set to this value " - "when you join a server.")); - - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_username_lbl); - - ui_username_textbox = new QLineEdit(ui_form_layout_widget); - ui_username_textbox->setMaxLength(30); - - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_username_textbox); - - row += 1; - ui_showname_lbl = new QLabel(ui_form_layout_widget); - ui_showname_lbl->setText(tr("Custom shownames:")); - ui_showname_lbl->setToolTip( - tr("Gives the default value for the in-game 'Custom shownames' " - "tickbox, which in turn determines whether the client should " - "display custom in-character names.")); - - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_showname_lbl); - - ui_showname_cb = new QCheckBox(ui_form_layout_widget); - - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_showname_cb); - - row +=1; - ui_default_showname_lbl = new QLabel(ui_form_layout_widget); - ui_default_showname_lbl->setText(tr("Default showname:")); - ui_default_showname_lbl->setToolTip( - tr("Your showname will be automatically set to this value " - "when you join a server.")); - - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_default_showname_lbl); - - ui_default_showname_textbox = new QLineEdit(ui_form_layout_widget); - ui_default_showname_textbox->setMaxLength(30); - - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_default_showname_textbox); - - row += 1; - ui_net_divider = new QFrame(ui_form_layout_widget); - ui_net_divider->setFrameShape(QFrame::HLine); - ui_net_divider->setFrameShadow(QFrame::Sunken); - - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_net_divider); - - row += 1; - ui_ms_lbl = new QLabel(ui_form_layout_widget); - ui_ms_lbl->setText(tr("Alternate Server List:")); - ui_ms_lbl->setToolTip( - tr("Overrides the base URL to retrieve server information from.")); - - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_ms_lbl); - - ui_ms_textbox = new QLineEdit(ui_form_layout_widget); - - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_ms_textbox); - - row += 1; - ui_discord_lbl = new QLabel(ui_form_layout_widget); - ui_discord_lbl->setText(tr("Discord:")); - ui_discord_lbl->setToolTip( - tr("Allows others on Discord to see what server you are in, " - "what character are you playing, and how long you have " - "been playing for.")); - - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_discord_lbl); - - ui_discord_cb = new QCheckBox(ui_form_layout_widget); - - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_discord_cb); - - row += 1; - ui_language_label = new QLabel(ui_form_layout_widget); - ui_language_label->setText(tr("Language:")); - ui_language_label->setToolTip( - tr("Sets the language if you don't want to use your system language.")); - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_language_label); - - ui_language_combobox = new QComboBox(ui_form_layout_widget); - ui_language_combobox->addItem( - ao_app->configini->value("language", " ").value() + - tr(" - Keep current setting")); - ui_language_combobox->addItem(" - Default"); - ui_language_combobox->addItem("en - English"); - ui_language_combobox->addItem("de - Deutsch"); - ui_language_combobox->addItem("es - Español"); - ui_language_combobox->addItem("pt - Português"); - ui_language_combobox->addItem("pl - Polskie"); - ui_language_combobox->addItem("jp - 日本語"); - ui_language_combobox->addItem("ru - Русский"); - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, - ui_language_combobox); - - row += 1; - ui_scaling_label = new QLabel(ui_form_layout_widget); - ui_scaling_label->setText(tr("Scaling:")); - ui_scaling_label->setToolTip( - tr("Sets the default scaling method, if there is not one already defined " - "specifically for the character.")); - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_scaling_label); - - ui_scaling_combobox = new QComboBox(ui_form_layout_widget); - // Corresponds with Qt::TransformationMode enum. Please don't change the order. - ui_scaling_combobox->addItem(tr("Pixel"), "fast"); - ui_scaling_combobox->addItem(tr("Smooth"), "smooth"); - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_scaling_combobox); - - row += 1; - ui_shake_lbl = new QLabel(ui_form_layout_widget); - ui_shake_lbl->setText(tr("Allow Screenshake:")); - ui_shake_lbl->setToolTip( - tr("Allows screenshaking. Disable this if you have concerns or issues " - "with photosensitivity and/or seizures.")); - - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_shake_lbl); - - ui_shake_cb = new QCheckBox(ui_form_layout_widget); - - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_shake_cb); - - row += 1; - ui_effects_lbl = new QLabel(ui_form_layout_widget); - ui_effects_lbl->setText(tr("Allow Effects:")); - ui_effects_lbl->setToolTip( - tr("Allows screen effects. Disable this if you have concerns or issues " - "with photosensitivity and/or seizures.")); - - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_effects_lbl); - - ui_effects_cb = new QCheckBox(ui_form_layout_widget); - - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_effects_cb); - - row += 1; - ui_framenetwork_lbl = new QLabel(ui_form_layout_widget); - ui_framenetwork_lbl->setText(tr("Network Frame Effects:")); - ui_framenetwork_lbl->setToolTip(tr( - "Send screen-shaking, flashes and sounds as defined in the char.ini over " - "the network. Only works for servers that support this functionality.")); - - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_framenetwork_lbl); - - ui_framenetwork_cb = new QCheckBox(ui_form_layout_widget); - - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_framenetwork_cb); - - row += 1; - ui_colorlog_lbl = new QLabel(ui_form_layout_widget); - ui_colorlog_lbl->setText(tr("Colors in IC Log:")); - ui_colorlog_lbl->setToolTip( - tr("Use the markup colors in the server IC chatlog.")); - - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_colorlog_lbl); - - ui_colorlog_cb = new QCheckBox(ui_form_layout_widget); - - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_colorlog_cb); - - row += 1; - ui_stickysounds_lbl = new QLabel(ui_form_layout_widget); - ui_stickysounds_lbl->setText(tr("Sticky Sounds:")); - ui_stickysounds_lbl->setToolTip( - tr("Turn this on to prevent the sound dropdown from clearing the sound " - "after playing it.")); - - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_stickysounds_lbl); - - ui_stickysounds_cb = new QCheckBox(ui_form_layout_widget); - - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_stickysounds_cb); - - row += 1; - ui_stickyeffects_lbl = new QLabel(ui_form_layout_widget); - ui_stickyeffects_lbl->setText(tr("Sticky Effects:")); - ui_stickyeffects_lbl->setToolTip( - tr("Turn this on to prevent the effects dropdown from clearing the " - "effect after playing it.")); - - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, - ui_stickyeffects_lbl); - - ui_stickyeffects_cb = new QCheckBox(ui_form_layout_widget); - - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_stickyeffects_cb); - - row += 1; - ui_stickypres_lbl = new QLabel(ui_form_layout_widget); - ui_stickypres_lbl->setText(tr("Sticky Preanims:")); - ui_stickypres_lbl->setToolTip( - tr("Turn this on to prevent preanimation checkbox from clearing after " - "playing the emote.")); - - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_stickypres_lbl); - - ui_stickypres_cb = new QCheckBox(ui_form_layout_widget); - - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_stickypres_cb); - - row += 1; - ui_customchat_lbl = new QLabel(ui_form_layout_widget); - ui_customchat_lbl->setText(tr("Custom Chatboxes:")); - ui_customchat_lbl->setToolTip( - tr("Turn this on to allow characters to define their own " - "custom chat box designs.")); - - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_customchat_lbl); - - ui_customchat_cb = new QCheckBox(ui_form_layout_widget); - - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_customchat_cb); - - row += 1; - ui_sticker_lbl = new QLabel(ui_form_layout_widget); - ui_sticker_lbl->setText(tr("Stickers:")); - ui_sticker_lbl->setToolTip( - tr("Turn this on to allow characters to define their own " - "stickers (unique images that show up over the chatbox - like avatars or shownames).")); - - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_sticker_lbl); - - ui_sticker_cb = new QCheckBox(ui_form_layout_widget); - - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_sticker_cb); - - row += 1; - ui_continuous_lbl = new QLabel(ui_form_layout_widget); - ui_continuous_lbl->setText(tr("Continuous Playback:")); - ui_continuous_lbl->setToolTip( - tr("Whether or not to resume playing animations from where they left off. Turning off might reduce lag.")); - - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_continuous_lbl); - - ui_continuous_cb = new QCheckBox(ui_form_layout_widget); - - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_continuous_cb); - - row += 1; - ui_category_stop_lbl = new QLabel(ui_form_layout_widget); - ui_category_stop_lbl->setText(tr("Stop Music w/ Category:")); - ui_category_stop_lbl->setToolTip( - tr("Stop music when double-clicking a category. If this is disabled, use the right-click context menu to stop music.")); - - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_category_stop_lbl); - - ui_category_stop_cb = new QCheckBox(ui_form_layout_widget); - - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_category_stop_cb); - - row += 1; - - ui_sfx_on_idle_lbl = new QLabel(ui_form_layout_widget); - ui_sfx_on_idle_lbl->setText(tr("Always Send SFX:")); - ui_sfx_on_idle_lbl->setToolTip( - tr("If the SFX dropdown has an SFX selected, send the custom SFX alongside the message even if Preanim is OFF.")); - - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_sfx_on_idle_lbl); - - ui_sfx_on_idle_cb = new QCheckBox(ui_form_layout_widget); - - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_sfx_on_idle_cb); - - row += 1; - - ui_evidence_double_click_lbl = new QLabel(ui_form_layout_widget); - ui_evidence_double_click_lbl->setText(tr("Evidence Double Click:")); - ui_evidence_double_click_lbl->setToolTip( - tr("If ticked, Evidence needs a double-click to view rather than a single click.")); - - ui_gameplay_form->setWidget(row, QFormLayout::LabelRole, ui_evidence_double_click_lbl); - - ui_evidence_double_click_cb = new QCheckBox(ui_form_layout_widget); - - ui_gameplay_form->setWidget(row, QFormLayout::FieldRole, ui_evidence_double_click_cb); - - // Finish gameplay tab - QScrollArea *scroll = new QScrollArea(this); - scroll->setWidget(ui_form_layout_widget); - ui_gameplay_tab->setLayout(new QVBoxLayout); - ui_gameplay_tab->layout()->addWidget(scroll); - ui_gameplay_tab->show(); - - // Here we start the callwords tab. - ui_callwords_tab = new QWidget(this); - ui_settings_tabs->addTab(ui_callwords_tab, tr("Callwords")); - - ui_callwords_widget = new QWidget(ui_callwords_tab); - ui_callwords_widget->setGeometry(QRect(10, 10, 361, 211)); - - ui_callwords_layout = new QVBoxLayout(ui_callwords_widget); - ui_callwords_layout->setContentsMargins(0, 0, 0, 0); - - ui_callwords_textbox = new QPlainTextEdit(ui_callwords_widget); - QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - sizePolicy.setHorizontalStretch(0); - sizePolicy.setVerticalStretch(0); - sizePolicy.setHeightForWidth( - ui_callwords_textbox->sizePolicy().hasHeightForWidth()); - ui_callwords_textbox->setSizePolicy(sizePolicy); - - ui_callwords_layout->addWidget(ui_callwords_textbox); - - ui_callwords_explain_lbl = new QLabel(ui_callwords_widget); - ui_callwords_explain_lbl->setWordWrap(true); - ui_callwords_explain_lbl->setText( - tr("Enter as many callwords as you would like. These " - "are case insensitive. Make sure to leave every callword in its own " - "line!
Do not leave a line with a space at the end -- you will be " - "alerted everytime someone uses a space in their " - "messages.")); - - ui_callwords_layout->addWidget(ui_callwords_explain_lbl); - - // The audio tab. - ui_audio_tab = new QWidget(this); - ui_settings_tabs->addTab(ui_audio_tab, tr("Audio")); - - ui_audio_widget = new QWidget(ui_audio_tab); - ui_audio_widget->setGeometry(QRect(10, 10, 361, 211)); - - ui_audio_layout = new QFormLayout(ui_audio_widget); - ui_audio_layout->setLabelAlignment(Qt::AlignLeading | Qt::AlignLeft | - Qt::AlignVCenter); - ui_audio_layout->setFormAlignment(Qt::AlignLeading | Qt::AlignLeft | - Qt::AlignTop); - ui_audio_layout->setContentsMargins(0, 0, 0, 0); - row = 0; - - ui_audio_device_lbl = new QLabel(ui_audio_widget); - ui_audio_device_lbl->setText(tr("Audio device:")); - ui_audio_device_lbl->setToolTip(tr("Sets the audio device for all sounds.")); - - ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_audio_device_lbl); - - ui_audio_device_combobox = new QComboBox(ui_audio_widget); - - // Let's fill out the combobox with the available audio devices. Or don't if - // there is no audio - int a = 0; - if (needs_default_audiodev()) { - - ui_audio_device_combobox->addItem("default"); //TODO translate this without breaking the default audio device - } - BASS_DEVICEINFO info; - for (a = 0; BASS_GetDeviceInfo(a, &info); a++) { - ui_audio_device_combobox->addItem(info.name); - if (ao_app->get_audio_output_device() == info.name) - ui_audio_device_combobox->setCurrentIndex( - ui_audio_device_combobox->count() - 1); - } - ui_audio_layout->setWidget(row, QFormLayout::FieldRole, - ui_audio_device_combobox); - - row += 1; - ui_audio_volume_divider = new QFrame(ui_audio_widget); - ui_audio_volume_divider->setFrameShape(QFrame::HLine); - ui_audio_volume_divider->setFrameShadow(QFrame::Sunken); - - ui_audio_layout->setWidget(row, QFormLayout::FieldRole, - ui_audio_volume_divider); - - row += 1; - ui_music_volume_lbl = new QLabel(ui_audio_widget); - ui_music_volume_lbl->setText(tr("Music:")); - ui_music_volume_lbl->setToolTip(tr("Sets the music's default volume.")); - - ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_music_volume_lbl); - - ui_music_volume_spinbox = new QSpinBox(ui_audio_widget); - ui_music_volume_spinbox->setMaximum(100); - ui_music_volume_spinbox->setSuffix("%"); - - ui_audio_layout->setWidget(row, QFormLayout::FieldRole, - ui_music_volume_spinbox); - - row += 1; - ui_sfx_volume_lbl = new QLabel(ui_audio_widget); - ui_sfx_volume_lbl->setText(tr("SFX:")); - ui_sfx_volume_lbl->setToolTip( - tr("Sets the SFX's default volume. " - "Interjections and actual sound effects count as 'SFX'.")); - ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_sfx_volume_lbl); - - ui_sfx_volume_spinbox = new QSpinBox(ui_audio_widget); - ui_sfx_volume_spinbox->setMaximum(100); - ui_sfx_volume_spinbox->setSuffix("%"); - - ui_audio_layout->setWidget(row, QFormLayout::FieldRole, - ui_sfx_volume_spinbox); - - row += 1; - ui_blips_volume_lbl = new QLabel(ui_audio_widget); - ui_blips_volume_lbl->setText(tr("Blips:")); - ui_blips_volume_lbl->setToolTip( - tr("Sets the volume of the blips, the talking sound effects.")); - - ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_blips_volume_lbl); - - ui_blips_volume_spinbox = new QSpinBox(ui_audio_widget); - ui_blips_volume_spinbox->setMaximum(100); - ui_blips_volume_spinbox->setSuffix("%"); - - ui_audio_layout->setWidget(row, QFormLayout::FieldRole, - ui_blips_volume_spinbox); - - row += 1; - ui_suppress_audio_lbl = new QLabel(ui_audio_widget); - ui_suppress_audio_lbl->setText(tr("Suppress Audio:")); - ui_suppress_audio_lbl->setToolTip( - tr("How much of the volume to suppress when client is not in focus.")); - - ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_suppress_audio_lbl); - - ui_suppress_audio_spinbox = new QSpinBox(ui_audio_widget); - ui_suppress_audio_spinbox->setMaximum(100); - ui_suppress_audio_spinbox->setSuffix("%"); - - ui_audio_layout->setWidget(row, QFormLayout::FieldRole, - ui_suppress_audio_spinbox); - - row += 1; - ui_volume_blip_divider = new QFrame(ui_audio_widget); - ui_volume_blip_divider->setFrameShape(QFrame::HLine); - ui_volume_blip_divider->setFrameShadow(QFrame::Sunken); - - ui_audio_layout->setWidget(row, QFormLayout::FieldRole, - ui_volume_blip_divider); - - row += 1; - ui_bliprate_lbl = new QLabel(ui_audio_widget); - ui_bliprate_lbl->setText(tr("Blip rate:")); - ui_bliprate_lbl->setToolTip( - tr("Sets the delay between playing the blip sounds.")); - - ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_bliprate_lbl); - - ui_bliprate_spinbox = new QSpinBox(ui_audio_widget); - ui_bliprate_spinbox->setMinimum(0); - ui_bliprate_spinbox->setToolTip( - tr("Play a blip sound \"once per every X symbols\", where " - "X is the blip rate. 0 plays a blip sound only once.")); - - ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_bliprate_spinbox); - - row += 1; - ui_blank_blips_lbl = new QLabel(ui_audio_widget); - ui_blank_blips_lbl->setText(tr("Blank blips:")); - ui_blank_blips_lbl->setToolTip( - tr("If true, the game will play a blip sound even " - "when a space is 'being said'.")); - - ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_blank_blips_lbl); - - ui_blank_blips_cb = new QCheckBox(ui_audio_widget); - - ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_blank_blips_cb); - - row += 1; - ui_loopsfx_lbl = new QLabel(ui_audio_widget); - ui_loopsfx_lbl->setText(tr("Enable Looping SFX:")); - ui_loopsfx_lbl->setToolTip(tr("If true, the game will allow looping sound " - "effects to play on preanimations.")); - - ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_loopsfx_lbl); - - ui_loopsfx_cb = new QCheckBox(ui_audio_widget); - - ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_loopsfx_cb); - - row += 1; - ui_objectmusic_lbl = new QLabel(ui_audio_widget); - ui_objectmusic_lbl->setText(tr("Kill Music On Objection:")); - ui_objectmusic_lbl->setToolTip( - tr("If true, AO2 will ask the server to stop music when you use 'Objection!' ")); - - ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_objectmusic_lbl); - - ui_objectmusic_cb = new QCheckBox(ui_audio_widget); - - ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_objectmusic_cb); - - row += 1; - ui_disablestreams_lbl = new QLabel(ui_audio_widget); - ui_disablestreams_lbl->setText(tr("Disable Music Streaming:")); - ui_disablestreams_lbl->setToolTip( - tr("If true, AO2 will not play any streamed audio and show that streaming is disabled.")); - ui_audio_layout->setWidget(row, QFormLayout::LabelRole, ui_disablestreams_lbl); - - ui_disablestreams_cb = new QCheckBox(ui_audio_widget); - ui_audio_layout->setWidget(row, QFormLayout::FieldRole, ui_disablestreams_cb); - - // The casing tab! - ui_casing_tab = new QWidget(this); - ui_settings_tabs->addTab(ui_casing_tab, tr("Casing")); - - ui_casing_widget = new QWidget(ui_casing_tab); - ui_casing_widget->setGeometry(QRect(10, 10, 361, 211)); - - ui_casing_layout = new QFormLayout(ui_casing_widget); - ui_casing_layout->setLabelAlignment(Qt::AlignLeading | Qt::AlignLeft | - Qt::AlignVCenter); - ui_casing_layout->setFormAlignment(Qt::AlignLeading | Qt::AlignLeft | - Qt::AlignTop); - ui_casing_layout->setContentsMargins(0, 0, 0, 0); - row = 0; - - // -- SERVER SUPPORTS CASING - - ui_casing_supported_lbl = new QLabel(ui_casing_widget); - if (ao_app->casing_alerts_supported) - ui_casing_supported_lbl->setText(tr("This server supports case alerts.")); - else - ui_casing_supported_lbl->setText( - tr("This server does not support case alerts.")); - ui_casing_supported_lbl->setToolTip(tr("Pretty self-explanatory.")); - - ui_casing_layout->setWidget(row, QFormLayout::FieldRole, - ui_casing_supported_lbl); - - // -- CASE ANNOUNCEMENTS - - row += 1; - ui_casing_enabled_lbl = new QLabel(ui_casing_widget); - ui_casing_enabled_lbl->setText(tr("Casing:")); - ui_casing_enabled_lbl->setToolTip( - tr("If checked, you will get alerts about case " - "announcements.")); - - ui_casing_layout->setWidget(row, QFormLayout::LabelRole, - ui_casing_enabled_lbl); - - ui_casing_enabled_cb = new QCheckBox(ui_casing_widget); - - ui_casing_layout->setWidget(row, QFormLayout::FieldRole, - ui_casing_enabled_cb); - - // -- DEFENSE ANNOUNCEMENTS - - row += 1; - ui_casing_def_lbl = new QLabel(ui_casing_widget); - ui_casing_def_lbl->setText(tr("Defense:")); - ui_casing_def_lbl->setToolTip(tr("If checked, you will get alerts about case " - "announcements if a defense spot is open.")); - - ui_casing_layout->setWidget(row, QFormLayout::LabelRole, ui_casing_def_lbl); - - ui_casing_def_cb = new QCheckBox(ui_casing_widget); - - ui_casing_layout->setWidget(row, QFormLayout::FieldRole, ui_casing_def_cb); - - // -- PROSECUTOR ANNOUNCEMENTS - - row += 1; - ui_casing_pro_lbl = new QLabel(ui_casing_widget); - ui_casing_pro_lbl->setText(tr("Prosecution:")); - ui_casing_pro_lbl->setToolTip( - tr("If checked, you will get alerts about case " - "announcements if a prosecutor spot is open.")); - - ui_casing_layout->setWidget(row, QFormLayout::LabelRole, ui_casing_pro_lbl); - - ui_casing_pro_cb = new QCheckBox(ui_casing_widget); - - ui_casing_layout->setWidget(row, QFormLayout::FieldRole, ui_casing_pro_cb); - - // -- JUDGE ANNOUNCEMENTS - - row += 1; - ui_casing_jud_lbl = new QLabel(ui_casing_widget); - ui_casing_jud_lbl->setText(tr("Judge:")); - ui_casing_jud_lbl->setToolTip(tr("If checked, you will get alerts about case " - "announcements if the judge spot is open.")); - - ui_casing_layout->setWidget(row, QFormLayout::LabelRole, ui_casing_jud_lbl); - - ui_casing_jud_cb = new QCheckBox(ui_casing_widget); - - ui_casing_layout->setWidget(row, QFormLayout::FieldRole, ui_casing_jud_cb); - - // -- JUROR ANNOUNCEMENTS - - row += 1; - ui_casing_jur_lbl = new QLabel(ui_casing_widget); - ui_casing_jur_lbl->setText(tr("Juror:")); - ui_casing_jur_lbl->setToolTip(tr("If checked, you will get alerts about case " - "announcements if a juror spot is open.")); - - ui_casing_layout->setWidget(row, QFormLayout::LabelRole, ui_casing_jur_lbl); - - ui_casing_jur_cb = new QCheckBox(ui_casing_widget); - - ui_casing_layout->setWidget(row, QFormLayout::FieldRole, ui_casing_jur_cb); - - // -- STENO ANNOUNCEMENTS - - row += 1; - ui_casing_steno_lbl = new QLabel(ui_casing_widget); - ui_casing_steno_lbl->setText(tr("Stenographer:")); - ui_casing_steno_lbl->setToolTip( - tr("If checked, you will get alerts about case " - "announcements if a stenographer spot is open.")); - - ui_casing_layout->setWidget(row, QFormLayout::LabelRole, ui_casing_steno_lbl); - - ui_casing_steno_cb = new QCheckBox(ui_casing_widget); - - ui_casing_layout->setWidget(row, QFormLayout::FieldRole, ui_casing_steno_cb); - - // -- CM ANNOUNCEMENTS - - row += 1; - ui_casing_cm_lbl = new QLabel(ui_casing_widget); - ui_casing_cm_lbl->setText(tr("CM:")); - ui_casing_cm_lbl->setToolTip( - tr("If checked, you will appear amongst the potential " - "CMs on the server.")); - - ui_casing_layout->setWidget(row, QFormLayout::LabelRole, ui_casing_cm_lbl); - - ui_casing_cm_cb = new QCheckBox(ui_casing_widget); - - ui_casing_layout->setWidget(row, QFormLayout::FieldRole, ui_casing_cm_cb); - - // -- CM CASES ANNOUNCEMENTS - - row += 1; - ui_casing_cm_cases_lbl = new QLabel(ui_casing_widget); - ui_casing_cm_cases_lbl->setText(tr("Hosting cases:")); - ui_casing_cm_cases_lbl->setToolTip( - tr("If you're a CM, enter what cases you are " - "willing to host.")); - - ui_casing_layout->setWidget(row, QFormLayout::LabelRole, - ui_casing_cm_cases_lbl); - - ui_casing_cm_cases_textbox = new QLineEdit(ui_casing_widget); - - ui_casing_layout->setWidget(row, QFormLayout::FieldRole, - ui_casing_cm_cases_textbox); - - // Assets tab - ui_assets_tab = new QWidget(this); - ui_assets_tab_layout = new QVBoxLayout(ui_assets_tab); - ui_assets_tab->setLayout(ui_assets_tab_layout); - ui_settings_tabs->addTab(ui_assets_tab, tr("Assets")); - - ui_asset_lbl = new QLabel(ui_assets_tab); - ui_asset_lbl->setText( - tr("Add or remove base folders for use by assets. " - "Base folders on the bottom are prioritized over those above them.")); - ui_asset_lbl->setWordWrap(true); - ui_assets_tab_layout->addWidget(ui_asset_lbl); - - ui_mount_list = new QListWidget(ui_assets_tab); - ui_assets_tab_layout->addWidget(ui_mount_list); - - ui_mount_buttons_layout = new QGridLayout(ui_assets_tab); - ui_assets_tab_layout->addLayout(ui_mount_buttons_layout); - - QSizePolicy stretch_btns(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); - stretch_btns.setHorizontalStretch(4); - - ui_mount_add = new QPushButton(tr("Add…"), ui_assets_tab); - ui_mount_add->setSizePolicy(stretch_btns); - ui_mount_buttons_layout->addWidget(ui_mount_add, 0, 0, 1, 1); - connect(ui_mount_add, &QPushButton::clicked, this, [this] { - QString 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("../")) { - path = relative; - } - QListWidgetItem *dir_item = new QListWidgetItem(path); - ui_mount_list->addItem(dir_item); - ui_mount_list->setCurrentItem(dir_item); - - // quick hack to update buttons - emit ui_mount_list->itemSelectionChanged(); - }); - - ui_mount_remove = new QPushButton(tr("Remove"), ui_assets_tab); - ui_mount_remove->setSizePolicy(stretch_btns); - ui_mount_remove->setEnabled(false); - ui_mount_buttons_layout->addWidget(ui_mount_remove, 0, 1, 1, 1); - connect(ui_mount_remove, &QPushButton::clicked, this, [this] { - auto selected = ui_mount_list->selectedItems(); - if (selected.isEmpty()) - return; - delete selected[0]; - emit ui_mount_list->itemSelectionChanged(); - asset_cache_dirty = true; - }); - - auto *mount_buttons_spacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, - QSizePolicy::Minimum); - ui_mount_buttons_layout->addItem(mount_buttons_spacer, 0, 2, 1, 1); - - ui_mount_up = new QPushButton(tr("↑"), ui_assets_tab); - ui_mount_up->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); - ui_mount_up->setMaximumWidth(40); - ui_mount_up->setEnabled(false); - ui_mount_buttons_layout->addWidget(ui_mount_up, 0, 3, 1, 1); - connect(ui_mount_up, &QPushButton::clicked, this, [this] { - auto selected = ui_mount_list->selectedItems(); - if (selected.isEmpty()) - return; - auto *item = selected[0]; - int row = ui_mount_list->row(item); - ui_mount_list->takeItem(row); - int new_row = qMax(1, row - 1); - ui_mount_list->insertItem(new_row, item); - ui_mount_list->setCurrentRow(new_row); - asset_cache_dirty = true; - }); - - ui_mount_down = new QPushButton(tr("↓"), ui_assets_tab); - ui_mount_down->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); - ui_mount_down->setMaximumWidth(40); - ui_mount_down->setEnabled(false); - ui_mount_buttons_layout->addWidget(ui_mount_down, 0, 4, 1, 1); - connect(ui_mount_down, &QPushButton::clicked, this, [this] { - auto selected = ui_mount_list->selectedItems(); - if (selected.isEmpty()) - return; - auto *item = selected[0]; - int row = ui_mount_list->row(item); - ui_mount_list->takeItem(row); - int new_row = qMin(ui_mount_list->count() + 1, row + 1); - ui_mount_list->insertItem(new_row, item); - ui_mount_list->setCurrentRow(new_row); - asset_cache_dirty = true; - }); - - auto *mount_buttons_spacer_2 = new QSpacerItem(40, 20, QSizePolicy::Expanding, - QSizePolicy::Minimum); - ui_mount_buttons_layout->addItem(mount_buttons_spacer_2, 0, 5, 1, 1); - - ui_mount_clear_cache = new QPushButton(tr("Clear Cache"), ui_assets_tab); - ui_mount_clear_cache->setToolTip(tr("Clears the lookup cache for assets. " - "Use this when you have added an asset that takes precedence over another " - "existing asset.")); - ui_mount_buttons_layout->addWidget(ui_mount_clear_cache, 0, 6, 1, 1); - connect(ui_mount_clear_cache, &QPushButton::clicked, this, [this] { - asset_cache_dirty = true; - ui_mount_clear_cache->setEnabled(false); - }); - - connect(ui_mount_list, &QListWidget::itemSelectionChanged, this, [this] { - auto selected_items = ui_mount_list->selectedItems(); - bool row_selected = !ui_mount_list->selectedItems().isEmpty(); - ui_mount_remove->setEnabled(row_selected); - ui_mount_up->setEnabled(row_selected); - ui_mount_down->setEnabled(row_selected); - - if (!row_selected) - return; - - int row = ui_mount_list->row(selected_items[0]); - if (row <= 1) - ui_mount_up->setEnabled(false); - if (row >= ui_mount_list->count() - 1) - ui_mount_down->setEnabled(false); - }); - - // Logging tab - ui_logging_tab = new QWidget(this); - ui_settings_tabs->addTab(ui_logging_tab, tr("Logging")); - ui_form_logging_widget = new QWidget(this); - - ui_logging_form = new QFormLayout(ui_form_logging_widget); - ui_logging_form->setLabelAlignment(Qt::AlignLeading | Qt::AlignLeft | - Qt::AlignVCenter); - ui_logging_form->setFormAlignment(Qt::AlignLeading | Qt::AlignLeft | - Qt::AlignTop); - ui_logging_form->setContentsMargins(5, 5, 0, 0); - ui_logging_form->setSpacing(4); - row = 0; - - ui_downwards_lbl = new QLabel(ui_form_logging_widget); - ui_downwards_lbl->setText(tr("Log goes downwards:")); - ui_downwards_lbl->setToolTip( - tr("If ticked, new messages will appear at " - "the bottom (like the OOC chatlog). The traditional " - "(AO1) behaviour is equivalent to this being unticked.")); - - ui_logging_form->setWidget(row, QFormLayout::LabelRole, ui_downwards_lbl); - - ui_downwards_cb = new QCheckBox(ui_form_logging_widget); - - ui_logging_form->setWidget(row, QFormLayout::FieldRole, ui_downwards_cb); - - row += 1; - ui_length_lbl = new QLabel(ui_form_logging_widget); - ui_length_lbl->setText(tr("Log length:")); - ui_length_lbl->setToolTip(tr( - "The amount of message lines the IC chatlog will keep before " - "deleting older message lines. A value of 0 or below counts as 'infinite'.")); - - ui_logging_form->setWidget(row, QFormLayout::LabelRole, ui_length_lbl); - - ui_length_spinbox = new QSpinBox(ui_form_logging_widget); - ui_length_spinbox->setSuffix(" lines"); - ui_length_spinbox->setMaximum(10000); - - ui_logging_form->setWidget(row, QFormLayout::FieldRole, ui_length_spinbox); - - row += 1; - ui_log_newline_lbl = new QLabel(ui_form_logging_widget); - ui_log_newline_lbl->setText(tr("Log newline:")); - ui_log_newline_lbl->setToolTip( - tr("If ticked, new messages will appear separated, " - "with the message coming on the next line after the name. " - "When unticked, it displays it as 'name: message'.")); - - ui_logging_form->setWidget(row, QFormLayout::LabelRole, ui_log_newline_lbl); - - ui_log_newline_cb = new QCheckBox(ui_form_logging_widget); - - ui_logging_form->setWidget(row, QFormLayout::FieldRole, ui_log_newline_cb); - - row += 1; - ui_log_margin_lbl = new QLabel(ui_form_logging_widget); - ui_log_margin_lbl->setText(tr("Log margin:")); - ui_log_margin_lbl->setToolTip(tr( - "The distance in pixels between each entry in the IC log. " - "Default: 0.")); - - ui_logging_form->setWidget(row, QFormLayout::LabelRole, ui_log_margin_lbl); - - ui_log_margin_spinbox = new QSpinBox(ui_form_logging_widget); - ui_log_margin_spinbox->setSuffix(" px"); - ui_log_margin_spinbox->setMaximum(1000); - - ui_logging_form->setWidget(row, QFormLayout::FieldRole, ui_log_margin_spinbox); - - row += 1; - ui_log_timestamp_lbl = new QLabel(ui_form_logging_widget); - ui_log_timestamp_lbl->setText(tr("Log timestamp:")); - ui_log_timestamp_lbl->setToolTip( - tr("If ticked, log will contain a timestamp in UTC before the name.")); - - ui_logging_form->setWidget(row, QFormLayout::LabelRole, ui_log_timestamp_lbl); - - ui_log_timestamp_cb = new QCheckBox(ui_form_logging_widget); - - connect(ui_log_timestamp_cb, &QCheckBox::stateChanged, this, &AOOptionsDialog::timestamp_cb_changed); - - ui_logging_form->setWidget(row, QFormLayout::FieldRole, ui_log_timestamp_cb); - - row += 1; - ui_log_timestamp_format_lbl = new QLabel(ui_form_logging_widget); - ui_log_timestamp_format_lbl->setText(tr("Log timestamp format:\n") + QDateTime::currentDateTime().toString(ao_app->get_log_timestamp_format())); - ui_logging_form->setWidget(row, QFormLayout::LabelRole, ui_log_timestamp_format_lbl); - - ui_log_timestamp_format_combobox = new QComboBox(ui_form_logging_widget); - ui_log_timestamp_format_combobox->setEditable(true); - - QString l_current_format = ao_app->get_log_timestamp_format(); - - ui_log_timestamp_format_combobox->setCurrentText(l_current_format); - ui_log_timestamp_format_combobox->addItem("h:mm:ss AP"); // 2:13:09 PM - ui_log_timestamp_format_combobox->addItem("hh:mm:ss"); // 14:13:09 - ui_log_timestamp_format_combobox->addItem("h:mm AP"); // 2:13 PM - ui_log_timestamp_format_combobox->addItem("hh:mm"); // 14:13 - - ui_logging_form->setWidget(row, QFormLayout::FieldRole, ui_log_timestamp_format_combobox); - - connect(ui_log_timestamp_format_combobox, &QComboBox::currentTextChanged, this, &AOOptionsDialog::on_timestamp_format_edited); - - if(!ao_app->get_log_timestamp()) { - ui_log_timestamp_format_combobox->setDisabled(true); - } - row += 1; - ui_log_ic_actions_lbl = new QLabel(ui_form_logging_widget); - ui_log_ic_actions_lbl->setText(tr("Log IC actions:")); - ui_log_ic_actions_lbl->setToolTip( - tr("If ticked, log will show IC actions such as shouting and presenting evidence.")); - - ui_logging_form->setWidget(row, QFormLayout::LabelRole, ui_log_ic_actions_lbl); - - ui_log_ic_actions_cb = new QCheckBox(ui_form_logging_widget); - - ui_logging_form->setWidget(row, QFormLayout::FieldRole, ui_log_ic_actions_cb); - - row += 1; - ui_desync_logs_lbl = new QLabel(ui_form_logging_widget); - ui_desync_logs_lbl->setText(tr("Desynchronize IC Logs:")); - ui_desync_logs_lbl->setToolTip( - tr("If ticked, log will show messages as-received, while viewport will parse according to the queue (Text Stay Time).")); - - ui_logging_form->setWidget(row, QFormLayout::LabelRole, ui_desync_logs_lbl); - - ui_desync_logs_cb = new QCheckBox(ui_form_logging_widget); - - ui_logging_form->setWidget(row, QFormLayout::FieldRole, ui_desync_logs_cb); - - //Check whether mass logging is enabled - row += 1; - ui_log_text_lbl = new QLabel(ui_form_logging_widget); - ui_log_text_lbl->setText(tr("Log to Text Files:")); - ui_log_text_lbl->setToolTip( - tr("Text logs of gameplay will be automatically written in the /logs folder.")); - ui_logging_form->setWidget(row, QFormLayout::LabelRole, ui_log_text_lbl); - - ui_log_text_cb = new QCheckBox(ui_form_logging_widget); - ui_logging_form->setWidget(row, QFormLayout::FieldRole, ui_log_text_cb); - - row += 1; - ui_log_demo_lbl = new QLabel(ui_form_logging_widget); - ui_log_demo_lbl->setText(tr("Log to Demo Files:")); - ui_log_demo_lbl->setToolTip( - tr("Gameplay will be automatically recorded as demos in the /logs folder.")); - ui_logging_form->setWidget(row, QFormLayout::LabelRole, ui_log_demo_lbl); - - ui_log_demo_cb = new QCheckBox(ui_form_logging_widget); - ui_logging_form->setWidget(row, QFormLayout::FieldRole, ui_log_demo_cb); - - // Finish logging tab - QScrollArea *log_scroll = new QScrollArea(this); - log_scroll->setWidget(ui_form_logging_widget); - ui_logging_tab->setLayout(new QVBoxLayout); - ui_logging_tab->layout()->addWidget(log_scroll); - - // Privacy tab - ui_privacy_tab = new QWidget(this); - ui_settings_tabs->addTab(ui_privacy_tab, tr("Privacy")); - - ui_privacy_layout = new QVBoxLayout(ui_privacy_tab); - - ui_privacy_optout_cb = new QCheckBox(ui_privacy_tab); - ui_privacy_optout_cb->setText(tr("Do not include me in public player counts")); - ui_privacy_layout->addWidget(ui_privacy_optout_cb); - - ui_privacy_separator = new QFrame(ui_privacy_tab); - ui_privacy_separator->setObjectName(QString::fromUtf8("line")); - ui_privacy_separator->setFrameShape(QFrame::HLine); - ui_privacy_separator->setFrameShadow(QFrame::Sunken); - ui_privacy_layout->addWidget(ui_privacy_separator); - - ui_privacy_policy = new QTextBrowser(ui_privacy_tab); - QSizePolicy privacySizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - sizePolicy.setHorizontalStretch(0); - sizePolicy.setVerticalStretch(0); - ui_privacy_policy->setSizePolicy(privacySizePolicy); - ui_privacy_policy->setPlainText(tr("Getting privacy policy...")); - ui_privacy_layout->addWidget(ui_privacy_policy); - - update_values(); - - // When we're done, we should continue the updates! - setUpdatesEnabled(true); -} - -void AOOptionsDialog::update_values() { - for (int i = 0; i < ui_theme_combobox->count(); ++i) { - if (ui_theme_combobox->itemText(i) == ao_app->read_theme()) - { - ui_theme_combobox->setCurrentIndex(i); - break; - } - } - QString subtheme = - ao_app->configini->value("subtheme").value(); - for (int i = 0; i < ui_subtheme_combobox->count(); ++i) { - if (ui_subtheme_combobox->itemText(i) == subtheme) - { - ui_subtheme_combobox->setCurrentIndex(i); - break; - } - } - Qt::TransformationMode scaling = ao_app->get_scaling(ao_app->get_default_scaling()); - ui_scaling_combobox->setCurrentIndex(scaling); - - // Let's fill the callwords text edit with the already present callwords. - ui_callwords_textbox->document()->clear(); - foreach (QString callword, ao_app->get_call_words()) { - ui_callwords_textbox->appendPlainText(callword); - } - ui_animated_theme_cb->setChecked(ao_app->get_animated_theme()); - ui_ms_textbox->setText(ao_app->configini->value("master", "").value()); - ui_casing_cm_cases_textbox->setText(ao_app->get_casing_can_host_cases()); - ui_username_textbox->setText(ao_app->get_default_username()); - ui_downwards_cb->setChecked(ao_app->get_log_goes_downwards()); - ui_log_newline_cb->setChecked(ao_app->get_log_newline()); - ui_log_timestamp_cb->setChecked(ao_app->get_log_timestamp()); - ui_log_timestamp_format_combobox->setCurrentText(ao_app->get_log_timestamp_format()); - ui_log_ic_actions_cb->setChecked(ao_app->get_log_ic_actions()); - ui_desync_logs_cb->setChecked(ao_app->is_desyncrhonized_logs_enabled()); - ui_instant_objection_cb->setChecked(ao_app->is_instant_objection_enabled()); - ui_showname_cb->setChecked(ao_app->get_showname_enabled_by_default()); - ui_discord_cb->setChecked(ao_app->is_discord_enabled()); - ui_shake_cb->setChecked(ao_app->is_shake_enabled()); - ui_effects_cb->setChecked(ao_app->is_effects_enabled()); - ui_framenetwork_cb->setChecked(ao_app->is_frame_network_enabled()); - ui_colorlog_cb->setChecked(ao_app->is_colorlog_enabled()); - ui_stickysounds_cb->setChecked(ao_app->is_stickysounds_enabled()); - ui_stickyeffects_cb->setChecked(ao_app->is_stickyeffects_enabled()); - ui_stickypres_cb->setChecked(ao_app->is_stickypres_enabled()); - ui_customchat_cb->setChecked(ao_app->is_customchat_enabled()); - ui_sticker_cb->setChecked(ao_app->is_sticker_enabled()); - ui_continuous_cb->setChecked(ao_app->is_continuous_enabled()); - ui_category_stop_cb->setChecked(ao_app->is_category_stop_enabled()); - ui_sfx_on_idle_cb->setChecked(ao_app->get_sfx_on_idle()); - ui_blank_blips_cb->setChecked(ao_app->get_blank_blip()); - ui_loopsfx_cb->setChecked(ao_app->get_looping_sfx()); - ui_objectmusic_cb->setChecked(ao_app->objection_stop_music()); - ui_disablestreams_cb->setChecked(ao_app->is_streaming_disabled()); - ui_casing_enabled_cb->setChecked(ao_app->get_casing_enabled()); - ui_casing_def_cb->setChecked(ao_app->get_casing_defence_enabled()); - ui_casing_pro_cb->setChecked(ao_app->get_casing_prosecution_enabled()); - ui_casing_jud_cb->setChecked(ao_app->get_casing_judge_enabled()); - ui_casing_jur_cb->setChecked(ao_app->get_casing_juror_enabled()); - ui_casing_steno_cb->setChecked(ao_app->get_casing_steno_enabled()); - ui_casing_cm_cb->setChecked(ao_app->get_casing_cm_enabled()); - ui_log_text_cb->setChecked(ao_app->get_text_logging_enabled()); - ui_log_demo_cb->setChecked(ao_app->get_demo_logging_enabled()); - ui_length_spinbox->setValue(ao_app->get_max_log_size()); - ui_log_margin_spinbox->setValue(ao_app->get_log_margin()); - ui_stay_time_spinbox->setValue(ao_app->stay_time()); - ui_text_crawl_spinbox->setValue(ao_app->get_text_crawl()); - ui_chat_ratelimit_spinbox->setValue(ao_app->get_chat_ratelimit()); - ui_music_volume_spinbox->setValue(ao_app->get_default_music()); - ui_sfx_volume_spinbox->setValue(ao_app->get_default_sfx()); - ui_blips_volume_spinbox->setValue(ao_app->get_default_blip()); - ui_suppress_audio_spinbox->setValue(ao_app->get_default_suppress_audio()); - ui_bliprate_spinbox->setValue(ao_app->read_blip_rate()); - ui_default_showname_textbox->setText(ao_app->get_default_showname()); - ui_evidence_double_click_cb->setChecked(ao_app->get_evidence_double_click()); - - auto *defaultMount = new QListWidgetItem(tr("%1 (default)") - .arg(ao_app->get_base_path())); - defaultMount->setFlags(Qt::ItemFlag::NoItemFlags); - - //Clear the list to prevent duplication of default entries. - ui_mount_list->clear(); - ui_mount_list->addItem(defaultMount); - ui_mount_list->addItems(ao_app->get_mount_paths()); - - ui_privacy_optout_cb->setChecked(ao_app->get_player_count_optout()); - - ao_app->net_manager->request_document(MSDocumentType::PrivacyPolicy, [this](QString document) { - if (document.isEmpty()) { - document = tr("Couldn't get the privacy policy."); - } - ui_privacy_policy->setHtml(document); - }); -} - -void AOOptionsDialog::save_pressed() -{ - // Save everything into the config.ini. - QSettings *configini = ao_app->configini; - - const bool audioChanged = ui_audio_device_combobox->currentText() != - ao_app->get_audio_output_device(); - - configini->setValue("theme", ui_theme_combobox->currentText()); - configini->setValue("subtheme", ui_subtheme_combobox->currentText()); - configini->setValue("animated_theme", ui_animated_theme_cb->isChecked()); - configini->setValue("log_goes_downwards", ui_downwards_cb->isChecked()); - configini->setValue("log_maximum", ui_length_spinbox->value()); - configini->setValue("log_newline", ui_log_newline_cb->isChecked()); - configini->setValue("log_margin", ui_log_margin_spinbox->value()); - configini->setValue("log_timestamp", ui_log_timestamp_cb->isChecked()); - configini->setValue("log_timestamp_format", ui_log_timestamp_format_combobox->currentText()); - configini->setValue("log_ic_actions", ui_log_ic_actions_cb->isChecked()); - configini->setValue("desync_logs", ui_desync_logs_cb->isChecked()); - configini->setValue("stay_time", ui_stay_time_spinbox->value()); - configini->setValue("instant_objection", ui_instant_objection_cb->isChecked()); - configini->setValue("text_crawl", ui_text_crawl_spinbox->value()); - configini->setValue("chat_ratelimit", ui_chat_ratelimit_spinbox->value()); - configini->setValue("default_username", ui_username_textbox->text()); - configini->setValue("show_custom_shownames", ui_showname_cb->isChecked()); - configini->setValue("default_showname", ui_default_showname_textbox->text()); - configini->setValue("master", ui_ms_textbox->text()); - configini->setValue("discord", ui_discord_cb->isChecked()); - configini->setValue("language", ui_language_combobox->currentText().left(2)); - configini->setValue("default_scaling", ui_scaling_combobox->currentData()); - configini->setValue("shake", ui_shake_cb->isChecked()); - configini->setValue("effects", ui_effects_cb->isChecked()); - configini->setValue("framenetwork", ui_framenetwork_cb->isChecked()); - configini->setValue("colorlog", ui_colorlog_cb->isChecked()); - configini->setValue("stickysounds", ui_stickysounds_cb->isChecked()); - configini->setValue("stickyeffects", ui_stickyeffects_cb->isChecked()); - configini->setValue("stickypres", ui_stickypres_cb->isChecked()); - configini->setValue("customchat", ui_customchat_cb->isChecked()); - configini->setValue("sticker", ui_sticker_cb->isChecked()); - configini->setValue("automatic_logging_enabled", ui_log_text_cb->isChecked()); - configini->setValue("demo_logging_enabled", ui_log_demo_cb->isChecked()); - configini->setValue("continuous_playback", ui_continuous_cb->isChecked()); - configini->setValue("category_stop", ui_category_stop_cb->isChecked()); - configini->setValue("sfx_on_idle", ui_sfx_on_idle_cb->isChecked()); - configini->setValue("evidence_double_click", ui_evidence_double_click_cb->isChecked()); - QFile *callwordsini = new QFile(ao_app->get_base_path() + "callwords.ini"); - - if (callwordsini->open(QIODevice::WriteOnly | QIODevice::Truncate | - QIODevice::Text)) { - QTextStream out(callwordsini); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - out.setCodec("UTF-8"); -#endif - out << ui_callwords_textbox->toPlainText(); - callwordsini->close(); - } - - configini->setValue("default_audio_device", - ui_audio_device_combobox->currentText()); - configini->setValue("default_music", ui_music_volume_spinbox->value()); - configini->setValue("default_sfx", ui_sfx_volume_spinbox->value()); - configini->setValue("default_blip", ui_blips_volume_spinbox->value()); - configini->setValue("suppress_audio", ui_suppress_audio_spinbox->value()); - configini->setValue("blip_rate", ui_bliprate_spinbox->value()); - configini->setValue("blank_blip", ui_blank_blips_cb->isChecked()); - configini->setValue("looping_sfx", ui_loopsfx_cb->isChecked()); - configini->setValue("objection_stop_music", ui_objectmusic_cb->isChecked()); - configini->setValue("streaming_disabled", ui_disablestreams_cb->isChecked()); - - configini->setValue("casing_enabled", ui_casing_enabled_cb->isChecked()); - configini->setValue("casing_defence_enabled", ui_casing_def_cb->isChecked()); - configini->setValue("casing_prosecution_enabled", - ui_casing_pro_cb->isChecked()); - configini->setValue("casing_judge_enabled", ui_casing_jud_cb->isChecked()); - configini->setValue("casing_juror_enabled", ui_casing_jur_cb->isChecked()); - configini->setValue("casing_steno_enabled", ui_casing_steno_cb->isChecked()); - configini->setValue("casing_cm_enabled", ui_casing_cm_cb->isChecked()); - configini->setValue("casing_can_host_cases", - ui_casing_cm_cases_textbox->text()); - configini->setValue("player_count_optout", ui_privacy_optout_cb->isChecked()); - - QStringList mountPaths; - for (int i = 1; i < ui_mount_list->count(); i++) - mountPaths.append(ui_mount_list->item(i)->text()); - configini->setValue("mount_paths", mountPaths); - - if (audioChanged) - ao_app->initBASS(); - - if (asset_cache_dirty) - ao_app->invalidate_lookup_cache(); - - // We most probably pressed "Restore defaults" at some point. Since we're saving our settings, remove the temporary file. - if (QFile::exists(ao_app->get_base_path() + "config.temp")) - QFile::remove(ao_app->get_base_path() + "config.temp"); - done(0); -} - -void AOOptionsDialog::discard_pressed() { - // The .temp file exists, meaning we are trying to undo the user clicking on "Restore defaults" and bring back the old settings. - if (QFile::exists(ao_app->get_base_path() + "config.temp")) { - // Delete the QSettings object so it does not interfere with the file - delete ao_app->configini; - // Remove the current config.ini - QFile::remove(ao_app->get_base_path() + "config.ini"); - // Rename .temp to .ini - QFile::rename(ao_app->get_base_path() + "config.temp", ao_app->get_base_path() + "config.ini"); - // Recreate the QSettings object from the ini file, restoring the settings before the Options Dialog was opened.. - ao_app->configini = - new QSettings(ao_app->get_base_path() + "config.ini", QSettings::IniFormat); - } - done(0); -} - -void AOOptionsDialog::button_clicked(QAbstractButton *button) { - if (ui_settings_buttons->buttonRole(button) == QDialogButtonBox::ResetRole) { - // Store the current settings as a .temp file - QFile::rename(ao_app->get_base_path() + "config.ini", ao_app->get_base_path() + "config.temp"); - // Load up the default settings - ao_app->configini->clear(); - // Update the values on the settings ui - update_values(); - } -} - -void AOOptionsDialog::on_reload_theme_clicked() { - ao_app->configini->setValue("theme", ui_theme_combobox->currentText()); - ao_app->configini->setValue("subtheme", ui_subtheme_combobox->currentText()); - ao_app->configini->setValue("animated_theme", ui_animated_theme_cb->isChecked()); - if (ao_app->courtroom_constructed) - ao_app->w_courtroom->on_reload_theme_clicked(); - if (ao_app->lobby_constructed) - ao_app->w_lobby->set_widgets(); -} - -void AOOptionsDialog::theme_changed(int i) { - ui_subtheme_combobox->clear(); - // Fill the combobox with the names of the themes. - ui_subtheme_combobox->addItem("server"); - ui_subtheme_combobox->addItem("default"); - QDirIterator it(ao_app->get_real_path(ao_app->get_theme_path("", ui_theme_combobox->itemText(i))), QDir::Dirs, - QDirIterator::NoIteratorFlags); - while (it.hasNext()) { - QString actualname = QDir(it.next()).dirName(); - if (actualname != "." && actualname != ".." && actualname.toLower() != "server" && actualname.toLower() != "default" && actualname.toLower() != "effects" && actualname.toLower() != "misc") - ui_subtheme_combobox->addItem(actualname); - } - -} - -void AOOptionsDialog::on_timestamp_format_edited() { ui_log_timestamp_format_lbl->setText(tr("Log timestamp format:\n") + QDateTime::currentDateTime().toString(ui_log_timestamp_format_combobox->currentText())); } - -void AOOptionsDialog::timestamp_cb_changed(int state) { ui_log_timestamp_format_combobox->setDisabled(state == 0); } - -#if (defined(_WIN32) || defined(_WIN64)) -bool AOOptionsDialog::needs_default_audiodev() { return true; } -#elif (defined(LINUX) || defined(__linux__)) -bool AOOptionsDialog::needs_default_audiodev() { return false; } -#elif defined __APPLE__ -bool AOOptionsDialog::needs_default_audiodev() { return true; } -#else -#error This operating system is not supported. -#endif From eb0814e4ef419fb62d2081a66afbed56886635ec Mon Sep 17 00:00:00 2001 From: stonedDiscord Date: Wed, 28 Dec 2022 21:59:17 +0100 Subject: [PATCH 04/61] only set setting codec on qt5 --- src/options.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/options.cpp b/src/options.cpp index 7efaf9f6a..6cef55282 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -21,7 +21,9 @@ void Options::migrateCallwords() } QTextStream in(&l_file); - in.setCodec("UTF-8"); + #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + in.setCodec("UTF-8"); + #endif while (!in.atEnd()) { QString line = in.readLine(); From f413f5b0af1ba6ae8093edaab852fd3550315cbe Mon Sep 17 00:00:00 2001 From: stonedDiscord Date: Wed, 28 Dec 2022 22:08:27 +0100 Subject: [PATCH 05/61] fix old regex --- src/lobby.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lobby.cpp b/src/lobby.cpp index 5e3d032b6..4cd307989 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -441,7 +441,7 @@ void Lobby::set_server_description(const QString &server_description) ui_server_description_text->clear(); QString result = server_description.toHtmlEscaped() .replace("\n", "
") - .replace(QRegExp("\\b(https?://\\S+\\.\\S+)\\b"), + .replace(QRegularExpression("\\b(https?://\\S+\\.\\S+)\\b"), "\\1"); ui_server_description_text->insertHtml(result); } From ec9d6191a9edf7ddad6498881df3d2d932880a4b Mon Sep 17 00:00:00 2001 From: stonedDiscord Date: Wed, 28 Dec 2022 22:15:47 +0100 Subject: [PATCH 06/61] qlocale include was missing --- src/options.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/options.cpp b/src/options.cpp index 6cef55282..ca3a8dd3b 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -6,6 +6,7 @@ #include #include #include +#include void Options::migrateCallwords() { From 60411daa53fc2717ae211a7598e6abfc36f1e8d2 Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Sun, 22 Jan 2023 22:07:29 +0100 Subject: [PATCH 07/61] Add default soundfont value + cleaup stream checks --- include/aomusicplayer.h | 27 ++++++++++----------------- src/aoapplication.cpp | 2 ++ src/aomusicplayer.cpp | 21 +++++++-------------- 3 files changed, 19 insertions(+), 31 deletions(-) diff --git a/include/aomusicplayer.h b/include/aomusicplayer.h index 35bd78440..67e6888c5 100644 --- a/include/aomusicplayer.h +++ b/include/aomusicplayer.h @@ -1,11 +1,5 @@ #ifndef AOMUSICPLAYER_H #define AOMUSICPLAYER_H -#include "file_functions.h" - -#include "bass.h" -#include "bassmidi.h" -#include "bassopus.h" - #include "aoapplication.h" #include @@ -24,17 +18,6 @@ class AOMusicPlayer { const int m_channelmax = 4; - // These have to be public for the stupid sync thing - /** - * @brief The starting sample of the AB-Loop. - */ - unsigned int loop_start[4] = {0, 0, 0, 0}; - - /** - * @brief The end sample of the AB-Loop. - */ - unsigned int loop_end[4] = {0, 0, 0, 0}; - QFutureWatcher music_watcher; public slots: @@ -56,6 +39,16 @@ public slots: // Channel 3 = extra HSTREAM m_stream_list[4]; HSYNC loop_sync[4]; + + /** + * @brief The starting sample of the AB-Loop. + */ + unsigned int loop_start[4] = {0, 0, 0, 0}; + + /** + * @brief The end sample of the AB-Loop. + */ + unsigned int loop_end[4] = {0, 0, 0, 0}; }; #endif // AOMUSICPLAYER_H diff --git a/src/aoapplication.cpp b/src/aoapplication.cpp index c444b77ab..41b33b575 100644 --- a/src/aoapplication.cpp +++ b/src/aoapplication.cpp @@ -250,12 +250,14 @@ void AOApplication::initBASS() 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()); return; } } BASS_Init(-1, 48000, BASS_DEVICE_LATENCY, nullptr, nullptr); load_bass_plugins(); } + BASS_SetConfigPtr(BASS_CONFIG_MIDI_DEFFONT, QString(get_base_path() + "soundfont.sf2").toStdString().c_str()); } #if (defined(_WIN32) || defined(_WIN64)) diff --git a/src/aomusicplayer.cpp b/src/aomusicplayer.cpp index c7090e67c..8abd38b6b 100644 --- a/src/aomusicplayer.cpp +++ b/src/aomusicplayer.cpp @@ -1,6 +1,9 @@ #include "aomusicplayer.h" #include "options.h" +#include "bass.h" +#include "file_functions.h" + AOMusicPlayer::AOMusicPlayer(QWidget *parent, AOApplication *p_ao_app) { m_parent = parent; @@ -35,21 +38,11 @@ QString AOMusicPlayer::play(QString p_song, int channel, bool loop, BASS_ChannelStop(m_stream_list[channel]); return QObject::tr("[MISSING] Streaming disabled."); } - - if (f_path.endsWith(".opus")) - newstream = BASS_OPUS_StreamCreateURL(f_path.toStdString().c_str(), 0, streaming_flags, nullptr, 0); - else if (f_path.endsWith(".mid")) - newstream = BASS_MIDI_StreamCreateURL(f_path.toStdString().c_str(), 0, streaming_flags, nullptr, 0, 1); - else - newstream = BASS_StreamCreateURL(f_path.toStdString().c_str(), 0, streaming_flags, nullptr, 0); - - } else { + newstream = BASS_StreamCreateURL(f_path.toStdString().c_str(), 0, streaming_flags, nullptr, 0); + } + else { f_path = ao_app->get_real_path(ao_app->get_music_path(p_song)); - if (f_path.endsWith(".opus")) - newstream = BASS_OPUS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, flags); - else if (f_path.endsWith(".mid")) - newstream = BASS_MIDI_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, flags, 1); - else 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") ) + 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); From 693f21d5becd27e2391b7dc12f03f31abf6d5ee1 Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Mon, 23 Jan 2023 02:33:03 +0100 Subject: [PATCH 08/61] Remove Case Announcement --- include/aocaseannouncerdialog.h | 46 ------------ include/courtroom.h | 10 --- include/options.h | 32 --------- include/widgets/aooptionsdialog.h | 10 --- resource/ui/options_dialog.ui | 115 ------------------------------ src/aoapplication.cpp | 7 -- src/aocaseannouncerdialog.cpp | 85 ---------------------- src/courtroom.cpp | 96 ------------------------- src/options.cpp | 92 +++--------------------- src/packet_distribution.cpp | 7 -- src/widgets/aooptionsdialog.cpp | 32 --------- 11 files changed, 11 insertions(+), 521 deletions(-) delete mode 100644 include/aocaseannouncerdialog.h delete mode 100644 src/aocaseannouncerdialog.cpp diff --git a/include/aocaseannouncerdialog.h b/include/aocaseannouncerdialog.h deleted file mode 100644 index 0ac8f0746..000000000 --- a/include/aocaseannouncerdialog.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef AOCASEANNOUNCERDIALOG_H -#define AOCASEANNOUNCERDIALOG_H - -#include "aoapplication.h" -#include "courtroom.h" - -#include -#include -#include -#include -#include -#include -#include - -class AOCaseAnnouncerDialog : public QDialog { - Q_OBJECT - -public: - explicit AOCaseAnnouncerDialog(QWidget *parent = nullptr, - AOApplication *p_ao_app = nullptr, - Courtroom *p_court = nullptr); - -private: - AOApplication *ao_app; - Courtroom *court; - - QDialogButtonBox *ui_announcer_buttons; - - QVBoxLayout *ui_vbox_layout; - QFormLayout *ui_form_layout; - - QLabel *ui_case_title_label; - QLineEdit *ui_case_title_textbox; - - QCheckBox *ui_defense_needed; - QCheckBox *ui_prosecutor_needed; - QCheckBox *ui_judge_needed; - QCheckBox *ui_juror_needed; - QCheckBox *ui_steno_needed; - -public slots: - void ok_pressed(); - void cancel_pressed(); -}; - -#endif // AOCASEANNOUNCERDIALOG_H diff --git a/include/courtroom.h b/include/courtroom.h index 6e9a4c97a..6107a7f66 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -318,9 +318,6 @@ class Courtroom : public QMainWindow { // Toggles the judge buttons, whether they should appear or not. void show_judge_controls(bool visible); - void announce_case(QString title, bool def, bool pro, bool jud, bool jur, - bool steno); - void check_connection_received(); void start_clock(int id); @@ -741,14 +738,12 @@ class Courtroom : public QMainWindow { AOButton *ui_reload_theme; AOButton *ui_call_mod; AOButton *ui_settings; - AOButton *ui_announce_casing; AOButton *ui_switch_area_music; QCheckBox *ui_pre; QCheckBox *ui_flip; QCheckBox *ui_additive; QCheckBox *ui_guard; - QCheckBox *ui_casing; QCheckBox *ui_immediate; QCheckBox *ui_showname_enable; @@ -852,8 +847,6 @@ public slots: void mod_called(QString p_ip); - void case_called(QString msg, bool def, bool pro, bool jud, bool jur, - bool steno); void on_reload_theme_clicked(); void update_ui_music_name(); @@ -975,7 +968,6 @@ private slots: void on_change_character_clicked(); void on_call_mod_clicked(); void on_settings_clicked(); - void on_announce_casing_clicked(); void on_pre_clicked(); void on_flip_clicked(); @@ -1016,8 +1008,6 @@ private slots: void on_switch_area_music_clicked(); - void on_casing_clicked(); - void on_application_state_changed(Qt::ApplicationState state); void ping_server(); diff --git a/include/options.h b/include/options.h index fe37dc6cc..306be421d 100644 --- a/include/options.h +++ b/include/options.h @@ -209,38 +209,6 @@ class Options { QString shownameOnJoin() const; void setShownameOnJoin(QString value); - // Returns if the user has casing alerts Enabled. - bool casingAlertEnabled() const; - void setCasingAlertEnabled(bool value); - - // Returns if the user wants to get alerts for the defence role. - bool casingDefenceEnabled() const; - void setcasingDefenceEnabled(bool value); - - // Same for prosecution. - bool casingProsecutionEnabled() const; - void setCasingProseuctionEnabled(bool value); - - // Same for judge. - bool casingJudgeEnabled() const; - void setCasingJudgeEnabled(bool value); - - // Same for juror. - bool casingJurorEnabled() const; - void setCasingJurorEnabled(bool value); - - // Same for steno. - bool casingStenoEnabled() const; - void setCasingStenoEnabled(bool value); - - // Same for CM. - bool casingCmEnabled() const; - void setCasingCmEnabled(bool value); - - // Get the message for the CM for casing alerts. - QString casingCanHostCases() const; - void setCasingCanHostCases(QString value); - // Get if text file logging is Enabled bool logToTextFileEnabled() const; void setLogToTextFileEnabled(bool value); diff --git a/include/widgets/aooptionsdialog.h b/include/widgets/aooptionsdialog.h index 21fc322b6..e5a21246e 100644 --- a/include/widgets/aooptionsdialog.h +++ b/include/widgets/aooptionsdialog.h @@ -102,16 +102,6 @@ class AOOptionsDialog : public QDialog { QCheckBox *ui_objectmusic_cb; QCheckBox *ui_disablestreams_cb; - // The casing tab - QGroupBox *ui_casing_enabled_box; - QCheckBox *ui_casing_def_cb; - QCheckBox *ui_casing_pro_cb; - QCheckBox *ui_casing_jud_cb; - QCheckBox *ui_casing_jur_cb; - QCheckBox *ui_casing_steno_cb; - QCheckBox *ui_casing_cm_cb; - QLineEdit *ui_casing_cm_cases_textbox; - // The asset tab QListWidget *ui_mount_list; QPushButton *ui_mount_add; diff --git a/resource/ui/options_dialog.ui b/resource/ui/options_dialog.ui index d63643248..419eadd7d 100644 --- a/resource/ui/options_dialog.ui +++ b/resource/ui/options_dialog.ui @@ -800,121 +800,6 @@ - - - Casing - - - - - - If checked, you will get alerts about case announcements. - - - Casing - - - true - - - false - - - - - - If checked, you will get alerts about case announcements if a defense spot is open. - - - Defense - - - - - - - If checked, you will get alerts about case announcements if a juror spot is open. - - - Juror - - - - - - - If checked, you will get alerts about case announcements if a stenographer spot is open. - - - Stenographer - - - - - - - If checked, you will appear amongst the potential CMs on the server. - - - Case Master - - - - - - - - - If you're a CM, enter what cases you are willing to host. - - - Hosting cases: - - - - - - - - - - - - If checked, you will get alerts about case announcements if a prosecutor spot is open. - - - Prosecution - - - - - - - If checked, you will get alerts about case announcements if the judge spot is open. - - - Judge - - - - - - - - - - Qt::Vertical - - - - 20 - 338 - - - - - - diff --git a/src/aoapplication.cpp b/src/aoapplication.cpp index 41b33b575..e033d09f8 100644 --- a/src/aoapplication.cpp +++ b/src/aoapplication.cpp @@ -6,7 +6,6 @@ #include "networkmanager.h" #include "options.h" -#include "aocaseannouncerdialog.h" #include "widgets/aooptionsdialog.h" static QtMessageHandler original_message_handler; @@ -204,12 +203,6 @@ void AOApplication::call_settings_menu() delete l_dialog; } -void AOApplication::call_announce_menu(Courtroom *court) -{ - AOCaseAnnouncerDialog announcer(nullptr, this, court); - announcer.exec(); -} - // Callback for when BASS device is lost // Only actually used for music syncs void CALLBACK AOApplication::BASSreset(HSTREAM handle, DWORD channel, diff --git a/src/aocaseannouncerdialog.cpp b/src/aocaseannouncerdialog.cpp deleted file mode 100644 index 0c9ee0f36..000000000 --- a/src/aocaseannouncerdialog.cpp +++ /dev/null @@ -1,85 +0,0 @@ -#include "aocaseannouncerdialog.h" - -AOCaseAnnouncerDialog::AOCaseAnnouncerDialog(QWidget *parent, - AOApplication *p_ao_app, - Courtroom *p_court) - : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint) -{ - ao_app = p_ao_app; - court = p_court; - - setWindowTitle(tr("Case Announcer")); - resize(405, 235); - - ui_announcer_buttons = new QDialogButtonBox(this); - - QSizePolicy sizepolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - sizepolicy.setHorizontalStretch(0); - sizepolicy.setVerticalStretch(0); - sizepolicy.setHeightForWidth( - ui_announcer_buttons->sizePolicy().hasHeightForWidth()); - ui_announcer_buttons->setSizePolicy(sizepolicy); - ui_announcer_buttons->setOrientation(Qt::Horizontal); - ui_announcer_buttons->setStandardButtons(QDialogButtonBox::Ok | - QDialogButtonBox::Cancel); - - connect(ui_announcer_buttons, &QDialogButtonBox::accepted, this, - &AOCaseAnnouncerDialog::ok_pressed); - connect(ui_announcer_buttons, &QDialogButtonBox::rejected, this, - &AOCaseAnnouncerDialog::cancel_pressed); - - setUpdatesEnabled(false); - - ui_vbox_layout = new QVBoxLayout(this); - - ui_form_layout = new QFormLayout(this); - ui_form_layout->setLabelAlignment(Qt::AlignLeading | Qt::AlignLeft | - Qt::AlignVCenter); - ui_form_layout->setFormAlignment(Qt::AlignLeading | Qt::AlignLeft | - Qt::AlignTop); - ui_form_layout->setContentsMargins(6, 6, 6, 6); - - ui_vbox_layout->addItem(ui_form_layout); - ui_vbox_layout->addWidget(ui_announcer_buttons); - - ui_case_title_label = new QLabel(this); - ui_case_title_label->setText(tr("Case title:")); - - ui_form_layout->setWidget(0, QFormLayout::LabelRole, ui_case_title_label); - - ui_case_title_textbox = new QLineEdit(this); - ui_case_title_textbox->setMaxLength(50); - - ui_form_layout->setWidget(0, QFormLayout::FieldRole, ui_case_title_textbox); - - ui_defense_needed = new QCheckBox(this); - ui_defense_needed->setText(tr("Defense needed")); - ui_prosecutor_needed = new QCheckBox(this); - ui_prosecutor_needed->setText(tr("Prosecution needed")); - ui_judge_needed = new QCheckBox(this); - ui_judge_needed->setText(tr("Judge needed")); - ui_juror_needed = new QCheckBox(this); - ui_juror_needed->setText(tr("Jurors needed")); - ui_steno_needed = new QCheckBox(this); - ui_steno_needed->setText(tr("Stenographer needed")); - - ui_form_layout->setWidget(1, QFormLayout::FieldRole, ui_defense_needed); - ui_form_layout->setWidget(2, QFormLayout::FieldRole, ui_prosecutor_needed); - ui_form_layout->setWidget(3, QFormLayout::FieldRole, ui_judge_needed); - ui_form_layout->setWidget(4, QFormLayout::FieldRole, ui_juror_needed); - ui_form_layout->setWidget(5, QFormLayout::FieldRole, ui_steno_needed); - - setUpdatesEnabled(true); -} - -void AOCaseAnnouncerDialog::ok_pressed() -{ - court->announce_case( - ui_case_title_textbox->text(), ui_defense_needed->isChecked(), - ui_prosecutor_needed->isChecked(), ui_judge_needed->isChecked(), - ui_juror_needed->isChecked(), ui_steno_needed->isChecked()); - - done(0); -} - -void AOCaseAnnouncerDialog::cancel_pressed() { done(0); } diff --git a/src/courtroom.cpp b/src/courtroom.cpp index ebbf2c0ec..6116eb204 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -291,9 +291,6 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_settings = new AOButton(this, ao_app); ui_settings->setObjectName("ui_settings"); - ui_announce_casing = new AOButton(this, ao_app); - ui_announce_casing->setObjectName("ui_announce_casing"); - ui_switch_area_music = new AOButton(this, ao_app); ui_switch_area_music->setObjectName("ui_switch_area_music"); @@ -316,12 +313,6 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_additive->hide(); ui_additive->setObjectName("ui_additive"); - ui_casing = new QCheckBox(this); - ui_casing->setChecked(Options::getInstance().casingAlertEnabled()); - ui_casing->setText(tr("Casing")); - ui_casing->hide(); - ui_casing->setObjectName("ui_casing"); - ui_showname_enable = new QCheckBox(this); ui_showname_enable->setChecked(Options::getInstance().customShownameEnabled()); ui_showname_enable->setText(tr("Shownames")); @@ -540,8 +531,6 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() &Courtroom::on_reload_theme_clicked); connect(ui_call_mod, &AOButton::clicked, this, &Courtroom::on_call_mod_clicked); connect(ui_settings, &AOButton::clicked, this, &Courtroom::on_settings_clicked); - connect(ui_announce_casing, &AOButton::clicked, this, - &Courtroom::on_announce_casing_clicked); connect(ui_switch_area_music, &AOButton::clicked, this, &Courtroom::on_switch_area_music_clicked); @@ -549,7 +538,6 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() connect(ui_flip, &AOButton::clicked, this, &Courtroom::on_flip_clicked); connect(ui_additive, &AOButton::clicked, this, &Courtroom::on_additive_clicked); connect(ui_guard, &AOButton::clicked, this, &Courtroom::on_guard_clicked); - connect(ui_casing, &AOButton::clicked, this, &Courtroom::on_casing_clicked); connect(ui_showname_enable, &AOButton::clicked, this, &Courtroom::on_showname_enable_clicked); @@ -691,15 +679,6 @@ void Courtroom::set_widgets() ui_ic_chat_name->setEnabled(false); } - if (ao_app->casing_alerts_supported) { - ui_announce_casing->show(); - ui_casing->show(); - } - else { - ui_announce_casing->hide(); - ui_casing->hide(); - } - // We also show the non-server-dependent client additions. // Once again, if the theme can't display it, set_move_and_pos will catch // them. @@ -1012,13 +991,6 @@ void Courtroom::set_widgets() ui_settings->setToolTip( tr("Allows you to change various aspects of the client.")); - set_size_and_pos(ui_announce_casing, "casing_button"); - ui_announce_casing->setText(tr("Casing")); - ui_announce_casing->set_image("casing_button"); - ui_announce_casing->setToolTip( - tr("An interface to help you announce a case (you have to be a CM first " - "to be able to announce cases)")); - set_size_and_pos(ui_switch_area_music, "switch_area_music"); ui_switch_area_music->setText(tr("A/M")); ui_switch_area_music->set_image("switch_area_music"); @@ -1059,10 +1031,6 @@ void Courtroom::set_widgets() 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_casing, "casing"); - ui_casing->setToolTip(tr("Lets you receive case alerts when enabled.\n" - "(You can set your preferences in the Settings!)")); - set_size_and_pos(ui_showname_enable, "showname_enable"); ui_showname_enable->setToolTip( tr("Display customized shownames for all users when checked.")); @@ -1600,11 +1568,6 @@ void Courtroom::enter_courtroom() else ui_additive->hide(); - if (ao_app->casing_alerts_supported) - ui_casing->show(); - else - ui_casing->hide(); - list_music(); list_areas(); @@ -4243,21 +4206,6 @@ void Courtroom::mod_called(QString p_ip) } } -void Courtroom::case_called(QString msg, bool def, bool pro, bool jud, bool jur, - bool steno) -{ - Q_UNUSED(def); - Q_UNUSED(pro); - Q_UNUSED(jud); - Q_UNUSED(jur); - Q_UNUSED(steno); - if (ui_casing->isChecked()) { - ui_server_chatlog->append(msg); - modcall_player->play(ao_app->get_court_sfx("case_call")); - ao_app->alert(this); - } -} - void Courtroom::on_ooc_return_pressed() { QString ooc_message = ui_ooc_chat_message->text(); @@ -5644,11 +5592,6 @@ void Courtroom::on_call_mod_clicked() void Courtroom::on_settings_clicked() { ao_app->call_settings_menu(); } -void Courtroom::on_announce_casing_clicked() -{ - ao_app->call_announce_menu(this); -} - void Courtroom::on_pre_clicked() { ui_ic_chat_message->setFocus(); } void Courtroom::on_flip_clicked() { ui_ic_chat_message->setFocus(); } @@ -5748,45 +5691,6 @@ qint64 Courtroom::pong() return ping_timer.elapsed(); } -void Courtroom::on_casing_clicked() -{ - if (ao_app->casing_alerts_supported) { - if (ui_casing->isChecked()) { - QStringList f_packet; - - f_packet.append(Options::getInstance().casingCanHostCases()); - f_packet.append(QString::number(Options::getInstance().casingCmEnabled())); - f_packet.append(QString::number(Options::getInstance().casingDefenceEnabled())); - f_packet.append( - QString::number(Options::getInstance().casingProsecutionEnabled())); - f_packet.append(QString::number(Options::getInstance().casingJudgeEnabled())); - f_packet.append(QString::number(Options::getInstance().casingJurorEnabled())); - f_packet.append(QString::number(Options::getInstance().casingStenoEnabled())); - - ao_app->send_server_packet(new AOPacket("SETCASE", f_packet)); - } - else - ao_app->send_server_packet(new AOPacket("SETCASE", {"","0","0","0","0","0","0"})); - } -} - -void Courtroom::announce_case(QString title, bool def, bool pro, bool jud, - bool jur, bool steno) -{ - if (ao_app->casing_alerts_supported) { - QStringList f_packet; - - f_packet.append(title); - f_packet.append(QString::number(def)); - f_packet.append(QString::number(pro)); - f_packet.append(QString::number(jud)); - f_packet.append(QString::number(jur)); - f_packet.append(QString::number(steno)); - - ao_app->send_server_packet(new AOPacket("CASEA", f_packet)); - } -} - void Courtroom::start_clock(int id) { if (id >= 0 && id < max_clocks && ui_clock[id] != nullptr) diff --git a/src/options.cpp b/src/options.cpp index ca3a8dd3b..be429a77d 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -60,6 +60,17 @@ void Options::migrate() } config.remove("ooc_name"); } + + if (config.contains("casing_enabled")) { + config.remove("casing_enabled"); + config.remove("casing_defence_enabled"); + config.remove("casing_prosecution_enabled"); + config.remove("casing_judge_enabled"); + config.remove("casing_juror_enabled"); + config.remove("casing_steno_enabled"); + config.remove("casing_cm_enabled"); + config.remove("casing_can_host_cases"); + } } QString Options::theme() const @@ -418,87 +429,6 @@ void Options::setStopMusicOnCategoryEnabled(bool value) config.setValue("category_stop", value); } -bool Options::casingAlertEnabled() const -{ - return config.value("casing_enabled", false).toBool(); -} - -void Options::setCasingAlertEnabled(bool value) -{ - config.setValue("casing_enabled", value); -} - -bool Options::casingDefenceEnabled() const -{ - return config.value("casing_defence_enabled", false).toBool(); -} - -void Options::setcasingDefenceEnabled(bool value) -{ - config.setValue("casing_defence_enabled", value); -} - -bool Options::casingProsecutionEnabled() const -{ - return config.value("casing_prosecution_enabled", false).toBool(); -} - -void Options::setCasingProseuctionEnabled(bool value) -{ - config.setValue("casing_prosecution_enabled", value); -} - -bool Options::casingJudgeEnabled() const -{ - return config.value("casing_judge_enabled", false).toBool(); -} - -void Options::setCasingJudgeEnabled(bool value) -{ - config.setValue("casing_judge_enabled", value); -} - -bool Options::casingJurorEnabled() const -{ - return config.value("casing_juror_enabled", false).toBool(); -} - -void Options::setCasingJurorEnabled(bool value) -{ - config.setValue("casing_juror_enabled", value); -} - -bool Options::casingStenoEnabled() const -{ - return config.value("casing_steno_enabled", false).toBool(); -} - -void Options::setCasingStenoEnabled(bool value) -{ - config.setValue("casing_steno_enabled", value); -} - -bool Options::casingCmEnabled() const -{ - return config.value("casing_cm_enabled", false).toBool(); -} - -void Options::setCasingCmEnabled(bool value) -{ - config.setValue("casing_cm_enabled", value); -} - -QString Options::casingCanHostCases() const -{ - return config.value("casing_can_host_cases", "Turnabout Check Your Settings") - .toString(); -} - -void Options::setCasingCanHostCases(QString value) -{ - config.setValue("casing_can_host_cases", value); -} - bool Options::logToTextFileEnabled() const { return config.value("automatic_logging_enabled", true).toBool(); diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index bc9c7eaae..670c86af4 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -494,13 +494,6 @@ void AOApplication::server_packet_received(AOPacket *p_packet) if (courtroom_constructed && !f_contents.isEmpty()) w_courtroom->mod_called(f_contents.at(0)); } - else if (header == "CASEA") { - if (courtroom_constructed && f_contents.size() >= 6) - w_courtroom->case_called(f_contents.at(0), f_contents.at(1) == "1", - f_contents.at(2) == "1", f_contents.at(3) == "1", - f_contents.at(4) == "1", - f_contents.at(5) == "1"); - } else if (header == "TI") { // Timer packet if (!courtroom_constructed || f_contents.size() < 2) goto end; diff --git a/src/widgets/aooptionsdialog.cpp b/src/widgets/aooptionsdialog.cpp index e9fbcaf39..dfa911362 100644 --- a/src/widgets/aooptionsdialog.cpp +++ b/src/widgets/aooptionsdialog.cpp @@ -210,38 +210,6 @@ AOOptionsDialog::AOOptionsDialog(QDialog *parent, AOApplication *p_ao_app) &Options::streamingEnabled, &Options::setStreamingEnabled); - // Casing tab. - FROM_UI(QGroupBox, casing_enabled_box) - FROM_UI(QCheckBox, casing_def_cb) - FROM_UI(QCheckBox, casing_pro_cb) - FROM_UI(QCheckBox, casing_jud_cb) - FROM_UI(QCheckBox, casing_jur_cb) - FROM_UI(QCheckBox, casing_steno_cb) - FROM_UI(QCheckBox, casing_cm_cb) - FROM_UI(QLineEdit, casing_cm_cases_textbox) - - registerOption("casing_enabled_box", - &Options::casingAlertEnabled, - &Options::setCasingAlertEnabled); - registerOption("casing_def_cb", - &Options::casingDefenceEnabled, - &Options::setcasingDefenceEnabled); - registerOption("casing_pro_cb", - &Options::casingProsecutionEnabled, - &::Options::setCasingProseuctionEnabled); - registerOption("casing_jud_cb", &Options::casingJudgeEnabled, - &::Options::setCasingJudgeEnabled); - registerOption("casing_jur_cb", &Options::casingJurorEnabled, - &Options::setCasingJurorEnabled); - registerOption("casing_steno_cb", - &Options::casingStenoEnabled, - &Options::setCasingStenoEnabled); - registerOption("casing_cm_cb", &Options::casingCmEnabled, - &Options::setCasingCmEnabled); - registerOption("casing_cm_cases_textbox", - &Options::casingCanHostCases, - &Options::setCasingCanHostCases); - // Asset tab FROM_UI(QListWidget, mount_list) auto *defaultMount = From 2e312f061809dfa89fc15d13ebb6512f8519bf50 Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Mon, 23 Jan 2023 04:51:44 +0100 Subject: [PATCH 09/61] Add add_server dialog and move logic to options.h --- include/aoapplication.h | 24 ----- include/lobby.h | 2 + include/options.h | 15 +++ include/widgets/add_server_dialog.h | 48 +++++++++ resource/ui/add_server_dialog.ui | 149 ++++++++++++++++++++++++++++ resource/ui/lobby.ui | 11 +- resources.qrc | 1 + src/aoapplication.cpp | 56 ----------- src/lobby.cpp | 78 +++++++++------ src/options.cpp | 105 +++++++++++++++++++- src/packet_distribution.cpp | 1 + src/text_file_functions.cpp | 85 ---------------- src/widgets/add_server_dialog.cpp | 92 +++++++++++++++++ 13 files changed, 464 insertions(+), 203 deletions(-) create mode 100644 include/widgets/add_server_dialog.h create mode 100644 resource/ui/add_server_dialog.ui create mode 100644 src/widgets/add_server_dialog.cpp diff --git a/include/aoapplication.h b/include/aoapplication.h index 66399f0db..ed466f906 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -132,10 +132,6 @@ class AOApplication : public QApplication { /////////////////////////////////////////// - void load_favorite_list(); - void save_favorite_list(); - QVector &get_favorite_list() { return favorite_list; } - // Adds the server to favorite_servers.ini void add_favorite_server(int p_server); void remove_favorite_server(int p_server); @@ -190,25 +186,6 @@ class AOApplication : public QApplication { // Append to the currently open demo file if there is one void append_to_demofile(QString packet_string); - /** - * @brief Reads favorite_servers.ini and returns a list of servers. - * - * The demo server entry is always present at the top of the list. - * - * If the server list returned was to be empty (exluding the demo server entry), - * will return a list of servers from the legacy serverlist.txt file. - * - * @return A list of servers. - */ - QVector read_favorite_servers(); - - /** - * @brief Reads serverlist.txt and returns a list of servers. - * - * @return A list of servers. - */ - QVector read_legacy_favorite_servers(); - /** * @brief Reads the clients log folder and locates potential demo files to populate the demoserver list. * @@ -410,7 +387,6 @@ class AOApplication : public QApplication { const int MINOR_VERSION = 0; QVector server_list; - QVector favorite_list; QHash asset_lookup_cache; QHash dir_listing_cache; QSet dir_listing_exist_cache; diff --git a/include/lobby.h b/include/lobby.h index 85693c249..623e8235d 100644 --- a/include/lobby.h +++ b/include/lobby.h @@ -67,6 +67,7 @@ class Lobby : public QMainWindow { QLineEdit *ui_demo_search; QPushButton *ui_add_to_favorite_button; + QPushButton *ui_add_server_button; QPushButton *ui_remove_from_favorites_button; QPushButton *ui_refresh_button; @@ -81,6 +82,7 @@ private slots: void on_tab_changed(int index); void on_refresh_released(); void on_add_to_fav_released(); + void on_add_server_to_fave_released(); void on_remove_from_fav_released(); void on_about_clicked(); void on_server_list_clicked(QTreeWidgetItem *p_item, int column); diff --git a/include/options.h b/include/options.h index 306be421d..a77937e71 100644 --- a/include/options.h +++ b/include/options.h @@ -4,6 +4,7 @@ #include #include +#include class Options { private: @@ -12,6 +13,12 @@ class Options { */ QSettings config; + /** + * @brief QSettings object for favorite_servers.ini + */ + QSettings favorite; + + void migrateCallwords(); /** @@ -259,6 +266,14 @@ class Options { // Clears the configuration file. Essentially restoring it to default. void clearConfig(); + + // Loads the favorite servers + QVector favorites(); + void setFavorites(QVector value); + + // Interactions with favorite servers + void removeFavorite(int index); + void addFavorite(server_type server); }; #endif // OPTIONS_H diff --git a/include/widgets/add_server_dialog.h b/include/widgets/add_server_dialog.h new file mode 100644 index 000000000..9111a4ef5 --- /dev/null +++ b/include/widgets/add_server_dialog.h @@ -0,0 +1,48 @@ +#ifndef ADD_SERVER_DIALOG_H +#define ADD_SERVER_DIALOG_H + +#include +#include +class QPushButton; +class QDialogButton; +class QLineEdit; +class QComboBox; +class QSpinBox; +class QPlainTextEdit; +class QDialogButtonBox; +class QSettings; + +class AddServerDialog : public QDialog { + Q_OBJECT +public : + AddServerDialog(); + ~AddServerDialog(); + +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 + QLineEdit* ui_server_legacy_edit; + QPushButton* ui_server_legacy_load_button; + + + QSettings* m_favorite_ini; + + const int TCP_INDEX = 0; + + const QString DEFAULT_UI = ":/resource/ui/add_server_dialog.ui"; + +private slots: + void savePressed(); + void discardPressed(); + void parseLegacyServerEntry(); +}; + +#endif // ADD_SERVER_DIALOG_H diff --git a/resource/ui/add_server_dialog.ui b/resource/ui/add_server_dialog.ui new file mode 100644 index 000000000..fc0459aa8 --- /dev/null +++ b/resource/ui/add_server_dialog.ui @@ -0,0 +1,149 @@ + + + add_server_widget + + + + 0 + 0 + 412 + 423 + + + + Form + + + + + + + + Legacy Entry : + + + + + + + + + + Convert + + + + + + + + + QFrame::Plain + + + Qt::Horizontal + + + + + + + + + Display Name: + + + + + + + + + + Hostname : + + + + + + + + + + Port: + + + + + + + 65535 + + + + + + + Protocol : + + + + + + + Description: + + + + + + + + TCP + + + + + WEBSOCKET + + + + + + + + + 0 + 0 + + + + + + + + + + Add your server to your favorites : + + + + + + + QDialogButtonBox::Close|QDialogButtonBox::Save + + + + + + + Convert legacy favorite entries: + + + + + + + + diff --git a/resource/ui/lobby.ui b/resource/ui/lobby.ui index 29a561f19..ec3f6f95d 100644 --- a/resource/ui/lobby.ui +++ b/resource/ui/lobby.ui @@ -85,7 +85,7 @@ - Version: 2.11.0 + Version: 2.10.1 @@ -372,10 +372,17 @@ + + + + Add + + + - Remove From Favorites + Remove diff --git a/resources.qrc b/resources.qrc index 5194097f7..6a05e2c67 100644 --- a/resources.qrc +++ b/resources.qrc @@ -10,6 +10,7 @@ resource/translations/ao_pt.qm resource/translations/ao_ru.qm resource/ui/options_dialog.ui + resource/ui/add_server_dialog.ui resource/ui/lobby.ui diff --git a/src/aoapplication.cpp b/src/aoapplication.cpp index e033d09f8..622546d72 100644 --- a/src/aoapplication.cpp +++ b/src/aoapplication.cpp @@ -46,7 +46,6 @@ void AOApplication::construct_lobby() return; } - load_favorite_list(); w_lobby = new Lobby(this, net_manager); lobby_constructed = true; @@ -120,61 +119,6 @@ QString AOApplication::get_version_string() QString::number(MINOR_VERSION); } -void AOApplication::load_favorite_list() -{ - favorite_list = read_favorite_servers(); -} - -void AOApplication::save_favorite_list() -{ - QSettings favorite_servers_ini(get_base_path() + "favorite_servers.ini", QSettings::IniFormat); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - favorite_servers_ini.setIniCodec("UTF-8"); -#endif - - favorite_servers_ini.clear(); - for(int i = 0; i < favorite_list.size(); ++i) { - auto fav_server = favorite_list.at(i); - favorite_servers_ini.beginGroup(QString::number(i)); - favorite_servers_ini.setValue("name", fav_server.name); - favorite_servers_ini.setValue("address", fav_server.ip); - favorite_servers_ini.setValue("port", fav_server.port); - favorite_servers_ini.setValue("desc", fav_server.desc); - - if (fav_server.socket_type == TCP) { - favorite_servers_ini.setValue("protocol", "tcp"); - } else { - favorite_servers_ini.setValue("protocol", "ws"); - } - favorite_servers_ini.endGroup(); - } - favorite_servers_ini.sync(); -} - -QString AOApplication::get_current_char() -{ - if (courtroom_constructed) - return w_courtroom->get_current_char(); - else - return ""; -} - -void AOApplication::add_favorite_server(int p_server) -{ - if (p_server < 0 || p_server >= server_list.size()) - return; - favorite_list.append(server_list.at(p_server)); - save_favorite_list(); -} - -void AOApplication::remove_favorite_server(int p_server) -{ - if (p_server < 0 || p_server >= favorite_list.size()) - return; - favorite_list.removeAt(p_server); - save_favorite_list(); -} - void AOApplication::server_disconnected() { if (courtroom_constructed) { diff --git a/src/lobby.cpp b/src/lobby.cpp index 4cd307989..f54acbd50 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -3,6 +3,7 @@ #include "aoapplication.h" #include "demoserver.h" #include "networkmanager.h" +#include "widgets/add_server_dialog.h" #include #include @@ -82,8 +83,13 @@ Lobby::Lobby(AOApplication *p_ao_app, NetworkManager *p_net_manager) connect(ui_add_to_favorite_button, &QPushButton::released, this, &Lobby::on_add_to_fav_released); - FROM_UI(QPushButton, remove_from_favorites_button) - ui_remove_from_favorites_button->setVisible(false); + 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) + + 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); @@ -92,8 +98,8 @@ Lobby::Lobby(AOApplication *p_ao_app, NetworkManager *p_net_manager) FROM_UI(QPushButton, connect_button); connect(ui_connect_button, &QPushButton::released, net_manager, &NetworkManager::join_to_server); - connect(net_manager, &NetworkManager::server_connected, - ui_connect_button, &QPushButton::setEnabled); + connect(net_manager, &NetworkManager::server_connected, ui_connect_button, + &QPushButton::setEnabled); FROM_UI(QTextBrowser, motd_text); @@ -110,15 +116,18 @@ void Lobby::on_tab_changed(int index) case SERVER: ui_add_to_favorite_button->setVisible(true); ui_remove_from_favorites_button->setVisible(false); + ui_add_server_button->setVisible(false); reset_selection(); break; case FAVORITES: ui_add_to_favorite_button->setVisible(false); ui_remove_from_favorites_button->setVisible(true); + ui_add_server_button->setVisible(true); reset_selection(); break; case DEMOS: ui_add_to_favorite_button->setVisible(false); + ui_add_server_button->setVisible(false); ui_remove_from_favorites_button->setVisible(false); reset_selection(); break; @@ -157,7 +166,6 @@ void Lobby::on_refresh_released() { net_manager->get_server_list(std::bind(&Lobby::list_servers, this)); get_motd(); - ao_app->load_favorite_list(); list_favorites(); } @@ -165,16 +173,23 @@ void Lobby::on_add_to_fav_released() { int selection = get_selected_server(); if (selection > -1) { - ao_app->add_favorite_server(selection); + Options::getInstance().addFavorite(ao_app->get_server_list().at(selection)); list_favorites(); } } +void Lobby::on_add_server_to_fave_released() +{ + AddServerDialog l_dialog; + l_dialog.exec(); + list_favorites(); +} + void Lobby::on_remove_from_fav_released() { int selection = get_selected_server(); if (selection >= 0) { - ao_app->remove_favorite_server(selection); + Options::getInstance().removeFavorite(selection); list_favorites(); } } @@ -276,7 +291,7 @@ void Lobby::on_favorite_list_context_menu_requested(const QPoint &point) auto *menu = new QMenu(this); menu->addAction(tr("Remove"), ao_app, [this, server_index]() { - ao_app->remove_favorite_server(server_index); + Options::getInstance().removeFavorite(server_index); list_favorites(); }); menu->popup(ui_favorites_tree->mapToGlobal(point)); @@ -284,33 +299,33 @@ void Lobby::on_favorite_list_context_menu_requested(const QPoint &point) void Lobby::on_favorite_tree_clicked(QTreeWidgetItem *p_item, int column) { - column = 0; - server_type f_server; - int n_server = p_item->text(column).toInt(); + column = 0; + server_type f_server; + int n_server = p_item->text(column).toInt(); - if (n_server == last_index) { - return; - } - last_index = n_server; + if (n_server == last_index) { + return; + } + last_index = n_server; - if (n_server < 0) return; + if (n_server < 0) return; - QVector f_server_list = ao_app->get_favorite_list(); + QVector 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); + f_server = f_server_list.at(n_server); - set_server_description(f_server.desc); + set_server_description(f_server.desc); - ui_server_description_text->moveCursor(QTextCursor::Start); - ui_server_description_text->ensureCursorVisible(); - ui_server_player_count_lbl->setText(tr("Connecting...")); + ui_server_description_text->moveCursor(QTextCursor::Start); + ui_server_description_text->ensureCursorVisible(); + ui_server_player_count_lbl->setText(tr("Connecting...")); - ui_connect_button->setEnabled(false); + ui_connect_button->setEnabled(false); - net_manager->connect_to_server(f_server); - } + net_manager->connect_to_server(f_server); +} void Lobby::on_server_search_edited(QString p_text) { @@ -377,7 +392,7 @@ void Lobby::list_favorites() ui_favorites_tree->clear(); int i = 0; - for (const server_type &i_server : qAsConst(ao_app->get_favorite_list())) { + 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); @@ -439,10 +454,11 @@ void Lobby::set_player_count(int players_online, int max_players) void Lobby::set_server_description(const QString &server_description) { ui_server_description_text->clear(); - QString result = server_description.toHtmlEscaped() - .replace("\n", "
") - .replace(QRegularExpression("\\b(https?://\\S+\\.\\S+)\\b"), - "\\1"); + QString result = + server_description.toHtmlEscaped() + .replace("\n", "
") + .replace(QRegularExpression("\\b(https?://\\S+\\.\\S+)\\b"), + "\\1"); ui_server_description_text->insertHtml(result); } diff --git a/src/options.cpp b/src/options.cpp index be429a77d..835403b2c 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -3,10 +3,10 @@ #include #include #include +#include #include #include #include -#include void Options::migrateCallwords() { @@ -19,12 +19,13 @@ void Options::migrateCallwords() if (!l_file.open(QIODevice::ReadOnly)) { qWarning() << "Unable to migrate callwords : File not open."; + return; } QTextStream in(&l_file); - #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - in.setCodec("UTF-8"); - #endif +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + in.setCodec("UTF-8"); +#endif while (!in.atEnd()) { QString line = in.readLine(); @@ -38,10 +39,19 @@ void Options::migrateCallwords() Options::Options() : config(QCoreApplication::applicationDirPath() + "/base/config.ini", - QSettings::IniFormat) + QSettings::IniFormat, nullptr), + favorite(QCoreApplication::applicationDirPath() + + "/base/favorite_servers.ini", + QSettings::IniFormat, nullptr) { +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) config.setIniCodec("UTF-8"); +#endif migrate(); + +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + favorite.setIniCodec("UTF-8"); +#endif } /*! Migrate old configuration keys/values to a relevant format. */ @@ -551,3 +561,88 @@ void Options::setCallwords(QStringList value) } void Options::clearConfig() { config.clear(); } + +QVector Options::favorites() +{ + QVector serverlist; + + auto grouplist = favorite.childGroups(); + { // remove all negative and non-numbers + auto filtered_grouplist = grouplist; + for (const QString &group : qAsConst(grouplist)) { + bool ok = false; + const int l_num = group.toInt(&ok); + 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(); + }); + grouplist = std::move(filtered_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()); + serverlist.append(std::move(f_server)); + favorite.endGroup(); + } + + return serverlist; +} + +void Options::setFavorites(QVector value) +{ + favorite.clear(); + 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); + favorite.setValue("address", fav_server.ip); + favorite.setValue("port", fav_server.port); + favorite.setValue("desc", fav_server.desc); + + if (fav_server.socket_type == TCP) { + favorite.setValue("protocol", "tcp"); + } + else { + favorite.setValue("protocol", "ws"); + } + favorite.endGroup(); + } + favorite.sync(); +} + +void Options::removeFavorite(int index) +{ + QVector l_favorites = favorites(); + l_favorites.remove(index); + setFavorites(l_favorites); +} + +void Options::addFavorite(server_type server) +{ + int index = favorites().size(); + favorite.beginGroup(QString::number(index)); + favorite.setValue("name", server.name); + favorite.setValue("address", server.ip); + favorite.setValue("port", server.port); + favorite.setValue("desc", server.desc); + if (server.socket_type == TCP) { + favorite.setValue("protocol", "tcp"); + } + else { + favorite.setValue("protocol", "ws"); + } + favorite.endGroup(); + favorite.sync(); +} diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index 670c86af4..84af609a5 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -187,6 +187,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet) } } else { + QVector 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; diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 8d48d3f81..daf84cd56 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -102,91 +102,6 @@ bool AOApplication::append_to_file(QString p_text, QString p_file, return false; } -QVector AOApplication::read_favorite_servers() -{ - QVector serverlist; - - QString fav_servers_ini_path(get_base_path() + "favorite_servers.ini"); - if (!QFile::exists(fav_servers_ini_path)) { - qWarning() << "failed to locate favorite_servers.ini, falling back to legacy serverlist.txt"; - serverlist += read_legacy_favorite_servers(); - } - else { - QSettings fav_servers_ini(fav_servers_ini_path, QSettings::IniFormat); - fav_servers_ini.setIniCodec("UTF-8"); - - auto grouplist = fav_servers_ini.childGroups(); - { // remove all negative and non-numbers - auto filtered_grouplist = grouplist; - for (const QString &group : qAsConst(grouplist)) { - bool ok = false; - const int l_num = group.toInt(&ok); - 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(); - }); - grouplist = std::move(filtered_grouplist); - } - - for(const QString &group: qAsConst(grouplist)) { - server_type f_server; - fav_servers_ini.beginGroup(group); - f_server.ip = fav_servers_ini.value("address", "127.0.0.1").toString(); - f_server.port = fav_servers_ini.value("port", 27016).toInt(); - f_server.name = fav_servers_ini.value("name", "Missing Name").toString(); - f_server.desc = fav_servers_ini.value("desc", "No description").toString(); - f_server.socket_type = to_connection_type.value(fav_servers_ini.value("protocol", "tcp").toString()); - serverlist.append(std::move(f_server)); - fav_servers_ini.endGroup(); - } - } - - return serverlist; -} - -QVector AOApplication::read_legacy_favorite_servers() -{ - QVector serverlist; - - QFile serverlist_txt(get_base_path() + "serverlist.txt"); - if (!serverlist_txt.exists()) { - qWarning() << "serverlist.txt does not exist"; - } else if (!serverlist_txt.open(QIODevice::ReadOnly)) { - qWarning() << "failed to open serverlist.txt"; - } else { - QTextStream stream(&serverlist_txt); - stream.setCodec("UTF-8"); - - while (!stream.atEnd()) - { - QStringList contents = stream.readLine().split(":"); - - int item_count = contents.size(); - if (item_count < 3 || item_count > 4) { - continue; - } - - server_type server; - server.ip = contents.at(0); - server.port = contents.at(1).toInt(); - server.name = contents.at(2); - if (item_count == 4) { - server.socket_type = connection_type(contents.at(3).toInt()); - } else { - server.socket_type = TCP; - } - serverlist.append(std::move(server)); - } - serverlist_txt.close(); - } - - return serverlist; -} - QMultiMap AOApplication::load_demo_logs_list() const { QString l_log_path = applicationDirPath() + "/logs/"; diff --git a/src/widgets/add_server_dialog.cpp b/src/widgets/add_server_dialog.cpp new file mode 100644 index 000000000..46329d533 --- /dev/null +++ b/src/widgets/add_server_dialog.cpp @@ -0,0 +1,92 @@ +#include "widgets/add_server_dialog.h" +#include "datatypes.h" +#include "options.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FROM_UI(type, name) \ + ; \ + ui_##name = findChild(#name); + +AddServerDialog::AddServerDialog() +{ + QUiLoader l_loader(this); + QFile l_uiFile(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); + + 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, + &AddServerDialog::savePressed); + connect(ui_server_dialog_button, &QDialogButtonBox::rejected, this, + &AddServerDialog::discardPressed); + + FROM_UI(QLineEdit, server_legacy_edit); + FROM_UI(QPushButton, server_legacy_load_button); + connect(ui_server_legacy_load_button, &QPushButton::released, this, + &AddServerDialog::parseLegacyServerEntry); +} + +AddServerDialog::~AddServerDialog() {} + +void AddServerDialog::savePressed() +{ + 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().addFavorite(server); + close(); +} + +void AddServerDialog::discardPressed() { close(); } + +void AddServerDialog::parseLegacyServerEntry() +{ + QStringList l_legacy_entry = ui_server_legacy_edit->text().split(":"); + server_type l_server_entry; + if (l_legacy_entry.isEmpty()) { + qDebug() << "Legacy entry empty."; + return; + } + + int l_item_count = l_legacy_entry.size(); + + 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") { + ui_server_protocol_box->setCurrentIndex(1); + } + else { + ui_server_protocol_box->setCurrentIndex(0); + } + } + } +} From ba070be94ebebfd34e01b4065b6709c0f1532dd6 Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Tue, 24 Jan 2023 20:29:06 +0100 Subject: [PATCH 10/61] Add Direction Connection Widget and function --- include/lobby.h | 2 + include/widgets/add_server_dialog.h | 2 +- include/widgets/direct_connect_dialog.h | 40 +++++++++ resource/ui/direct_connect_dialog.ui | 110 ++++++++++++++++++++++++ resource/ui/lobby.ui | 103 +++++++++------------- resources.qrc | 1 + src/lobby.cpp | 11 +++ src/widgets/add_server_dialog.cpp | 4 +- src/widgets/direct_connect_dialog.cpp | 61 +++++++++++++ 9 files changed, 268 insertions(+), 66 deletions(-) create mode 100644 include/widgets/direct_connect_dialog.h create mode 100644 resource/ui/direct_connect_dialog.ui create mode 100644 src/widgets/direct_connect_dialog.cpp diff --git a/include/lobby.h b/include/lobby.h index 623e8235d..1b159c960 100644 --- a/include/lobby.h +++ b/include/lobby.h @@ -69,6 +69,7 @@ class Lobby : public QMainWindow { QPushButton *ui_add_to_favorite_button; QPushButton *ui_add_server_button; QPushButton *ui_remove_from_favorites_button; + QPushButton *ui_direct_connect_button; QPushButton *ui_refresh_button; // Serverinfo / MOTD Horizontal Row @@ -81,6 +82,7 @@ class Lobby : public QMainWindow { private 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_remove_from_fav_released(); diff --git a/include/widgets/add_server_dialog.h b/include/widgets/add_server_dialog.h index 9111a4ef5..60913e7aa 100644 --- a/include/widgets/add_server_dialog.h +++ b/include/widgets/add_server_dialog.h @@ -16,7 +16,7 @@ class AddServerDialog : public QDialog { Q_OBJECT public : AddServerDialog(); - ~AddServerDialog(); + ~AddServerDialog() = default; private: QWidget* ui_widget; diff --git a/include/widgets/direct_connect_dialog.h b/include/widgets/direct_connect_dialog.h new file mode 100644 index 000000000..8d66024f5 --- /dev/null +++ b/include/widgets/direct_connect_dialog.h @@ -0,0 +1,40 @@ +#ifndef DIRECT_CONNECT_DIALOG_H +#define DIRECT_CONNECT_DIALOG_H + +#include + +class QLabel; +class QSpinBox; +class QLineEdit; +class QPushButton; +class QComboBox; +class NetworkManager; + +class DirectConnectDialog : public QDialog { + Q_OBJECT +public: + DirectConnectDialog(NetworkManager* p_net_manager); + ~DirectConnectDialog() = default; + +private slots: + void onConnectPressed(); + void onServerConnected(); + +private: + NetworkManager* net_manager; + + QComboBox* ui_direct_protocol_box; + QLineEdit* ui_direct_hostname_edit; + QSpinBox* ui_direct_port_box; + + QPushButton* ui_direct_connect_button; + QPushButton* ui_direct_cancel_button; + + QWidget* ui_widget; + + const int TCP_INDEX = 0; + const QString DEFAULT_UI = ":/resource/ui/direct_connect_dialog.ui";; + +}; + +#endif // DIRECT_CONNECT_DIALOG_H diff --git a/resource/ui/direct_connect_dialog.ui b/resource/ui/direct_connect_dialog.ui new file mode 100644 index 000000000..801c77c27 --- /dev/null +++ b/resource/ui/direct_connect_dialog.ui @@ -0,0 +1,110 @@ + + + direct_connect_dialog + + + + 0 + 0 + 401 + 77 + + + + Form + + + + + + + + + TCP + + + + + WS + + + + + + + + :// + + + + + + + Hostname + + + + + + + : + + + + + + + + 50 + 0 + + + + 1 + + + 65535 + + + 80 + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Connect + + + + + + + Cancel + + + + + + + + + + diff --git a/resource/ui/lobby.ui b/resource/ui/lobby.ui index ec3f6f95d..cf2628d7d 100644 --- a/resource/ui/lobby.ui +++ b/resource/ui/lobby.ui @@ -147,21 +147,6 @@ - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - @@ -341,53 +326,47 @@ - - - - 2 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Refresh - - - - - - - Add To Favorites - - - - - - - Add - - - - - - - Remove - - - - - + + + + + Direct Connect + + + + + + + Add To Favorites + + + + + + + Add + + + + + + + Remove + + + + + + + + + + + Refresh + + + + diff --git a/resources.qrc b/resources.qrc index 6a05e2c67..1a3a57ef1 100644 --- a/resources.qrc +++ b/resources.qrc @@ -11,6 +11,7 @@ resource/translations/ao_ru.qm resource/ui/options_dialog.ui resource/ui/add_server_dialog.ui + resource/ui/direct_connect_dialog.ui resource/ui/lobby.ui diff --git a/src/lobby.cpp b/src/lobby.cpp index f54acbd50..823be7032 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -4,6 +4,7 @@ #include "demoserver.h" #include "networkmanager.h" #include "widgets/add_server_dialog.h" +#include "widgets/direct_connect_dialog.h" #include #include @@ -79,6 +80,10 @@ Lobby::Lobby(AOApplication *p_ao_app, NetworkManager *p_net_manager) 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); + FROM_UI(QPushButton, add_to_favorite_button) connect(ui_add_to_favorite_button, &QPushButton::released, this, &Lobby::on_add_to_fav_released); @@ -169,6 +174,12 @@ void Lobby::on_refresh_released() list_favorites(); } +void Lobby::on_direct_connect_released() +{ + DirectConnectDialog connect_dialog(net_manager); + connect_dialog.exec(); +} + void Lobby::on_add_to_fav_released() { int selection = get_selected_server(); diff --git a/src/widgets/add_server_dialog.cpp b/src/widgets/add_server_dialog.cpp index 46329d533..e6fcb6c76 100644 --- a/src/widgets/add_server_dialog.cpp +++ b/src/widgets/add_server_dialog.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include @@ -48,8 +48,6 @@ AddServerDialog::AddServerDialog() &AddServerDialog::parseLegacyServerEntry); } -AddServerDialog::~AddServerDialog() {} - void AddServerDialog::savePressed() { server_type server; diff --git a/src/widgets/direct_connect_dialog.cpp b/src/widgets/direct_connect_dialog.cpp new file mode 100644 index 000000000..3e0c67d26 --- /dev/null +++ b/src/widgets/direct_connect_dialog.cpp @@ -0,0 +1,61 @@ +#include "widgets/direct_connect_dialog.h" + +#include "networkmanager.h" + +#include +#include +#include +#include +#include + +#define FROM_UI(type, name) \ + ; \ + ui_##name = findChild(#name); + +DirectConnectDialog::DirectConnectDialog(NetworkManager *p_net_manager) : + net_manager(p_net_manager) +{ + QUiLoader l_loader(this); + QFile l_uiFile(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); + + auto l_layout = new QVBoxLayout(this); + l_layout->addWidget(ui_widget); + + FROM_UI(QComboBox, direct_protocol_box) + FROM_UI(QLineEdit, direct_hostname_edit) + FROM_UI(QSpinBox, direct_port_box) + + 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); +} + +void DirectConnectDialog::onConnectPressed() +{ + server_type l_server; + l_server.socket_type = ui_direct_protocol_box->currentIndex() == TCP_INDEX ? TCP : WEBSOCKETS; + l_server.ip = ui_direct_hostname_edit->text(); + l_server.port = ui_direct_port_box->value(); + l_server.name = "Direct Connection"; + + net_manager->connect_to_server(l_server); + ui_direct_connect_button->setEnabled(false); +} + +void DirectConnectDialog::onServerConnected() +{ + net_manager->join_to_server(); + close(); +} From b9613449e2e69acd13fe7d98b45d1cd77c3272fc Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Tue, 24 Jan 2023 23:28:07 +0100 Subject: [PATCH 11/61] Visual Fluff, don't show direct connection on demo screen --- include/widgets/direct_connect_dialog.h | 6 ++++++ resource/ui/direct_connect_dialog.ui | 7 +++++++ src/lobby.cpp | 3 +++ src/widgets/direct_connect_dialog.cpp | 19 +++++++++++++++++++ 4 files changed, 35 insertions(+) diff --git a/include/widgets/direct_connect_dialog.h b/include/widgets/direct_connect_dialog.h index 8d66024f5..1a712e426 100644 --- a/include/widgets/direct_connect_dialog.h +++ b/include/widgets/direct_connect_dialog.h @@ -2,12 +2,14 @@ #define DIRECT_CONNECT_DIALOG_H #include +#include class QLabel; class QSpinBox; class QLineEdit; class QPushButton; class QComboBox; +class QLabel; class NetworkManager; class DirectConnectDialog : public QDialog { @@ -19,6 +21,7 @@ class DirectConnectDialog : public QDialog { private slots: void onConnectPressed(); void onServerConnected(); + void onConnectTimeout(); private: NetworkManager* net_manager; @@ -27,12 +30,15 @@ private slots: QLineEdit* ui_direct_hostname_edit; QSpinBox* ui_direct_port_box; + 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 int CONNECT_TIMEOUT = 5 * 1000; const QString DEFAULT_UI = ":/resource/ui/direct_connect_dialog.ui";; }; diff --git a/resource/ui/direct_connect_dialog.ui b/resource/ui/direct_connect_dialog.ui index 801c77c27..09deb32e5 100644 --- a/resource/ui/direct_connect_dialog.ui +++ b/resource/ui/direct_connect_dialog.ui @@ -74,6 +74,13 @@ + + + + Not Connected + + + diff --git a/src/lobby.cpp b/src/lobby.cpp index 823be7032..562038fda 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -122,18 +122,21 @@ void Lobby::on_tab_changed(int index) ui_add_to_favorite_button->setVisible(true); ui_remove_from_favorites_button->setVisible(false); ui_add_server_button->setVisible(false); + ui_direct_connect_button->setVisible(true); reset_selection(); break; case FAVORITES: ui_add_to_favorite_button->setVisible(false); ui_remove_from_favorites_button->setVisible(true); ui_add_server_button->setVisible(true); + ui_direct_connect_button->setVisible(true); reset_selection(); break; case DEMOS: ui_add_to_favorite_button->setVisible(false); ui_add_server_button->setVisible(false); ui_remove_from_favorites_button->setVisible(false); + ui_direct_connect_button->setVisible(false); reset_selection(); break; default: diff --git a/src/widgets/direct_connect_dialog.cpp b/src/widgets/direct_connect_dialog.cpp index 3e0c67d26..9b3a99b06 100644 --- a/src/widgets/direct_connect_dialog.cpp +++ b/src/widgets/direct_connect_dialog.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #define FROM_UI(type, name) \ ; \ @@ -31,6 +32,8 @@ DirectConnectDialog::DirectConnectDialog(NetworkManager *p_net_manager) : FROM_UI(QLineEdit, direct_hostname_edit) FROM_UI(QSpinBox, direct_port_box) + FROM_UI(QLabel, direct_connection_status_lbl) + FROM_UI(QPushButton, direct_connect_button); connect(ui_direct_connect_button, &QPushButton::pressed, this, &DirectConnectDialog::onConnectPressed); @@ -40,6 +43,10 @@ DirectConnectDialog::DirectConnectDialog(NetworkManager *p_net_manager) : connect(net_manager, &NetworkManager::server_connected, this, &DirectConnectDialog::onServerConnected); + + connect(&connect_timeout, &QTimer::timeout, this, + &DirectConnectDialog::onConnectTimeout); + connect_timeout.setSingleShot(true); } void DirectConnectDialog::onConnectPressed() @@ -52,10 +59,22 @@ void DirectConnectDialog::onConnectPressed() net_manager->connect_to_server(l_server); ui_direct_connect_button->setEnabled(false); + ui_direct_connection_status_lbl->setText("Connecting..."); + ui_direct_connection_status_lbl->setStyleSheet("color : rgb(0,64,156)"); + connect_timeout.start(CONNECT_TIMEOUT); } void DirectConnectDialog::onServerConnected() { net_manager->join_to_server(); + ui_direct_connection_status_lbl->setText("Connected!"); + ui_direct_connection_status_lbl->setStyleSheet("color: rgb(0,128,0)"); close(); } + +void DirectConnectDialog::onConnectTimeout() +{ + ui_direct_connect_button->setEnabled(true); + ui_direct_connection_status_lbl->setText("Connection Timeout!"); + ui_direct_connection_status_lbl->setStyleSheet("color: rgb(255,0,0)"); +} From fc0156a4ee231e9754c9fbf505d4c95f4e3bc46b Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Wed, 25 Jan 2023 03:07:22 +0100 Subject: [PATCH 12/61] Implement ui-file reload and RCC mounting. --- include/lobby.h | 7 +- include/options.h | 9 ++ include/widgets/add_server_dialog.h | 2 +- include/widgets/direct_connect_dialog.h | 2 +- src/aoapplication.cpp | 2 - src/lobby.cpp | 159 ++++++++++++++---------- src/main.cpp | 2 + src/options.cpp | 60 ++++++--- src/packet_distribution.cpp | 4 +- src/widgets/add_server_dialog.cpp | 2 +- src/widgets/aooptionsdialog.cpp | 13 +- src/widgets/direct_connect_dialog.cpp | 3 +- 12 files changed, 174 insertions(+), 91 deletions(-) diff --git a/include/lobby.h b/include/lobby.h index 1b159c960..366fd024e 100644 --- a/include/lobby.h +++ b/include/lobby.h @@ -30,13 +30,14 @@ class Lobby : public QMainWindow { int get_selected_server(); signals: - void settings_requested(); private: AOApplication *ao_app; NetworkManager *net_manager; + const QString DEFAULT_UI = "lobby.ui"; + void list_favorites(); void list_demos(); void get_motd(); @@ -79,6 +80,8 @@ class Lobby : public QMainWindow { QTextBrowser *ui_server_description_text; QPushButton *ui_connect_button; + void loadUI(); + private slots: void on_tab_changed(int index); void on_refresh_released(); @@ -93,6 +96,8 @@ private slots: 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(); }; #endif // LOBBY_H diff --git a/include/options.h b/include/options.h index a77937e71..5e530203d 100644 --- a/include/options.h +++ b/include/options.h @@ -26,6 +26,8 @@ class Options { */ Options(); + QString m_server_subtheme; + public: Options(Options const &) = delete; void operator=(Options const &) = delete; @@ -228,6 +230,10 @@ class Options { QString subTheme() const; void setSubTheme(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); @@ -274,6 +280,9 @@ class Options { // Interactions with favorite servers void removeFavorite(int index); void addFavorite(server_type server); + + // Theming Nonesense! + QString getUIAsset(QString f_asset_name); }; #endif // OPTIONS_H diff --git a/include/widgets/add_server_dialog.h b/include/widgets/add_server_dialog.h index 60913e7aa..194ccecdf 100644 --- a/include/widgets/add_server_dialog.h +++ b/include/widgets/add_server_dialog.h @@ -37,7 +37,7 @@ public : const int TCP_INDEX = 0; - const QString DEFAULT_UI = ":/resource/ui/add_server_dialog.ui"; + const QString DEFAULT_UI = "add_server_dialog.ui"; private slots: void savePressed(); diff --git a/include/widgets/direct_connect_dialog.h b/include/widgets/direct_connect_dialog.h index 1a712e426..cd973c178 100644 --- a/include/widgets/direct_connect_dialog.h +++ b/include/widgets/direct_connect_dialog.h @@ -39,7 +39,7 @@ private slots: const int TCP_INDEX = 0; const int CONNECT_TIMEOUT = 5 * 1000; - const QString DEFAULT_UI = ":/resource/ui/direct_connect_dialog.ui";; + const QString DEFAULT_UI = "direct_connect_dialog.ui";; }; diff --git a/src/aoapplication.cpp b/src/aoapplication.cpp index 622546d72..8b3bcec54 100644 --- a/src/aoapplication.cpp +++ b/src/aoapplication.cpp @@ -60,8 +60,6 @@ void AOApplication::construct_lobby() if (demo_server) demo_server->deleteLater(); demo_server = new DemoServer(this); - - connect(w_lobby, &Lobby::settings_requested, this, &AOApplication::call_settings_menu); w_lobby->show(); } diff --git a/src/lobby.cpp b/src/lobby.cpp index 562038fda..db28d634c 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -15,19 +15,88 @@ ; \ ui_##name = findChild(#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() +} + +void Lobby::on_tab_changed(int index) +{ + switch (index) { // Implicit conversion cause FUCK ALL OF YOU. + case SERVER: + ui_add_to_favorite_button->setVisible(true); + ui_remove_from_favorites_button->setVisible(false); + ui_add_server_button->setVisible(false); + ui_direct_connect_button->setVisible(true); + reset_selection(); + break; + case FAVORITES: + ui_add_to_favorite_button->setVisible(false); + ui_remove_from_favorites_button->setVisible(true); + ui_add_server_button->setVisible(true); + ui_direct_connect_button->setVisible(true); + reset_selection(); + break; + case DEMOS: + ui_add_to_favorite_button->setVisible(false); + ui_add_server_button->setVisible(false); + ui_remove_from_favorites_button->setVisible(false); + ui_direct_connect_button->setVisible(false); + reset_selection(); + break; + default: + break; + } +} + +int Lobby::get_selected_server() +{ + switch (ui_connections_tabview->currentIndex()) { + case SERVER: + if (auto item = ui_serverlist_tree->currentItem()) { + return item->text(0).toInt(); + } + case FAVORITES: + if (auto item = ui_favorites_tree->currentItem()) { + return item->text(0).toInt(); + } + default: + break; + } + return -1; +} + +void Lobby::reset_selection() +{ + last_index = -1; + ui_server_player_count_lbl->setText(tr("Offline")); + ui_server_description_text->clear(); + + ui_connect_button->setEnabled(false); +} + +void Lobby::loadUI() +{ 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(":/resource/ui/lobby.ui"); + QFile l_uiFile(Options::getInstance().getUIAsset(DEFAULT_UI)); if (!l_uiFile.open(QFile::ReadOnly)) { qCritical() << "Unable to open file " << l_uiFile.fileName(); return; @@ -41,7 +110,7 @@ Lobby::Lobby(AOApplication *p_ao_app, NetworkManager *p_net_manager) FROM_UI(QPushButton, settings_button); connect(ui_settings_button, &QPushButton::clicked, this, - &Lobby::settings_requested); + &Lobby::onSettingsRequested); FROM_UI(QPushButton, about_button); connect(ui_about_button, &QPushButton::clicked, this, @@ -81,8 +150,8 @@ Lobby::Lobby(AOApplication *p_ao_app, NetworkManager *p_net_manager) &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, @@ -107,67 +176,6 @@ Lobby::Lobby(AOApplication *p_ao_app, NetworkManager *p_net_manager) &QPushButton::setEnabled); FROM_UI(QTextBrowser, motd_text); - - list_servers(); - list_favorites(); - list_demos(); - get_motd(); - check_for_updates(); -} - -void Lobby::on_tab_changed(int index) -{ - switch (index) { // Implicit conversion cause FUCK ALL OF YOU. - case SERVER: - ui_add_to_favorite_button->setVisible(true); - ui_remove_from_favorites_button->setVisible(false); - ui_add_server_button->setVisible(false); - ui_direct_connect_button->setVisible(true); - reset_selection(); - break; - case FAVORITES: - ui_add_to_favorite_button->setVisible(false); - ui_remove_from_favorites_button->setVisible(true); - ui_add_server_button->setVisible(true); - ui_direct_connect_button->setVisible(true); - reset_selection(); - break; - case DEMOS: - ui_add_to_favorite_button->setVisible(false); - ui_add_server_button->setVisible(false); - ui_remove_from_favorites_button->setVisible(false); - ui_direct_connect_button->setVisible(false); - reset_selection(); - break; - default: - break; - } -} - -int Lobby::get_selected_server() -{ - switch (ui_connections_tabview->currentIndex()) { - case SERVER: - if (auto item = ui_serverlist_tree->currentItem()) { - return item->text(0).toInt(); - } - case FAVORITES: - if (auto item = ui_favorites_tree->currentItem()) { - return item->text(0).toInt(); - } - default: - break; - } - return -1; -} - -void Lobby::reset_selection() -{ - last_index = -1; - ui_server_player_count_lbl->setText(tr("Offline")); - ui_server_description_text->clear(); - - ui_connect_button->setEnabled(false); } void Lobby::on_refresh_released() @@ -179,8 +187,8 @@ void Lobby::on_refresh_released() void Lobby::on_direct_connect_released() { - DirectConnectDialog connect_dialog(net_manager); - connect_dialog.exec(); + DirectConnectDialog connect_dialog(net_manager); + connect_dialog.exec(); } void Lobby::on_add_to_fav_released() @@ -382,6 +390,23 @@ void Lobby::on_demo_clicked(QTreeWidgetItem *item, int column) net_manager->connect_to_server(demo_server); } +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() +} + +void Lobby::onSettingsRequested() +{ + AOOptionsDialog options(nullptr, ao_app); + connect(&options, &AOOptionsDialog::reloadThemeRequest, this, + &Lobby::onReloadThemeRequested); + options.exec(); +} + void Lobby::list_servers() { ui_serverlist_tree->setSortingEnabled(false); diff --git a/src/main.cpp b/src/main.cpp index 9ec52f27c..9adfbda11 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -9,6 +9,7 @@ #include #include #include +#include int main(int argc, char *argv[]) { @@ -17,6 +18,7 @@ int main(int argc, char *argv[]) AOApplication main_app(argc, argv); AOApplication::addLibraryPath(AOApplication::applicationDirPath() + "/lib"); + QResource::registerResource(main_app.get_asset("themes/" + Options::getInstance().theme() + ".rcc")); QFontDatabase fontDatabase; QDirIterator it(main_app.get_base_path() + "fonts", diff --git a/src/options.cpp b/src/options.cpp index 835403b2c..43bfc4311 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -466,6 +466,10 @@ QString Options::subTheme() const void Options::setSubTheme(QString value) { config.setValue("subtheme", value); } +QString Options::serverSubTheme() const { return m_server_subtheme; } + +void Options::setServerSubTheme(QString value) { m_server_subtheme = value; } + bool Options::animatedThemeEnabled() const { return config.value("animated_theme", true).toBool(); @@ -624,25 +628,51 @@ void Options::setFavorites(QVector value) void Options::removeFavorite(int index) { - QVector l_favorites = favorites(); - l_favorites.remove(index); - setFavorites(l_favorites); + QVector l_favorites = favorites(); + l_favorites.remove(index); + setFavorites(l_favorites); } void Options::addFavorite(server_type server) { - int index = favorites().size(); - favorite.beginGroup(QString::number(index)); - favorite.setValue("name", server.name); - favorite.setValue("address", server.ip); - favorite.setValue("port", server.port); - favorite.setValue("desc", server.desc); - if (server.socket_type == TCP) { - favorite.setValue("protocol", "tcp"); + int index = favorites().size(); + favorite.beginGroup(QString::number(index)); + favorite.setValue("name", server.name); + favorite.setValue("address", server.ip); + favorite.setValue("port", server.port); + favorite.setValue("desc", server.desc); + if (server.socket_type == TCP) { + favorite.setValue("protocol", "tcp"); + } + else { + favorite.setValue("protocol", "ws"); + } + favorite.endGroup(); + favorite.sync(); +} + +QString Options::getUIAsset(QString f_asset_name) +{ + QStringList l_paths{":/base/themes/" + Options::getInstance().theme() + "/" + + f_asset_name}; + + if (Options::getInstance().subTheme() == "server") { + if (!Options::getInstance().serverSubTheme().isEmpty()) { + l_paths.prepend(":/base/themes/" + Options::getInstance().theme() + "/" + + Options::getInstance().subTheme() + "/" + f_asset_name); } - else { - favorite.setValue("protocol", "ws"); + } + else { + l_paths.prepend(":/base/themes/" + Options::getInstance().theme() + "/" + + Options::getInstance().subTheme() + "/" + f_asset_name); + } + + for (const QString &l_path : qAsConst(l_paths)) { + if (QFile::exists(l_path)) { + return l_path; } - favorite.endGroup(); - favorite.sync(); + } + qWarning() << "Unable to locate ui-asset" << f_asset_name << "in theme" + << theme() << "Defaulting to embeeded asset."; + return QString(":/resource/ui/" + f_asset_name); } diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index 84af609a5..474686ffe 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -563,8 +563,10 @@ void AOApplication::server_packet_received(AOPacket *p_packet) 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") { diff --git a/src/widgets/add_server_dialog.cpp b/src/widgets/add_server_dialog.cpp index e6fcb6c76..6321927d8 100644 --- a/src/widgets/add_server_dialog.cpp +++ b/src/widgets/add_server_dialog.cpp @@ -20,7 +20,7 @@ AddServerDialog::AddServerDialog() { QUiLoader l_loader(this); - QFile l_uiFile(DEFAULT_UI); + QFile l_uiFile(Options::getInstance().getUIAsset(DEFAULT_UI)); if (!l_uiFile.open(QFile::ReadOnly)) { qCritical() << "Unable to open file " << l_uiFile.fileName(); diff --git a/src/widgets/aooptionsdialog.cpp b/src/widgets/aooptionsdialog.cpp index dfa911362..6bd82a2cc 100644 --- a/src/widgets/aooptionsdialog.cpp +++ b/src/widgets/aooptionsdialog.cpp @@ -1,11 +1,12 @@ #include "widgets/aooptionsdialog.h" +#include "QDesktopServices" #include "aoapplication.h" #include "bass.h" #include "file_functions.h" -#include "QDesktopServices" #include "networkmanager.h" #include "options.h" +#include #include #define FROM_UI(type, name) \ @@ -592,6 +593,16 @@ void AOOptionsDialog::themeChanged(int i) actualname.toLower() != "server" && actualname.toLower() != "default" && actualname.toLower() != "effects" && actualname.toLower() != "misc") ui_subtheme_combobox->addItem(actualname); + + QString l_resource = ao_app->get_asset( + "themes/" + ui_theme_combobox->currentText() + ".rcc"); + if (l_resource.isEmpty()) { + QResource::unregisterResource(ao_app->get_asset( + "themes/" + Options::getInstance().theme() + ".rcc")); + qDebug() << "Unable to locate ressource file" << l_resource; + return; + } + QResource::registerResource(l_resource); } } diff --git a/src/widgets/direct_connect_dialog.cpp b/src/widgets/direct_connect_dialog.cpp index 9b3a99b06..5fb28a038 100644 --- a/src/widgets/direct_connect_dialog.cpp +++ b/src/widgets/direct_connect_dialog.cpp @@ -1,6 +1,7 @@ #include "widgets/direct_connect_dialog.h" #include "networkmanager.h" +#include "options.h" #include #include @@ -17,7 +18,7 @@ DirectConnectDialog::DirectConnectDialog(NetworkManager *p_net_manager) : net_manager(p_net_manager) { QUiLoader l_loader(this); - QFile l_uiFile(DEFAULT_UI); + QFile l_uiFile(Options::getInstance().getUIAsset(DEFAULT_UI)); if (!l_uiFile.open(QFile::ReadOnly)) { qCritical() << "Unable to open file " << l_uiFile.fileName(); From 6eeceb40baa79972f3f34e8b5dafe0ddfbd9b739 Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Sat, 28 Jan 2023 23:16:13 +0100 Subject: [PATCH 13/61] Add edit menu to favorites --- .clang-format | 4 +- include/interfaces/server_dialog.h | 21 +++++ include/lobby.h | 3 +- include/options.h | 1 + include/widgets/add_server_dialog.h | 52 +++++------ include/widgets/edit_server_dialog.h | 46 ++++++++++ ...er_dialog.ui => favorite_server_dialog.ui} | 48 ++++------ resource/ui/lobby.ui | 27 ++++-- resources.qrc | 2 +- src/lobby.cpp | 57 ++++++------ src/options.cpp | 23 ++++- src/widgets/add_server_dialog.cpp | 14 ++- src/widgets/edit_server_dialog.cpp | 87 +++++++++++++++++++ 13 files changed, 281 insertions(+), 104 deletions(-) create mode 100644 include/interfaces/server_dialog.h create mode 100644 include/widgets/edit_server_dialog.h rename resource/ui/{add_server_dialog.ui => favorite_server_dialog.ui} (89%) create mode 100644 src/widgets/edit_server_dialog.cpp diff --git a/.clang-format b/.clang-format index 02dc5a171..ff61b452b 100644 --- a/.clang-format +++ b/.clang-format @@ -1,3 +1,5 @@ BasedOnStyle: LLVM BreakBeforeBraces: Stroustrup -AllowShortIfStatementsOnASingleLine: true \ No newline at end of file +AllowShortIfStatementsOnASingleLine: true +NamespaceIndentation: All + diff --git a/include/interfaces/server_dialog.h b/include/interfaces/server_dialog.h new file mode 100644 index 000000000..63817d092 --- /dev/null +++ b/include/interfaces/server_dialog.h @@ -0,0 +1,21 @@ +#include +#pragma once + +#ifndef AO_UI_FAVORITESERVERDIALOG +#define AO_UI_FAVORITESRRVERDIALOG +namespace AttorneyOnline { + namespace UI { + class FavoriteServerDialog : public QDialog { + public: + FavoriteServerDialog() = default; + ~FavoriteServerDialog() = default; + + const QString DEFAULT_UI = "favorite_server_dialog.ui"; + const int TCP_INDEX = 0; + private slots: + virtual void onSavePressed() = 0; + virtual void onCancelPressed() = 0; + }; + } // namespace UI +} // namespace AttorneyOnline +#endif // AO_UI_FAVORITESERVERDIALOG diff --git a/include/lobby.h b/include/lobby.h index 366fd024e..1868c8f2d 100644 --- a/include/lobby.h +++ b/include/lobby.h @@ -70,6 +70,7 @@ class Lobby : public QMainWindow { 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; @@ -88,11 +89,11 @@ private slots: 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_list_context_menu_requested(const QPoint &point); 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); diff --git a/include/options.h b/include/options.h index 5e530203d..792f84668 100644 --- a/include/options.h +++ b/include/options.h @@ -280,6 +280,7 @@ class Options { // 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); diff --git a/include/widgets/add_server_dialog.h b/include/widgets/add_server_dialog.h index 194ccecdf..d7daff4e7 100644 --- a/include/widgets/add_server_dialog.h +++ b/include/widgets/add_server_dialog.h @@ -1,48 +1,44 @@ +#pragma once + #ifndef ADD_SERVER_DIALOG_H #define ADD_SERVER_DIALOG_H -#include -#include +#include "interfaces/server_dialog.h" + class QPushButton; class QDialogButton; +class QLabel; class QLineEdit; class QComboBox; class QSpinBox; class QPlainTextEdit; class QDialogButtonBox; -class QSettings; -class AddServerDialog : public QDialog { - Q_OBJECT -public : - AddServerDialog(); - ~AddServerDialog() = default; +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 - QLineEdit* ui_server_legacy_edit; - QPushButton* ui_server_legacy_load_button; - - - QSettings* m_favorite_ini; + QWidget *ui_widget; - const int TCP_INDEX = 0; + 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; - const QString DEFAULT_UI = "add_server_dialog.ui"; + // Legacy Server UI + QLabel *ui_server_legacy_lbl; + QLineEdit *ui_server_legacy_edit; + QPushButton *ui_server_legacy_load_button; private slots: - void savePressed(); - void discardPressed(); - void parseLegacyServerEntry(); + void onSavePressed() override; + void onCancelPressed() override; + void parseLegacyServerEntry(); }; #endif // ADD_SERVER_DIALOG_H diff --git a/include/widgets/edit_server_dialog.h b/include/widgets/edit_server_dialog.h new file mode 100644 index 000000000..3c4595ec2 --- /dev/null +++ b/include/widgets/edit_server_dialog.h @@ -0,0 +1,46 @@ +#pragma once + +#ifndef EDIT_SERVER_DIALOG_H +#define EDIT_SERVER_DIALOG_H + +#include "interfaces/server_dialog.h" + +class QPushButton; +class QDialogButton; +class QLabel; +class QLineEdit; +class QComboBox; +class QSpinBox; +class QPlainTextEdit; +class QDialogButtonBox; + +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 slots: + void onSavePressed() override; + void onCancelPressed() override; +}; + +#endif // EDIT_SERVER_DIALOG_H diff --git a/resource/ui/add_server_dialog.ui b/resource/ui/favorite_server_dialog.ui similarity index 89% rename from resource/ui/add_server_dialog.ui rename to resource/ui/favorite_server_dialog.ui index fc0459aa8..0ce467503 100644 --- a/resource/ui/add_server_dialog.ui +++ b/resource/ui/favorite_server_dialog.ui @@ -14,7 +14,7 @@ Form - + @@ -35,17 +35,7 @@ - - - - QFrame::Plain - - - Qt::Horizontal - - - - + @@ -88,13 +78,6 @@ - - - - Description: - - - @@ -109,6 +92,13 @@ + + + + Description: + + + @@ -121,27 +111,23 @@ - - - - Add your server to your favorites : + + + + QFrame::Plain + + + Qt::Horizontal - + QDialogButtonBox::Close|QDialogButtonBox::Save - - - - Convert legacy favorite entries: - - - diff --git a/resource/ui/lobby.ui b/resource/ui/lobby.ui index cf2628d7d..b15719f55 100644 --- a/resource/ui/lobby.ui +++ b/resource/ui/lobby.ui @@ -328,30 +328,41 @@ - + - Direct Connect + Add Server - + - Add To Favorites + Remove Server - + + + Edit Server + + + + + + + + + - Add + Direct Connect - + - Remove + Add To Favorites diff --git a/resources.qrc b/resources.qrc index 1a3a57ef1..a1386ce6a 100644 --- a/resources.qrc +++ b/resources.qrc @@ -10,7 +10,7 @@ resource/translations/ao_pt.qm resource/translations/ao_ru.qm resource/ui/options_dialog.ui - resource/ui/add_server_dialog.ui + resource/ui/favorite_server_dialog.ui resource/ui/direct_connect_dialog.ui resource/ui/lobby.ui diff --git a/src/lobby.cpp b/src/lobby.cpp index db28d634c..8a0295233 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -3,12 +3,11 @@ #include "aoapplication.h" #include "demoserver.h" #include "networkmanager.h" +#include "qimagereader.h" #include "widgets/add_server_dialog.h" #include "widgets/direct_connect_dialog.h" +#include "widgets/edit_server_dialog.h" -#include -#include -#include #include #define FROM_UI(type, name) \ @@ -35,11 +34,12 @@ Lobby::Lobby(AOApplication *p_ao_app, NetworkManager *p_net_manager) void Lobby::on_tab_changed(int index) { - switch (index) { // Implicit conversion cause FUCK ALL OF YOU. + switch (index) { case SERVER: ui_add_to_favorite_button->setVisible(true); ui_remove_from_favorites_button->setVisible(false); ui_add_server_button->setVisible(false); + ui_edit_favorite_button->setVisible(false); ui_direct_connect_button->setVisible(true); reset_selection(); break; @@ -47,13 +47,15 @@ void Lobby::on_tab_changed(int index) ui_add_to_favorite_button->setVisible(false); ui_remove_from_favorites_button->setVisible(true); ui_add_server_button->setVisible(true); - ui_direct_connect_button->setVisible(true); + ui_edit_favorite_button->setVisible(true); + ui_direct_connect_button->setVisible(false); reset_selection(); break; case DEMOS: ui_add_to_favorite_button->setVisible(false); ui_add_server_button->setVisible(false); ui_remove_from_favorites_button->setVisible(false); + ui_edit_favorite_button->setVisible(false); ui_direct_connect_button->setVisible(false); reset_selection(); break; @@ -85,6 +87,9 @@ void Lobby::reset_selection() ui_server_player_count_lbl->setText(tr("Offline")); ui_server_description_text->clear(); + ui_add_server_button->setEnabled(false); + ui_edit_favorite_button->setEnabled(false); + ui_remove_from_favorites_button->setEnabled(false); ui_connect_button->setEnabled(false); } @@ -136,8 +141,6 @@ void Lobby::loadUI() &Lobby::on_favorite_tree_clicked); connect(ui_favorites_tree, &QTreeWidget::itemDoubleClicked, this, &Lobby::on_list_doubleclicked); - connect(ui_favorites_tree, &QTreeWidget::customContextMenuRequested, this, - &Lobby::on_favorite_list_context_menu_requested); FROM_UI(QTreeWidget, demo_tree); connect(ui_demo_tree, &QTreeWidget::itemClicked, this, @@ -157,10 +160,15 @@ void Lobby::loadUI() 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) + &Lobby::on_add_server_to_fave_released); + + 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) FROM_UI(QPushButton, remove_from_favorites_button) ui_remove_from_favorites_button->setVisible(false); @@ -205,6 +213,15 @@ void Lobby::on_add_server_to_fave_released() AddServerDialog l_dialog; l_dialog.exec(); list_favorites(); + reset_selection(); +} + +void Lobby::on_edit_favorite_released() +{ + EditServerDialog l_dialog(get_selected_server()); + l_dialog.exec(); + list_favorites(); + reset_selection(); } void Lobby::on_remove_from_fav_released() @@ -302,23 +319,6 @@ void Lobby::on_list_doubleclicked(QTreeWidgetItem *p_item, int column) net_manager->join_to_server(); } -void Lobby::on_favorite_list_context_menu_requested(const QPoint &point) -{ - auto *item = ui_favorites_tree->itemAt(point); - if (item == nullptr) { - qInfo() << "no favorite server item; skipping context menu"; - return; - } - const int server_index = item->data(0, Qt::DisplayRole).toInt(); - - auto *menu = new QMenu(this); - menu->addAction(tr("Remove"), ao_app, [this, server_index]() { - Options::getInstance().removeFavorite(server_index); - list_favorites(); - }); - menu->popup(ui_favorites_tree->mapToGlobal(point)); -} - void Lobby::on_favorite_tree_clicked(QTreeWidgetItem *p_item, int column) { column = 0; @@ -332,6 +332,10 @@ void Lobby::on_favorite_tree_clicked(QTreeWidgetItem *p_item, int column) if (n_server < 0) return; + ui_add_server_button->setEnabled(true); + ui_edit_favorite_button->setEnabled(true); + ui_remove_from_favorites_button->setEnabled(true); + QVector f_server_list = Options::getInstance().favorites(); if (n_server >= f_server_list.size()) return; @@ -339,7 +343,6 @@ void Lobby::on_favorite_tree_clicked(QTreeWidgetItem *p_item, int column) f_server = f_server_list.at(n_server); set_server_description(f_server.desc); - ui_server_description_text->moveCursor(QTextCursor::Start); ui_server_description_text->ensureCursorVisible(); ui_server_player_count_lbl->setText(tr("Connecting...")); diff --git a/src/options.cpp b/src/options.cpp index 43bfc4311..1c54f2bbb 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -651,20 +651,37 @@ void Options::addFavorite(server_type server) favorite.sync(); } +void Options::updateFavorite(server_type server, int index) +{ + favorite.beginGroup(QString::number(index)); + favorite.setValue("name", server.name); + favorite.setValue("address", server.ip); + favorite.setValue("port", server.port); + favorite.setValue("desc", server.desc); + if (server.socket_type == TCP) { + favorite.setValue("protocol", "tcp"); + } + else { + favorite.setValue("protocol", "ws"); + } + favorite.endGroup(); + favorite.sync(); +} + QString Options::getUIAsset(QString f_asset_name) { QStringList l_paths{":/base/themes/" + Options::getInstance().theme() + "/" + - f_asset_name}; + f_asset_name}; if (Options::getInstance().subTheme() == "server") { if (!Options::getInstance().serverSubTheme().isEmpty()) { l_paths.prepend(":/base/themes/" + Options::getInstance().theme() + "/" + - Options::getInstance().subTheme() + "/" + f_asset_name); + Options::getInstance().subTheme() + "/" + f_asset_name); } } else { l_paths.prepend(":/base/themes/" + Options::getInstance().theme() + "/" + - Options::getInstance().subTheme() + "/" + f_asset_name); + Options::getInstance().subTheme() + "/" + f_asset_name); } for (const QString &l_path : qAsConst(l_paths)) { diff --git a/src/widgets/add_server_dialog.cpp b/src/widgets/add_server_dialog.cpp index 6321927d8..d590d77c9 100644 --- a/src/widgets/add_server_dialog.cpp +++ b/src/widgets/add_server_dialog.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -38,17 +39,18 @@ AddServerDialog::AddServerDialog() FROM_UI(QPlainTextEdit, server_description_edit); FROM_UI(QDialogButtonBox, server_dialog_button); connect(ui_server_dialog_button, &QDialogButtonBox::accepted, this, - &AddServerDialog::savePressed); + &::AddServerDialog::onSavePressed); connect(ui_server_dialog_button, &QDialogButtonBox::rejected, this, - &AddServerDialog::discardPressed); + &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); } -void AddServerDialog::savePressed() +void AddServerDialog::onSavePressed() { server_type server; server.name = ui_server_display_name_edit->text(); @@ -61,7 +63,11 @@ void AddServerDialog::savePressed() close(); } -void AddServerDialog::discardPressed() { close(); } +void AddServerDialog::onCancelPressed() +{ + close(); + deleteLater(); +} void AddServerDialog::parseLegacyServerEntry() { diff --git a/src/widgets/edit_server_dialog.cpp b/src/widgets/edit_server_dialog.cpp new file mode 100644 index 000000000..109e968f7 --- /dev/null +++ b/src/widgets/edit_server_dialog.cpp @@ -0,0 +1,87 @@ +#include "widgets/edit_server_dialog.h" +#include "datatypes.h" +#include "options.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FROM_UI(type, name) \ + ; \ + ui_##name = findChild(#name); + +EditServerDialog::EditServerDialog(int index) : + index(index) // lol +{ + 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); + + 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); + + // 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); + + 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); +} + +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(); +} + +void EditServerDialog::onCancelPressed() +{ + close(); + deleteLater(); +} From fd324e943d51f8327179df0498791b82a348e732 Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Sat, 28 Jan 2023 23:18:54 +0100 Subject: [PATCH 14/61] Add Server remains active when no server is selected --- src/lobby.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lobby.cpp b/src/lobby.cpp index 8a0295233..aff169ebe 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -87,7 +87,6 @@ void Lobby::reset_selection() ui_server_player_count_lbl->setText(tr("Offline")); ui_server_description_text->clear(); - ui_add_server_button->setEnabled(false); ui_edit_favorite_button->setEnabled(false); ui_remove_from_favorites_button->setEnabled(false); ui_connect_button->setEnabled(false); From 8dce3af9eb5e4c57a5381aa4ad8211c8400deb3d Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Sun, 29 Jan 2023 03:17:55 +0100 Subject: [PATCH 15/61] Hack together window title for courtroom I hate this. --- include/lobby.h | 7 +++--- src/lobby.cpp | 8 +++++++ src/packet_distribution.cpp | 44 ++++++++++++++++++++++--------------- 3 files changed, 37 insertions(+), 22 deletions(-) diff --git a/include/lobby.h b/include/lobby.h index 1868c8f2d..43b59f2fd 100644 --- a/include/lobby.h +++ b/include/lobby.h @@ -19,7 +19,6 @@ class AOApplication; class Lobby : public QMainWindow { Q_OBJECT - public: Lobby(AOApplication *p_ao_app, NetworkManager *p_net_man = nullptr); ~Lobby(); @@ -28,9 +27,7 @@ class Lobby : public QMainWindow { void set_server_description(const QString &server_description); void list_servers(); int get_selected_server(); - -signals: - + int pageSelected(); private: AOApplication *ao_app; @@ -83,6 +80,8 @@ class Lobby : public QMainWindow { void loadUI(); + TabPage current_page = SERVER; + private slots: void on_tab_changed(int index); void on_refresh_released(); diff --git a/src/lobby.cpp b/src/lobby.cpp index aff169ebe..405b1facf 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -36,6 +36,7 @@ void Lobby::on_tab_changed(int index) { switch (index) { case SERVER: + current_page = SERVER; ui_add_to_favorite_button->setVisible(true); ui_remove_from_favorites_button->setVisible(false); ui_add_server_button->setVisible(false); @@ -44,6 +45,7 @@ void Lobby::on_tab_changed(int index) reset_selection(); break; case FAVORITES: + current_page = FAVORITES; ui_add_to_favorite_button->setVisible(false); ui_remove_from_favorites_button->setVisible(true); ui_add_server_button->setVisible(true); @@ -52,6 +54,7 @@ void Lobby::on_tab_changed(int index) reset_selection(); break; case DEMOS: + current_page = DEMOS; ui_add_to_favorite_button->setVisible(false); ui_add_server_button->setVisible(false); ui_remove_from_favorites_button->setVisible(false); @@ -81,6 +84,11 @@ int Lobby::get_selected_server() return -1; } +int Lobby::pageSelected() +{ + return current_page; +} + void Lobby::reset_selection() { last_index = -1; diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index 474686ffe..395ce2f5b 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -175,26 +175,34 @@ void AOApplication::server_packet_received(AOPacket *p_packet) courtroom_loaded = false; int selected_server = w_lobby->get_selected_server(); - QString server_address = "", server_name = ""; - if (true) { - 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; - } + 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; + case 1: + { + QVector 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; + } } - else { - QVector 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; + case 2: + window_title = "Local Demo Recording"; + break; + default: + break; } if (courtroom_constructed) From 05959a841388a2324dd196e043dab7b15e03f97d Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Wed, 1 Feb 2023 20:02:56 +0100 Subject: [PATCH 16/61] Fix incorrect subtheme location code --- src/options.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/options.cpp b/src/options.cpp index 1c54f2bbb..c82c12894 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -676,7 +676,7 @@ QString Options::getUIAsset(QString f_asset_name) if (Options::getInstance().subTheme() == "server") { if (!Options::getInstance().serverSubTheme().isEmpty()) { l_paths.prepend(":/base/themes/" + Options::getInstance().theme() + "/" + - Options::getInstance().subTheme() + "/" + f_asset_name); + Options::getInstance().serverSubTheme() + "/" + f_asset_name); } } else { From b362a57c991c9a5b2a9e24a2c4d7441676a7c091 Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Fri, 10 Feb 2023 19:29:09 +0100 Subject: [PATCH 17/61] Cleanup --- include/aoapplication.h | 2 -- include/lobby.h | 14 ++++++------ include/widgets/add_server_dialog.h | 8 +++---- include/widgets/aooptionsdialog.h | 31 +++++++++++---------------- src/aoapplication.cpp | 1 + src/lobby.cpp | 18 +++++++++------- src/widgets/aooptionsdialog.cpp | 12 ++++++++++- src/widgets/direct_connect_dialog.cpp | 9 ++++---- 8 files changed, 51 insertions(+), 44 deletions(-) diff --git a/include/aoapplication.h b/include/aoapplication.h index ed466f906..2496cb59d 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -8,8 +8,6 @@ #include "discord_rich_presence.h" #include "bass.h" -#include "bassmidi.h" -#include "bassopus.h" #include #include diff --git a/include/lobby.h b/include/lobby.h index 43b59f2fd..ad69c88e4 100644 --- a/include/lobby.h +++ b/include/lobby.h @@ -1,14 +1,14 @@ #ifndef LOBBY_H #define LOBBY_H -#include -#include -#include -#include -#include -#include -#include +class QLabel; +class QLineEdit; +class QPushButton; +class QTextBrowser; +class QTreeWidget; +class QTreeWidgetItem; +#include #include "networkmanager.h" #ifdef ANDROID diff --git a/include/widgets/add_server_dialog.h b/include/widgets/add_server_dialog.h index d7daff4e7..db999bfea 100644 --- a/include/widgets/add_server_dialog.h +++ b/include/widgets/add_server_dialog.h @@ -5,14 +5,14 @@ #include "interfaces/server_dialog.h" -class QPushButton; +class QComboBox; class QDialogButton; +class QDialogButtonBox; class QLabel; class QLineEdit; -class QComboBox; -class QSpinBox; class QPlainTextEdit; -class QDialogButtonBox; +class QPushButton; +class QSpinBox; class AddServerDialog : public AttorneyOnline::UI::FavoriteServerDialog { Q_OBJECT diff --git a/include/widgets/aooptionsdialog.h b/include/widgets/aooptionsdialog.h index e5a21246e..5ec7bf95c 100644 --- a/include/widgets/aooptionsdialog.h +++ b/include/widgets/aooptionsdialog.h @@ -5,23 +5,20 @@ #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +class QCheckBox; +class QComboBox; +class QDialogButtonBox; +class QLineEdit; +class QPlainTextEdit; +class QScrollArea; +class QSpinBox; +class QTabWidget; +class QLabel; +class QAbstractButton; + + +#include #include #include #include @@ -89,7 +86,6 @@ class AOOptionsDialog : public QDialog { // The audio tab QWidget *ui_audio_tab; QWidget *ui_audio_widget; - QFormLayout *ui_audio_layout; QComboBox *ui_audio_device_combobox; QSpinBox *ui_music_volume_spinbox; QSpinBox *ui_sfx_volume_spinbox; @@ -127,7 +123,6 @@ class AOOptionsDialog : public QDialog { * Allows the AO2 master server hoster to go broke. */ QWidget *ui_privacy_tab; - QVBoxLayout *ui_privacy_layout; QCheckBox *ui_privacy_optout_cb; QFrame *ui_privacy_separator; QTextBrowser *ui_privacy_policy; diff --git a/src/aoapplication.cpp b/src/aoapplication.cpp index 8b3bcec54..e92904e1d 100644 --- a/src/aoapplication.cpp +++ b/src/aoapplication.cpp @@ -1,5 +1,6 @@ #include "aoapplication.h" +#include "bassmidi.h" #include "courtroom.h" #include "debug_functions.h" #include "lobby.h" diff --git a/src/lobby.cpp b/src/lobby.cpp index 405b1facf..551c615e7 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -3,11 +3,16 @@ #include "aoapplication.h" #include "demoserver.h" #include "networkmanager.h" -#include "qimagereader.h" #include "widgets/add_server_dialog.h" #include "widgets/direct_connect_dialog.h" #include "widgets/edit_server_dialog.h" +#include +#include +#include +#include +#include + #include #define FROM_UI(type, name) \ @@ -36,7 +41,7 @@ void Lobby::on_tab_changed(int index) { switch (index) { case SERVER: - current_page = SERVER; + current_page = SERVER; ui_add_to_favorite_button->setVisible(true); ui_remove_from_favorites_button->setVisible(false); ui_add_server_button->setVisible(false); @@ -45,7 +50,7 @@ void Lobby::on_tab_changed(int index) reset_selection(); break; case FAVORITES: - current_page = FAVORITES; + current_page = FAVORITES; ui_add_to_favorite_button->setVisible(false); ui_remove_from_favorites_button->setVisible(true); ui_add_server_button->setVisible(true); @@ -54,7 +59,7 @@ void Lobby::on_tab_changed(int index) reset_selection(); break; case DEMOS: - current_page = DEMOS; + current_page = DEMOS; ui_add_to_favorite_button->setVisible(false); ui_add_server_button->setVisible(false); ui_remove_from_favorites_button->setVisible(false); @@ -84,10 +89,7 @@ int Lobby::get_selected_server() return -1; } -int Lobby::pageSelected() -{ - return current_page; -} +int Lobby::pageSelected() { return current_page; } void Lobby::reset_selection() { diff --git a/src/widgets/aooptionsdialog.cpp b/src/widgets/aooptionsdialog.cpp index 6bd82a2cc..298ecfbf3 100644 --- a/src/widgets/aooptionsdialog.cpp +++ b/src/widgets/aooptionsdialog.cpp @@ -1,13 +1,23 @@ -#include "widgets/aooptionsdialog.h" #include "QDesktopServices" #include "aoapplication.h" #include "bass.h" #include "file_functions.h" #include "networkmanager.h" #include "options.h" +#include "widgets/aooptionsdialog.h" +#include +#include +#include +#include +#include +#include +#include +#include #include +#include #include +#include #define FROM_UI(type, name) \ ; \ diff --git a/src/widgets/direct_connect_dialog.cpp b/src/widgets/direct_connect_dialog.cpp index 5fb28a038..f73cf1882 100644 --- a/src/widgets/direct_connect_dialog.cpp +++ b/src/widgets/direct_connect_dialog.cpp @@ -3,12 +3,13 @@ #include "networkmanager.h" #include "options.h" -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include #define FROM_UI(type, name) \ ; \ From b330e3d922f7bdbefcfff0a23aee3a19508361af Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Sat, 11 Feb 2023 18:13:25 +0100 Subject: [PATCH 18/61] Make all charicons appear on first join This entire system needs a rework, but this will do for now. Also slightly improves performance by not making it load the character list 4 times, only 2 now :^) closes #854 --- src/charselect.cpp | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/charselect.cpp b/src/charselect.cpp index 1a380febb..7a3ec1a15 100644 --- a/src/charselect.cpp +++ b/src/charselect.cpp @@ -98,8 +98,14 @@ void Courtroom::set_char_select() set_size_and_pos(ui_char_taken, "char_taken"); set_size_and_pos(ui_char_buttons, "char_buttons"); + // Silence emission. This causes the signal to be emitted TWICE during server join! + // Fuck this. Performance Sandwich. + ui_char_taken->blockSignals(true); + ui_char_passworded->blockSignals(true); ui_char_taken->setChecked(true); ui_char_passworded->setChecked(true); + ui_char_taken->blockSignals(false); + ui_char_passworded->blockSignals(false); truncate_label_text(ui_char_taken, "char_taken"); truncate_label_text(ui_char_passworded, "char_passworded"); @@ -142,6 +148,18 @@ void Courtroom::set_char_select_page() if (current_char_page > 0) ui_char_select_left->show(); + QPoint f_spacing = + ao_app->get_button_spacing("char_button_spacing", "courtroom_design.ini"); + + char_columns = + ((ui_char_buttons->width() - button_width) / (f_spacing.x() + button_width)) + + 1; + char_rows = ((ui_char_buttons->height() - button_height) / + (f_spacing.y() + button_height)) + + 1; + + max_chars_on_page = char_columns * char_rows; + put_button_in_place(current_char_page * max_chars_on_page, chars_on_page); } @@ -233,25 +251,13 @@ void Courtroom::put_button_in_place(int starting, int chars_on_this_page) QPoint f_spacing = ao_app->get_button_spacing("char_button_spacing", "courtroom_design.ini"); - int x_spacing = f_spacing.x(); int x_mod_count = 0; - - int y_spacing = f_spacing.y(); int y_mod_count = 0; - char_columns = - ((ui_char_buttons->width() - button_width) / (x_spacing + button_width)) + - 1; - char_rows = ((ui_char_buttons->height() - button_height) / - (y_spacing + button_height)) + - 1; - - max_chars_on_page = char_columns * char_rows; - int startout = starting; for (int n = starting; n < startout + chars_on_this_page; ++n) { - int x_pos = (button_width + x_spacing) * x_mod_count; - int y_pos = (button_height + y_spacing) * y_mod_count; + int x_pos = (button_width + f_spacing.x()) * x_mod_count; + int y_pos = (button_height + f_spacing.y()) * y_mod_count; ui_char_button_list_filtered.at(n)->move(x_pos, y_pos); ui_char_button_list_filtered.at(n)->show(); From 3da086c909027cc83ff8bf5f06e634dfabac6b5a Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Sun, 12 Feb 2023 02:44:01 +0100 Subject: [PATCH 19/61] Fix evidence hover selector under Qt5 #closes #890 --- include/aoevidencebutton.h | 4 ++++ src/aoevidencebutton.cpp | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/include/aoevidencebutton.h b/include/aoevidencebutton.h index 1898539f0..5ba2de085 100644 --- a/include/aoevidencebutton.h +++ b/include/aoevidencebutton.h @@ -32,7 +32,11 @@ class AOEvidenceButton : public QPushButton { int m_id = 0; protected: +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + void enterEvent(QEvent *e); +#else void enterEvent(QEnterEvent *e); +#endif void leaveEvent(QEvent *e); void mouseDoubleClickEvent(QMouseEvent *e); /* diff --git a/src/aoevidencebutton.cpp b/src/aoevidencebutton.cpp index ff690c200..9a259c547 100644 --- a/src/aoevidencebutton.cpp +++ b/src/aoevidencebutton.cpp @@ -104,6 +104,17 @@ void AOEvidenceButton::dragEnterEvent(QMouseEvent *e) } */ +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) +void AOEvidenceButton::enterEvent(QEvent *e) +{ + ui_selector->show(); + + emit on_hover(m_id, true); + + setFlat(false); + QPushButton::enterEvent(e); +} +#else void AOEvidenceButton::enterEvent(QEnterEvent *e) { ui_selector->show(); @@ -113,6 +124,7 @@ void AOEvidenceButton::enterEvent(QEnterEvent *e) setFlat(false); QPushButton::enterEvent(e); } +#endif void AOEvidenceButton::leaveEvent(QEvent *e) { From 8859305c1b9580b2f58fd437d587f5bbfeffad65 Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Sun, 12 Feb 2023 02:59:24 +0100 Subject: [PATCH 20/61] Remove options calling itself trough pointer --- src/options.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/options.cpp b/src/options.cpp index c82c12894..cb53d357a 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -673,15 +673,15 @@ QString Options::getUIAsset(QString f_asset_name) QStringList l_paths{":/base/themes/" + Options::getInstance().theme() + "/" + f_asset_name}; - if (Options::getInstance().subTheme() == "server") { - if (!Options::getInstance().serverSubTheme().isEmpty()) { - l_paths.prepend(":/base/themes/" + Options::getInstance().theme() + "/" + - Options::getInstance().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/" + Options::getInstance().theme() + "/" + - Options::getInstance().subTheme() + "/" + f_asset_name); + l_paths.prepend(":/base/themes/" + theme() + "/" + subTheme() + "/" + + f_asset_name); } for (const QString &l_path : qAsConst(l_paths)) { From 5b634c8019ae062c2c9b6917246b0b5fa482805b Mon Sep 17 00:00:00 2001 From: stonedDiscord Date: Mon, 13 Feb 2023 02:37:38 +0100 Subject: [PATCH 21/61] Fix Android CI (#891) * pro gamer move * remove pregenerated android files * version * install old ass android platform * Revert "remove pregenerated android files" This reverts commit c81a94c6fd337e187af61e9dd706fac5cd51bcc0. * switch to 24 --- .github/workflows/build.yml | 5 +++-- android/project.properties | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 019c8dedd..03cf945c7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -23,7 +23,7 @@ jobs: - platform: gcc_64 os: ubuntu-latest - platform: android - os: ubuntu-latest + os: ubuntu-20.04 - platform: msvc2019 os: windows-2019 - platform: mingw81_32 @@ -59,6 +59,7 @@ jobs: ANDROID_NDK_ROOT=${ANDROID_SDK_ROOT}/ndk-bundle SDKMANAGER=${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager echo "y" | $SDKMANAGER "ndk;21.4.7075529" + echo "y" | $SDKMANAGER "platforms;android-24" ln -sfn $ANDROID_SDK_ROOT/ndk/21.4.7075529 $ANDROID_NDK_ROOT - uses: Skycoder42/action-setup-qt@master @@ -255,7 +256,7 @@ jobs: mkdir ./build/libs/armeabi-v7a/ mv ./bin/*.so ./build/libs/armeabi-v7a/ cp ./QtApng/plugins/imageformats/libplugins_imageformats_qapng_armeabi-v7a.so ./build/libs/armeabi-v7a/ - androiddeployqt --input android-Attorney_Online-deployment-settings.json --output ./build/ --apk ./bin/AttorneyOnline.apk + androiddeployqt --android-platform android-24 --input android-Attorney_Online-deployment-settings.json --output ./build/ --apk ./bin/AttorneyOnline.apk - name: Upload Artifact uses: actions/upload-artifact@master diff --git a/android/project.properties b/android/project.properties index a08f37edd..1fe2228b6 100644 --- a/android/project.properties +++ b/android/project.properties @@ -1 +1 @@ -target=android-21 \ No newline at end of file +target=android-24 \ No newline at end of file From 44594936fbb03f65e0f347d3fc88aec9d234b2c4 Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Tue, 14 Feb 2023 00:26:54 +0100 Subject: [PATCH 22/61] CharButton - Fix enterEvent override in Qt5 Also mark them as override. Also make the preprocessor if a bit less copypastey. --- include/aocharbutton.h | 8 ++++++-- include/aoevidencebutton.h | 8 ++++---- src/aocharbutton.cpp | 4 ++++ src/aoevidencebutton.cpp | 10 +--------- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/include/aocharbutton.h b/include/aocharbutton.h index 8e8038f9c..688d52d60 100644 --- a/include/aocharbutton.h +++ b/include/aocharbutton.h @@ -38,8 +38,12 @@ class AOCharButton : public QPushButton { AOImage *ui_selector; protected: - void enterEvent(QEnterEvent *e); - void leaveEvent(QEvent *e); +#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; }; #endif // AOCHARBUTTON_H diff --git a/include/aoevidencebutton.h b/include/aoevidencebutton.h index 5ba2de085..f0e13531d 100644 --- a/include/aoevidencebutton.h +++ b/include/aoevidencebutton.h @@ -33,12 +33,12 @@ class AOEvidenceButton : public QPushButton { protected: #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - void enterEvent(QEvent *e); + void enterEvent(QEvent *e) override; #else - void enterEvent(QEnterEvent *e); + void enterEvent(QEnterEvent *e) override; #endif - void leaveEvent(QEvent *e); - void mouseDoubleClickEvent(QMouseEvent *e); + void leaveEvent(QEvent *e) override; + void mouseDoubleClickEvent(QMouseEvent *e) override; /* void dragLeaveEvent(QMouseEvent *e); void dragEnterEvent(QMouseEvent *e); diff --git a/src/aocharbutton.cpp b/src/aocharbutton.cpp index 19eff5fcc..0c4ff129d 100644 --- a/src/aocharbutton.cpp +++ b/src/aocharbutton.cpp @@ -78,7 +78,11 @@ void AOCharButton::set_image(QString p_character) } } +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) +void AOCharButton::enterEvent(QEvent *e) +#else void AOCharButton::enterEvent(QEnterEvent *e) +#endif { ui_selector->move(this->x() - 1, this->y() - 1); ui_selector->raise(); diff --git a/src/aoevidencebutton.cpp b/src/aoevidencebutton.cpp index 9a259c547..d731682e9 100644 --- a/src/aoevidencebutton.cpp +++ b/src/aoevidencebutton.cpp @@ -106,16 +106,9 @@ void AOEvidenceButton::dragEnterEvent(QMouseEvent *e) #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) void AOEvidenceButton::enterEvent(QEvent *e) -{ - ui_selector->show(); - - emit on_hover(m_id, true); - - setFlat(false); - QPushButton::enterEvent(e); -} #else void AOEvidenceButton::enterEvent(QEnterEvent *e) +#endif { ui_selector->show(); @@ -124,7 +117,6 @@ void AOEvidenceButton::enterEvent(QEnterEvent *e) setFlat(false); QPushButton::enterEvent(e); } -#endif void AOEvidenceButton::leaveEvent(QEvent *e) { From bae43d8f209cb71dbdc8a998f00183daafb97bdd Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Thu, 16 Feb 2023 16:33:18 +0100 Subject: [PATCH 23/61] version bump --- Attorney_Online.pro | 2 +- include/aoapplication.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Attorney_Online.pro b/Attorney_Online.pro index 1bb32c1b1..e2bec3952 100644 --- a/Attorney_Online.pro +++ b/Attorney_Online.pro @@ -3,7 +3,7 @@ QT += core gui widgets network websockets uitools TARGET = Attorney_Online TEMPLATE = app -VERSION = 2.10.0.0 +VERSION = 2.10.1.0 INCLUDEPATH += $$PWD/include DESTDIR = $$PWD/bin diff --git a/include/aoapplication.h b/include/aoapplication.h index 2496cb59d..7d8ff69a9 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -382,7 +382,7 @@ class AOApplication : public QApplication { private: const int RELEASE = 2; const int MAJOR_VERSION = 10; - const int MINOR_VERSION = 0; + const int MINOR_VERSION = 1; QVector server_list; QHash asset_lookup_cache; From 6ec735ace4e54fb0e1cb0a0caceefaa44a6c3be0 Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Fri, 17 Feb 2023 00:01:29 +0100 Subject: [PATCH 24/61] Update embeeded lobby ui color sheme Shoutout to Dumb Fuck (That is their real discord name). Co-Authored-By: Crystalwarrior <3470436+Crystalwarrior@users.noreply.github.com> --- resource/ui/lobby.ui | 225 ++++++++++++++++++++---- resource/ui/lobby_assets/down-arrow.png | Bin 0 -> 181 bytes resource/ui/lobby_assets/up-arrow.png | Bin 0 -> 181 bytes resources.qrc | 2 + 4 files changed, 192 insertions(+), 35 deletions(-) create mode 100644 resource/ui/lobby_assets/down-arrow.png create mode 100644 resource/ui/lobby_assets/up-arrow.png diff --git a/resource/ui/lobby.ui b/resource/ui/lobby.ui index b15719f55..e311abd7f 100644 --- a/resource/ui/lobby.ui +++ b/resource/ui/lobby.ui @@ -22,12 +22,117 @@ 550 + + Qt::CustomContextMenu + - QWidget#lobby { - background-color: gray; + QWidget#lobby_form { + background-color : rgba(102, 102, 102, 255); +} + +QLabel { + color: white; + font: 8pt "MS Sans Serif"; +} + +QLineEdit { + background-color: rgb(102,102,102); + color: rgb(255, 255, 255); + font: 8pt "MS Sans Serif"; +} + +QTreeWidget { + background-color: rgb(102,102,102); + color: white +} + +QWidget#demo_tab { + border: 1px solid white +} + +QPushButton { + border: 1px solid lightgray; + background-color: rgb(84,33,0); + color: white; + padding: 3; + margin-right: 2px; + margin-left: 2px; + font: 8pt "MS Sans Serif"; +} + +QPushButton:hover { + border: 1px solid white; + background-color: rgb(122,40,0); +} + +QPushButton:pressed { + border: 1px solid white; + background-color: rgb(125,41,0); + color: white; +} + +QTabBar { + font: 8pt "MS Sans Serif"; +} + +QTabBar::tab { + border: 2px solid lightgray; + background-color: rgb(100,41,0); + color: lightgray; + padding: 2; + margin-right: 1px; + margin-left: 1px; + border-bottom: 0; +} + +QTabBar::tab:selected, QTabBar::tab:hover { + color: white; + background-color: rgb(122,40,0); +} + +QTabBar::tab:selected { + background-color: rgb(122,40,0); + border: 2px solid white; + border-bottom: 0; +} + +QTabBar::tab:!selected { + margin-top: 2px; /* make non-selected tabs look smaller */ +} + +QHeaderView::section { + border: 1px solid white; + background-color: rgb(122,40,0); + margin-right: 2px; + padding: 1; + font: 8pt "MS Sans Serif"; +} + +QHeaderView::section:pressed { + background-color: rgb(84,33,0); +} + +QHeaderView::up-arrow +{ + image: url(":/resource/ui/lobby_assets/up-arrow.png"); +} + +QHeaderView::down-arrow +{ + image: url(":/resource/ui/lobby_assets/down-arrow.png"); +} + +QScrollBar:vertical { + background-color: rgba(140,140,140, 255); + color : white +} + +QScrollBar:horizontall { + background-color: rgba(140,140,140, 255); + color : white } @@ -94,6 +199,9 @@ Qt::Horizontal + + QSizePolicy::Expanding + 40 @@ -104,6 +212,18 @@ + + + 0 + 0 + + + + + 100 + 0 + + Settings @@ -111,6 +231,18 @@ + + + 0 + 0 + + + + + 100 + 0 + + About @@ -160,6 +292,9 @@ Qt::LeftToRight + + + 0 @@ -186,13 +321,18 @@ 0 + + + + Search + + + - QTreeWidget { - background-color:black; - color:white; -} + background-color: rgba(140, 140, 140, 255); +color: rgb(255, 255, 255); Qt::ElideNone @@ -212,13 +352,6 @@ - - - - Search - - - @@ -247,10 +380,8 @@ Qt::CustomContextMenu - QTreeWidget { - background-color:black; - color:white; -} + background-color: rgba(140, 140, 140, 255); +color: rgb(255, 255, 255); Qt::ElideNone @@ -295,10 +426,8 @@ - QTreeWidget { - background-color:black; - color:white; -} + background-color: rgba(140, 140, 140, 255); +color: rgb(255, 255, 255); Qt::ElideNone @@ -448,6 +577,12 @@ + + color: #F8A818; +background-color: #383838; +border: 1px solid white; +margin: 1 + Server Info @@ -458,6 +593,12 @@ + + color: #F8A818; +background-color: #383838; +border: 1px solid white; +margin: 1 + Offline @@ -468,18 +609,25 @@ + + + 0 + 0 + + - QTextBrowser { - background-color:back; - color:white; -} + background-color: rgba(140, 140, 140, 255); +color: rgb(255, 255, 255); <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +<html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">No description provided.</p></body></html> +hr { height: 1px; border-width: 0; } +li.unchecked::marker { content: "\2610"; } +li.checked::marker { content: "\2612"; } +</style></head><body style=" font-family:'Segoe UI'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt;">No description provided.</span></p></body></html> @@ -522,6 +670,12 @@ p, li { white-space: pre-wrap; } + + color: #F8A818; +background-color: #383838; +border: 1px solid white; +margin: 1 + Message of the Day @@ -533,17 +687,18 @@ p, li { white-space: pre-wrap; } - QTextBrowser { - background-color:back; - color:white; -} + background-color: rgba(140, 140, 140, 255); +color: rgb(255, 255, 255); <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +<html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> +hr { height: 1px; border-width: 0; } +li.unchecked::marker { content: "\2610"; } +li.checked::marker { content: "\2612"; } +</style></head><body style=" font-family:'Segoe UI'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8.25pt;"><br /></p></body></html> true diff --git a/resource/ui/lobby_assets/down-arrow.png b/resource/ui/lobby_assets/down-arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..ce40d0815cce766e68bf108c76a0451e7d4b28f2 GIT binary patch literal 181 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~k!3HF)wbmE`DaPU;cPEB*=VV?2IV|apzK#qG z8~eHcB(j237I;J!GcfQS24TkI`72U@f?l33jv*SsOV4@oF$nNDT)g)8eb4+U5?af) z8|eJHIOAk{!f)f$%D=6L&Rw5q6wPeWyM@1;@r}}3gJle16ALBs7?O`j-&11RZRH}w YB(3~!!E~u9KvNk!UHx3vIVCg!0MZ3GM*si- literal 0 HcmV?d00001 diff --git a/resource/ui/lobby_assets/up-arrow.png b/resource/ui/lobby_assets/up-arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..46ddf4c634fb158b9433dbcbf0b7123bf0a1d116 GIT binary patch literal 181 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~k!3HF)wbmE`DaPU;cPEB*=VV?2IV|apzK#qG z8~eHcB(j237I;J!GcfQS24TkI`72U@f?l33jv*Ssb9;~TG8k|$EB<~zN6p%+aZB}u zCB~bSnbxRv?K9|}bbP0l+XkK8hbVg literal 0 HcmV?d00001 diff --git a/resources.qrc b/resources.qrc index a1386ce6a..2f8d264ae 100644 --- a/resources.qrc +++ b/resources.qrc @@ -13,5 +13,7 @@ resource/ui/favorite_server_dialog.ui resource/ui/direct_connect_dialog.ui resource/ui/lobby.ui + resource/ui/lobby_assets/down-arrow.png + resource/ui/lobby_assets/up-arrow.png From 1e3e95773b95d1e5e692ff8163aa4f0ef93f1351 Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Mon, 20 Feb 2023 02:22:19 +0100 Subject: [PATCH 25/61] Add changelog.md loading logic from main mount path --- include/lobby.h | 3 +++ src/lobby.cpp | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/include/lobby.h b/include/lobby.h index ad69c88e4..5588ce4d1 100644 --- a/include/lobby.h +++ b/include/lobby.h @@ -78,6 +78,9 @@ class Lobby : public QMainWindow { QTextBrowser *ui_server_description_text; QPushButton *ui_connect_button; + // Optional Widget + QTextBrowser *ui_game_changelog_text; + void loadUI(); TabPage current_page = SERVER; diff --git a/src/lobby.cpp b/src/lobby.cpp index 551c615e7..fcacd17c1 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -193,6 +193,18 @@ void Lobby::loadUI() &QPushButton::setEnabled); FROM_UI(QTextBrowser, motd_text); + FROM_UI(QTextBrowser, game_changelog_text) + if (ui_game_changelog_text != nullptr) { + QString l_changelog_text = "No changelog found."; + QFile l_changelog(ao_app->get_base_path() + "changelog.md"); + if (!l_changelog.open(QFile::ReadOnly)) { + qDebug() << "Unable to locate changelog file. Does it even exist?"; + ui_game_changelog_text->setMarkdown(l_changelog_text); + return; + } + ui_game_changelog_text->setMarkdown(l_changelog.readAll()); + l_changelog.close(); + } } void Lobby::on_refresh_released() From 250fd7c0d7c6a6b44cde65e14a994d9f0bc718f3 Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Tue, 21 Feb 2023 07:31:30 +0100 Subject: [PATCH 26/61] Expand tabbar of optional Tabbar widget --- src/lobby.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/lobby.cpp b/src/lobby.cpp index fcacd17c1..b014290b9 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -204,6 +204,11 @@ void Lobby::loadUI() } ui_game_changelog_text->setMarkdown(l_changelog.readAll()); l_changelog.close(); + + QTabWidget* l_tabbar = findChild("motd_changelog_tab"); + if (l_tabbar != nullptr) { + l_tabbar->tabBar()->setExpanding(true); + } } } From bd4c7fb04f4de709eb54e48f8663e01b9f74bbad Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Tue, 21 Feb 2023 12:00:48 +0100 Subject: [PATCH 27/61] Fix order column being incorrectly sized --- src/lobby.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lobby.cpp b/src/lobby.cpp index b014290b9..e79f36785 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -452,6 +452,7 @@ void Lobby::list_servers() } ui_serverlist_tree->setSortingEnabled(true); ui_serverlist_tree->sortItems(0, Qt::SortOrder::AscendingOrder); + ui_serverlist_tree->resizeColumnToContents(0); } void Lobby::list_favorites() @@ -468,6 +469,7 @@ void Lobby::list_favorites() } ui_favorites_tree->setSortingEnabled(true); ui_favorites_tree->sortItems(0, Qt::SortOrder::AscendingOrder); + ui_favorites_tree->resizeColumnToContents(0); } void Lobby::list_demos() @@ -485,6 +487,7 @@ void Lobby::list_demos() } ui_demo_tree->setSortingEnabled(true); ui_demo_tree->sortItems(0, Qt::SortOrder::AscendingOrder); + ui_demo_tree->resizeColumnToContents(0); } void Lobby::get_motd() From 68a20acd963d6f99201a5126268d86b04e942a65 Mon Sep 17 00:00:00 2001 From: stonedDiscord Date: Wed, 22 Feb 2023 15:11:29 +0100 Subject: [PATCH 28/61] missed a space --- resource/translations/ao_de.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resource/translations/ao_de.ts b/resource/translations/ao_de.ts index 0e2cba946..cc476bad5 100644 --- a/resource/translations/ao_de.ts +++ b/resource/translations/ao_de.ts @@ -1085,7 +1085,7 @@ Hast du ALLES von tiny.cc/getao heruntergeladen und entpackt, auch den großen & New version available: %1 - Neue Version verfügbar:%1 + Neue Version verfügbar: %1 From 680b1259fffc96df42769c8249916a04c4162477 Mon Sep 17 00:00:00 2001 From: stonedDiscord Date: Wed, 22 Feb 2023 15:53:01 +0100 Subject: [PATCH 29/61] remove fonts --- resource/ui/lobby.ui | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/resource/ui/lobby.ui b/resource/ui/lobby.ui index e311abd7f..7b32a8538 100644 --- a/resource/ui/lobby.ui +++ b/resource/ui/lobby.ui @@ -35,13 +35,11 @@ QLabel { color: white; - font: 8pt "MS Sans Serif"; } QLineEdit { background-color: rgb(102,102,102); color: rgb(255, 255, 255); - font: 8pt "MS Sans Serif"; } QTreeWidget { @@ -60,7 +58,6 @@ QPushButton { padding: 3; margin-right: 2px; margin-left: 2px; - font: 8pt "MS Sans Serif"; } QPushButton:hover { @@ -74,10 +71,6 @@ QPushButton:pressed { color: white; } -QTabBar { - font: 8pt "MS Sans Serif"; -} - QTabBar::tab { border: 2px solid lightgray; background-color: rgb(100,41,0); @@ -108,7 +101,6 @@ QHeaderView::section { background-color: rgb(122,40,0); margin-right: 2px; padding: 1; - font: 8pt "MS Sans Serif"; } QHeaderView::section:pressed { @@ -281,11 +273,6 @@ QScrollBar:horizontall { - - - false - - Qt::CustomContextMenu @@ -556,7 +543,7 @@ color: rgb(255, 255, 255); 0 - 5 + 4 @@ -626,8 +613,8 @@ p, li { white-space: pre-wrap; } hr { height: 1px; border-width: 0; } li.unchecked::marker { content: "\2610"; } li.checked::marker { content: "\2612"; } -</style></head><body style=" font-family:'Segoe UI'; font-size:9pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt;">No description provided.</span></p></body></html> +</style></head><body > +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span >No description provided.</span></p></body></html> @@ -697,8 +684,8 @@ p, li { white-space: pre-wrap; } hr { height: 1px; border-width: 0; } li.unchecked::marker { content: "\2610"; } li.checked::marker { content: "\2612"; } -</style></head><body style=" font-family:'Segoe UI'; font-size:9pt; font-weight:400; font-style:normal;"> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8.25pt;"><br /></p></body></html> +</style></head><body> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; "><br /></p></body></html> true From 188deec8a646ce96691d889e0c1ea3031eb39088 Mon Sep 17 00:00:00 2001 From: stonedDiscord Date: Wed, 22 Feb 2023 17:25:45 +0100 Subject: [PATCH 30/61] change margins --- resource/ui/lobby.ui | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/resource/ui/lobby.ui b/resource/ui/lobby.ui index 7b32a8538..c33dccac0 100644 --- a/resource/ui/lobby.ui +++ b/resource/ui/lobby.ui @@ -56,8 +56,6 @@ QPushButton { background-color: rgb(84,33,0); color: white; padding: 3; - margin-right: 2px; - margin-left: 2px; } QPushButton:hover { @@ -76,8 +74,8 @@ QTabBar::tab { background-color: rgb(100,41,0); color: lightgray; padding: 2; - margin-right: 1px; - margin-left: 1px; + margin-right: 5px; + margin-left: 5px; border-bottom: 0; } @@ -331,6 +329,9 @@ color: rgb(255, 255, 255); # + + AlignTrailing|AlignVCenter + @@ -442,7 +443,7 @@ color: rgb(255, 255, 255); - + @@ -467,7 +468,7 @@ color: rgb(255, 255, 255); - + @@ -567,8 +568,7 @@ color: rgb(255, 255, 255); color: #F8A818; background-color: #383838; -border: 1px solid white; -margin: 1 +border: 1px solid white; Server Info @@ -583,8 +583,7 @@ margin: 1 color: #F8A818; background-color: #383838; -border: 1px solid white; -margin: 1 +border: 1px solid white; Offline @@ -597,7 +596,7 @@ margin: 1 - + 0 0 @@ -636,7 +635,7 @@ li.checked::marker { content: "\2612"; } 0 - 4 + 3 @@ -660,8 +659,7 @@ li.checked::marker { content: "\2612"; } color: #F8A818; background-color: #383838; -border: 1px solid white; -margin: 1 +border: 1px solid white; Message of the Day From b27a1a8355b5c0a75823bee3d3185ccaaeef555d Mon Sep 17 00:00:00 2001 From: stonedDiscord Date: Wed, 22 Feb 2023 17:42:02 +0100 Subject: [PATCH 31/61] fix minimum sizes --- resource/ui/favorite_server_dialog.ui | 10 ++++++++-- resource/ui/lobby.ui | 12 ++++++------ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/resource/ui/favorite_server_dialog.ui b/resource/ui/favorite_server_dialog.ui index 0ce467503..a1d5f28e1 100644 --- a/resource/ui/favorite_server_dialog.ui +++ b/resource/ui/favorite_server_dialog.ui @@ -6,10 +6,16 @@ 0 0 - 412 - 423 + 420 + 420 + + + 230 + 260 + + Form diff --git a/resource/ui/lobby.ui b/resource/ui/lobby.ui index c33dccac0..40b785960 100644 --- a/resource/ui/lobby.ui +++ b/resource/ui/lobby.ui @@ -18,8 +18,8 @@ - 600 - 550 + 300 + 280 @@ -612,8 +612,8 @@ p, li { white-space: pre-wrap; } hr { height: 1px; border-width: 0; } li.unchecked::marker { content: "\2610"; } li.checked::marker { content: "\2612"; } -</style></head><body > -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span >No description provided.</span></p></body></html> +</style></head><body style=" font-family:'Segoe UI'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">No description provided.</p></body></html> @@ -682,8 +682,8 @@ p, li { white-space: pre-wrap; } hr { height: 1px; border-width: 0; } li.unchecked::marker { content: "\2610"; } li.checked::marker { content: "\2612"; } -</style></head><body> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; "><br /></p></body></html> +</style></head><body style=" font-family:'Segoe UI'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> true From a33f5c1abaadaa1434a96770e3af1e7a94ed9758 Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Wed, 22 Feb 2023 21:55:15 +0100 Subject: [PATCH 32/61] Allow theme overwrite of settings menu --- src/widgets/aooptionsdialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/aooptionsdialog.cpp b/src/widgets/aooptionsdialog.cpp index 298ecfbf3..4ac4ac0cc 100644 --- a/src/widgets/aooptionsdialog.cpp +++ b/src/widgets/aooptionsdialog.cpp @@ -29,7 +29,7 @@ AOOptionsDialog::AOOptionsDialog(QDialog *parent, AOApplication *p_ao_app) ao_app = p_ao_app; QUiLoader l_loader(this); - QFile l_uiFile(":/resource/ui/options_dialog.ui"); + QFile l_uiFile(Options::getInstance().getUIAsset("options_dialog.ui")); if (!l_uiFile.open(QFile::ReadOnly)) { qWarning() << "Unable to open file " << l_uiFile.fileName(); return; From a0feb07cd0791bc6544f683d64deb5610eb84c29 Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Thu, 23 Feb 2023 00:24:26 +0100 Subject: [PATCH 33/61] Cleanup iterator for subthemes --- src/widgets/aooptionsdialog.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/widgets/aooptionsdialog.cpp b/src/widgets/aooptionsdialog.cpp index 4ac4ac0cc..83e38b2f6 100644 --- a/src/widgets/aooptionsdialog.cpp +++ b/src/widgets/aooptionsdialog.cpp @@ -1,10 +1,10 @@ +#include "widgets/aooptionsdialog.h" #include "QDesktopServices" #include "aoapplication.h" #include "bass.h" #include "file_functions.h" #include "networkmanager.h" #include "options.h" -#include "widgets/aooptionsdialog.h" #include #include @@ -52,13 +52,14 @@ AOOptionsDialog::AOOptionsDialog(QDialog *parent, AOApplication *p_ao_app) // Gameplay Tab FROM_UI(QComboBox, theme_combobox) + connect(ui_theme_combobox, + QOverload::of(&QComboBox::currentIndexChanged), this, + &AOOptionsDialog::themeChanged); + registerOption("theme_combobox", &Options::theme, &Options::setTheme); FROM_UI(QComboBox, subtheme_combobox) - connect(ui_theme_combobox, - QOverload::of(&QComboBox::currentIndexChanged), this, - &AOOptionsDialog::themeChanged); registerOption("subtheme_combobox", &Options::subTheme, &Options::setSubTheme); @@ -596,11 +597,11 @@ void AOOptionsDialog::themeChanged(int i) ui_subtheme_combobox->addItem("default"); QDirIterator it(ao_app->get_real_path(ao_app->get_theme_path( "", ui_theme_combobox->itemText(i))), - QDir::Dirs, QDirIterator::NoIteratorFlags); + QDir::Dirs | QDir::NoDotAndDotDot, + QDirIterator::NoIteratorFlags); while (it.hasNext()) { QString actualname = QDir(it.next()).dirName(); - if (actualname != "." && actualname != ".." && - actualname.toLower() != "server" && actualname.toLower() != "default" && + if (actualname.toLower() != "server" && actualname.toLower() != "default" && actualname.toLower() != "effects" && actualname.toLower() != "misc") ui_subtheme_combobox->addItem(actualname); From 28129e8eba651e025d6f5540854c0f2862f68f5a Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Thu, 23 Feb 2023 00:37:35 +0100 Subject: [PATCH 34/61] Allow reload of settings menu Might aswell do them all :shrug: --- include/widgets/aooptionsdialog.h | 2 + src/widgets/aooptionsdialog.cpp | 694 +++++++++++++++--------------- 2 files changed, 352 insertions(+), 344 deletions(-) diff --git a/include/widgets/aooptionsdialog.h b/include/widgets/aooptionsdialog.h index 5ec7bf95c..4f816745e 100644 --- a/include/widgets/aooptionsdialog.h +++ b/include/widgets/aooptionsdialog.h @@ -155,6 +155,8 @@ private slots: void timestampCbChanged(int state); void onReloadThemeClicked(); void themeChanged(int i); + void setupUI(); + }; #endif // AOOPTIONSDIALOG_H diff --git a/src/widgets/aooptionsdialog.cpp b/src/widgets/aooptionsdialog.cpp index 83e38b2f6..ce8eb0d73 100644 --- a/src/widgets/aooptionsdialog.cpp +++ b/src/widgets/aooptionsdialog.cpp @@ -27,350 +27,7 @@ AOOptionsDialog::AOOptionsDialog(QDialog *parent, AOApplication *p_ao_app) : QDialog(parent) { ao_app = p_ao_app; - - QUiLoader l_loader(this); - QFile l_uiFile(Options::getInstance().getUIAsset("options_dialog.ui")); - if (!l_uiFile.open(QFile::ReadOnly)) { - qWarning() << "Unable to open file " << l_uiFile.fileName(); - return; - } - - ui_settings_widget = l_loader.load(&l_uiFile, this); - - auto l_layout = new QVBoxLayout(this); - l_layout->addWidget(ui_settings_widget); - - // 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); - - // Gameplay Tab - FROM_UI(QComboBox, theme_combobox) - connect(ui_theme_combobox, - QOverload::of(&QComboBox::currentIndexChanged), this, - &AOOptionsDialog::themeChanged); - - registerOption("theme_combobox", &Options::theme, - &Options::setTheme); - - FROM_UI(QComboBox, subtheme_combobox) - registerOption("subtheme_combobox", &Options::subTheme, - &Options::setSubTheme); - - FROM_UI(QPushButton, theme_reload_button) - connect(ui_theme_reload_button, &QPushButton::clicked, this, - &::AOOptionsDialog::onReloadThemeClicked); - - 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)) { - return; - } - QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); - }); - - 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("animated_theme_cb", - &Options::animatedThemeEnabled, - &Options::setAnimatedThemeEnabled); - registerOption("stay_time_spinbox", &Options::textStayTime, - &Options::setTextStayTime); - registerOption("instant_objection_cb", - &Options::objectionSkipQueueEnabled, - &Options::setObjectionSkipQueueEnabled); - registerOption("text_crawl_spinbox", &Options::textCrawlSpeed, - &Options::setTextCrawlSpeed); - registerOption("chat_ratelimit_spinbox", - &Options::chatRateLimit, - &Options::setChatRateLimit); - registerOption("username_textbox", &Options::username, - &Options::setUsername); - registerOption("showname_cb", - &Options::customShownameEnabled, - &Options::setCustomShownameEnabled); - registerOption("default_showname_textbox", - &Options::shownameOnJoin, - &Options::setShownameOnJoin); - registerOption("ms_textbox", - &Options::alternativeMasterserver, - &Options::setAlternativeMasterserver); - registerOption("discord_cb", &Options::discordEnabled, - &Options::setDiscordEnabled); - registerOption("language_combobox", &Options::language, - &Options::setLanguage); - registerOption("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("shake_cb", &Options::shakeEnabled, - &Options::setShakeEnabled); - registerOption("effects_cb", &Options::effectsEnabled, - &Options::setEffectsEnabled); - registerOption("framenetwork_cb", - &Options::networkedFrameSfxEnabled, - &Options::setNetworkedFrameSfxEnabled); - registerOption("colorlog_cb", &Options::colorLogEnabled, - &Options::setColorLogEnabled); - registerOption( - "stickysounds_cb", &Options::clearSoundsDropdownOnPlayEnabled, - &Options::setClearSoundsDropdownOnPlayEnabled); - registerOption( - "stickyeffects_cb", &Options::clearEffectsDropdownOnPlayEnabled, - &Options::setClearEffectsDropdownOnPlayEnabled); - registerOption("stickypres_cb", - &Options::clearPreOnPlayEnabled, - &Options::setClearPreOnPlayEnabled); - registerOption("customchat_cb", - &Options::customChatboxEnabled, - &Options::setCustomChatboxEnabled); - registerOption("sticker_cb", - &Options::characterStickerEnabled, - &Options::setCharacterStickerEnabled); - registerOption("continuous_cb", - &Options::continuousPlaybackEnabled, - &Options::setContinuousPlaybackEnabled); - registerOption("category_stop_cb", - &Options::stopMusicOnCategoryEnabled, - &Options::setStopMusicOnCategoryEnabled); - registerOption("sfx_on_idle_cb", - &Options::playSelectedSFXOnIdle, - &Options::setPlaySelectedSFXOnIdle); - registerOption("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( - "callwords_textbox", &Options::callwords, &Options::setCallwords); - - // Audio tab. - FROM_UI(QComboBox, audio_device_combobox) - populateAudioDevices(); - registerOption("audio_device_combobox", - &Options::audioOutputDevice, - &Options::setAudioOutputDevice); - - FROM_UI(QSpinBox, music_volume_spinbox) - FROM_UI(QSpinBox, sfx_volume_spinbox) - FROM_UI(QSpinBox, blips_volume_spinbox) - 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("music_volume_spinbox", &Options::musicVolume, - &Options::setMusicVolume); - registerOption("sfx_volume_spinbox", &Options::sfxVolume, - &Options::setSfxVolume); - registerOption("blips_volume_spinbox", &::Options::blipVolume, - &Options::setBlipVolume); - registerOption("suppress_audio_spinbox", - &::Options::defaultSuppressAudio, - &Options::setDefaultSupressedAudio); - registerOption("bliprate_spinbox", &::Options::blipRate, - &Options::setBlipRate); - registerOption("blank_blips_cb", &Options::blankBlip, - &Options::setBlankBlip); - registerOption("loopsfx_cb", &Options::loopingSfx, - &Options::setLoopingSfx); - registerOption("objectmusic_cb", - &Options::objectionStopMusic, - &Options::setObjectionStopMusic); - registerOption("disablestreams_cb", - &Options::streamingEnabled, - &Options::setStreamingEnabled); - - // Asset tab - FROM_UI(QListWidget, mount_list) - auto *defaultMount = - new QListWidgetItem(tr("%1 (default)").arg(ao_app->get_base_path())); - defaultMount->setFlags(Qt::ItemFlag::NoItemFlags); - ui_mount_list->addItem(defaultMount); - registerOption("mount_list", &Options::mountPaths, - &Options::setMountPaths); - - 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()) { - return; - } - QDir dir(QApplication::applicationDirPath()); - QString relative = dir.relativeFilePath(path); - if (!relative.contains("../")) { - path = relative; - } - QListWidgetItem *dir_item = new QListWidgetItem(path); - ui_mount_list->addItem(dir_item); - ui_mount_list->setCurrentItem(dir_item); - - // quick hack to update buttons - emit ui_mount_list->itemSelectionChanged(); - }); - - FROM_UI(QPushButton, mount_remove) - connect(ui_mount_remove, &QPushButton::clicked, this, [this] { - auto selected = ui_mount_list->selectedItems(); - if (selected.isEmpty()) return; - delete selected[0]; - emit ui_mount_list->itemSelectionChanged(); - asset_cache_dirty = true; - }); - - FROM_UI(QPushButton, mount_up) - connect(ui_mount_up, &QPushButton::clicked, this, [this] { - auto selected = ui_mount_list->selectedItems(); - if (selected.isEmpty()) return; - auto *item = selected[0]; - int row = ui_mount_list->row(item); - ui_mount_list->takeItem(row); - int new_row = qMax(1, row - 1); - ui_mount_list->insertItem(new_row, item); - ui_mount_list->setCurrentRow(new_row); - asset_cache_dirty = true; - }); - - FROM_UI(QPushButton, mount_down) - connect(ui_mount_down, &QPushButton::clicked, this, [this] { - auto selected = ui_mount_list->selectedItems(); - if (selected.isEmpty()) return; - auto *item = selected[0]; - int row = ui_mount_list->row(item); - ui_mount_list->takeItem(row); - int new_row = qMin(ui_mount_list->count() + 1, row + 1); - ui_mount_list->insertItem(new_row, item); - ui_mount_list->setCurrentRow(new_row); - asset_cache_dirty = true; - }); - - 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); - }); - - connect(ui_mount_list, &QListWidget::itemSelectionChanged, this, [this] { - auto selected_items = ui_mount_list->selectedItems(); - bool row_selected = !ui_mount_list->selectedItems().isEmpty(); - ui_mount_remove->setEnabled(row_selected); - ui_mount_up->setEnabled(row_selected); - ui_mount_down->setEnabled(row_selected); - - if (!row_selected) return; - - int row = ui_mount_list->row(selected_items[0]); - if (row <= 1) ui_mount_up->setEnabled(false); - if (row >= ui_mount_list->count() - 1) ui_mount_down->setEnabled(false); - }); - - // 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("downwards_cb", - &Options::logDirectionDownwards, - &Options::setLogDirectionDownwards); - registerOption("length_spinbox", &Options::maxLogSize, - &Options::setMaxLogSize); - registerOption("log_newline_cb", &Options::logNewline, - &Options::setLogNewline); - registerOption("log_margin_spinbox", &Options::logMargin, - &Options::setLogMargin); - - FROM_UI(QCheckBox, log_timestamp_cb) - registerOption("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("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(); - - ui_log_timestamp_format_combobox->setCurrentText(l_current_format); - - 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) - - registerOption("log_ic_actions_cb", &Options::logIcActions, - &Options::setLogIcActions); - registerOption("desync_logs_cb", - &Options::desynchronisedLogsEnabled, - &Options::setDesynchronisedLogsEnabled); - registerOption("log_text_cb", &Options::logToTextFileEnabled, - &Options::setLogToTextFileEnabled); - registerOption("log_demo_cb", &Options::logToDemoFileEnabled, - &Options::setLogToDemoFileEnabled); - - // DSGVO/Privacy tab - - FROM_UI(QTextBrowser, privacy_policy) - ui_privacy_policy->setPlainText(tr("Getting privacy policy...")); - - updateValues(); + setupUI(); } void AOOptionsDialog::populateAudioDevices() @@ -587,6 +244,8 @@ void AOOptionsDialog::onReloadThemeClicked() Options::getInstance().setAnimatedThemeEnabled( ui_animated_theme_cb->isChecked()); emit reloadThemeRequest(); + delete ui_settings_widget; + setupUI(); } void AOOptionsDialog::themeChanged(int i) @@ -617,6 +276,353 @@ void AOOptionsDialog::themeChanged(int i) } } +void AOOptionsDialog::setupUI() +{ + QUiLoader l_loader(this); + QFile l_uiFile(Options::getInstance().getUIAsset("options_dialog.ui")); + if (!l_uiFile.open(QFile::ReadOnly)) { + qWarning() << "Unable to open file " << l_uiFile.fileName(); + return; + } + + ui_settings_widget = l_loader.load(&l_uiFile, this); + + auto l_layout = new QVBoxLayout(this); + l_layout->addWidget(ui_settings_widget); + + // 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); + + // Gameplay Tab + FROM_UI(QComboBox, theme_combobox) + connect(ui_theme_combobox, + QOverload::of(&QComboBox::currentIndexChanged), this, + &AOOptionsDialog::themeChanged); + + registerOption("theme_combobox", &Options::theme, + &Options::setTheme); + + FROM_UI(QComboBox, subtheme_combobox) + registerOption("subtheme_combobox", &Options::subTheme, + &Options::setSubTheme); + + FROM_UI(QPushButton, theme_reload_button) + connect(ui_theme_reload_button, &QPushButton::clicked, this, + &::AOOptionsDialog::onReloadThemeClicked); + + 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)) { + return; + } + QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); + }); + + 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("animated_theme_cb", + &Options::animatedThemeEnabled, + &Options::setAnimatedThemeEnabled); + registerOption("stay_time_spinbox", &Options::textStayTime, + &Options::setTextStayTime); + registerOption("instant_objection_cb", + &Options::objectionSkipQueueEnabled, + &Options::setObjectionSkipQueueEnabled); + registerOption("text_crawl_spinbox", &Options::textCrawlSpeed, + &Options::setTextCrawlSpeed); + registerOption("chat_ratelimit_spinbox", + &Options::chatRateLimit, + &Options::setChatRateLimit); + registerOption("username_textbox", &Options::username, + &Options::setUsername); + registerOption("showname_cb", + &Options::customShownameEnabled, + &Options::setCustomShownameEnabled); + registerOption("default_showname_textbox", + &Options::shownameOnJoin, + &Options::setShownameOnJoin); + registerOption("ms_textbox", + &Options::alternativeMasterserver, + &Options::setAlternativeMasterserver); + registerOption("discord_cb", &Options::discordEnabled, + &Options::setDiscordEnabled); + registerOption("language_combobox", &Options::language, + &Options::setLanguage); + registerOption("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("shake_cb", &Options::shakeEnabled, + &Options::setShakeEnabled); + registerOption("effects_cb", &Options::effectsEnabled, + &Options::setEffectsEnabled); + registerOption("framenetwork_cb", + &Options::networkedFrameSfxEnabled, + &Options::setNetworkedFrameSfxEnabled); + registerOption("colorlog_cb", &Options::colorLogEnabled, + &Options::setColorLogEnabled); + registerOption( + "stickysounds_cb", &Options::clearSoundsDropdownOnPlayEnabled, + &Options::setClearSoundsDropdownOnPlayEnabled); + registerOption( + "stickyeffects_cb", &Options::clearEffectsDropdownOnPlayEnabled, + &Options::setClearEffectsDropdownOnPlayEnabled); + registerOption("stickypres_cb", + &Options::clearPreOnPlayEnabled, + &Options::setClearPreOnPlayEnabled); + registerOption("customchat_cb", + &Options::customChatboxEnabled, + &Options::setCustomChatboxEnabled); + registerOption("sticker_cb", + &Options::characterStickerEnabled, + &Options::setCharacterStickerEnabled); + registerOption("continuous_cb", + &Options::continuousPlaybackEnabled, + &Options::setContinuousPlaybackEnabled); + registerOption("category_stop_cb", + &Options::stopMusicOnCategoryEnabled, + &Options::setStopMusicOnCategoryEnabled); + registerOption("sfx_on_idle_cb", + &Options::playSelectedSFXOnIdle, + &Options::setPlaySelectedSFXOnIdle); + registerOption("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( + "callwords_textbox", &Options::callwords, &Options::setCallwords); + + // Audio tab. + FROM_UI(QComboBox, audio_device_combobox) + populateAudioDevices(); + registerOption("audio_device_combobox", + &Options::audioOutputDevice, + &Options::setAudioOutputDevice); + + FROM_UI(QSpinBox, music_volume_spinbox) + FROM_UI(QSpinBox, sfx_volume_spinbox) + FROM_UI(QSpinBox, blips_volume_spinbox) + 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("music_volume_spinbox", &Options::musicVolume, + &Options::setMusicVolume); + registerOption("sfx_volume_spinbox", &Options::sfxVolume, + &Options::setSfxVolume); + registerOption("blips_volume_spinbox", &::Options::blipVolume, + &Options::setBlipVolume); + registerOption("suppress_audio_spinbox", + &::Options::defaultSuppressAudio, + &Options::setDefaultSupressedAudio); + registerOption("bliprate_spinbox", &::Options::blipRate, + &Options::setBlipRate); + registerOption("blank_blips_cb", &Options::blankBlip, + &Options::setBlankBlip); + registerOption("loopsfx_cb", &Options::loopingSfx, + &Options::setLoopingSfx); + registerOption("objectmusic_cb", + &Options::objectionStopMusic, + &Options::setObjectionStopMusic); + registerOption("disablestreams_cb", + &Options::streamingEnabled, + &Options::setStreamingEnabled); + + // Asset tab + FROM_UI(QListWidget, mount_list) + auto *defaultMount = + new QListWidgetItem(tr("%1 (default)").arg(ao_app->get_base_path())); + defaultMount->setFlags(Qt::ItemFlag::NoItemFlags); + ui_mount_list->addItem(defaultMount); + registerOption("mount_list", &Options::mountPaths, + &Options::setMountPaths); + + 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()) { + return; + } + QDir dir(QApplication::applicationDirPath()); + QString relative = dir.relativeFilePath(path); + if (!relative.contains("../")) { + path = relative; + } + QListWidgetItem *dir_item = new QListWidgetItem(path); + ui_mount_list->addItem(dir_item); + ui_mount_list->setCurrentItem(dir_item); + + // quick hack to update buttons + emit ui_mount_list->itemSelectionChanged(); + }); + + FROM_UI(QPushButton, mount_remove) + connect(ui_mount_remove, &QPushButton::clicked, this, [this] { + auto selected = ui_mount_list->selectedItems(); + if (selected.isEmpty()) return; + delete selected[0]; + emit ui_mount_list->itemSelectionChanged(); + asset_cache_dirty = true; + }); + + FROM_UI(QPushButton, mount_up) + connect(ui_mount_up, &QPushButton::clicked, this, [this] { + auto selected = ui_mount_list->selectedItems(); + if (selected.isEmpty()) return; + auto *item = selected[0]; + int row = ui_mount_list->row(item); + ui_mount_list->takeItem(row); + int new_row = qMax(1, row - 1); + ui_mount_list->insertItem(new_row, item); + ui_mount_list->setCurrentRow(new_row); + asset_cache_dirty = true; + }); + + FROM_UI(QPushButton, mount_down) + connect(ui_mount_down, &QPushButton::clicked, this, [this] { + auto selected = ui_mount_list->selectedItems(); + if (selected.isEmpty()) return; + auto *item = selected[0]; + int row = ui_mount_list->row(item); + ui_mount_list->takeItem(row); + int new_row = qMin(ui_mount_list->count() + 1, row + 1); + ui_mount_list->insertItem(new_row, item); + ui_mount_list->setCurrentRow(new_row); + asset_cache_dirty = true; + }); + + 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); + }); + + connect(ui_mount_list, &QListWidget::itemSelectionChanged, this, [this] { + auto selected_items = ui_mount_list->selectedItems(); + bool row_selected = !ui_mount_list->selectedItems().isEmpty(); + ui_mount_remove->setEnabled(row_selected); + ui_mount_up->setEnabled(row_selected); + ui_mount_down->setEnabled(row_selected); + + if (!row_selected) return; + + int row = ui_mount_list->row(selected_items[0]); + if (row <= 1) ui_mount_up->setEnabled(false); + if (row >= ui_mount_list->count() - 1) ui_mount_down->setEnabled(false); + }); + + // 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("downwards_cb", + &Options::logDirectionDownwards, + &Options::setLogDirectionDownwards); + registerOption("length_spinbox", &Options::maxLogSize, + &Options::setMaxLogSize); + registerOption("log_newline_cb", &Options::logNewline, + &Options::setLogNewline); + registerOption("log_margin_spinbox", &Options::logMargin, + &Options::setLogMargin); + + FROM_UI(QCheckBox, log_timestamp_cb) + registerOption("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("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(); + + ui_log_timestamp_format_combobox->setCurrentText(l_current_format); + + 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) + + registerOption("log_ic_actions_cb", &Options::logIcActions, + &Options::setLogIcActions); + registerOption("desync_logs_cb", + &Options::desynchronisedLogsEnabled, + &Options::setDesynchronisedLogsEnabled); + registerOption("log_text_cb", &Options::logToTextFileEnabled, + &Options::setLogToTextFileEnabled); + registerOption("log_demo_cb", &Options::logToDemoFileEnabled, + &Options::setLogToDemoFileEnabled); + + // DSGVO/Privacy tab + + FROM_UI(QTextBrowser, privacy_policy) + ui_privacy_policy->setPlainText(tr("Getting privacy policy...")); + + updateValues(); +} + void AOOptionsDialog::onTimestampFormatEdited() { ui_log_timestamp_format_lbl->setText( From 27e585c03d303785db4e8ffff16d0e927094f24b Mon Sep 17 00:00:00 2001 From: stonedDiscord Date: Fri, 24 Feb 2023 16:45:48 +0100 Subject: [PATCH 35/61] AO base path (#893) * make get_base_path global and move parts that use base to use it * options uses base * sal moved a bunch of code * fix creating case folder --------- Co-authored-by: stonedDiscord <10584181+stonedDiscord@users.noreply.github.com> --- include/aoapplication.h | 1 - include/file_functions.h | 2 ++ include/lobby.h | 1 + src/courtroom.cpp | 22 +++++++++++----------- src/evidence.cpp | 4 ++-- src/file_functions.cpp | 20 ++++++++++++++++++++ src/lobby.cpp | 2 +- src/main.cpp | 2 +- src/options.cpp | 14 +++++++------- src/path_functions.cpp | 20 -------------------- src/widgets/aooptionsdialog.cpp | 4 ++-- 11 files changed, 47 insertions(+), 45 deletions(-) diff --git a/include/aoapplication.h b/include/aoapplication.h index 7d8ff69a9..8ef2a12d4 100644 --- a/include/aoapplication.h +++ b/include/aoapplication.h @@ -141,7 +141,6 @@ class AOApplication : public QApplication { QString get_current_char(); // implementation in path_functions.cpp - QString get_base_path(); VPath get_theme_path(QString p_file, QString p_theme=""); VPath get_character_path(QString p_char, QString p_file); VPath get_misc_path(QString p_misc, QString p_file); diff --git a/include/file_functions.h b/include/file_functions.h index 8bb2e5f6a..31e2e16c1 100644 --- a/include/file_functions.h +++ b/include/file_functions.h @@ -4,9 +4,11 @@ #include #include #include +#include bool file_exists(QString file_path); bool dir_exists(QString file_path); bool exists(QString p_path); +QString get_base_path(); #endif // FILE_FUNCTIONS_H diff --git a/include/lobby.h b/include/lobby.h index 5588ce4d1..e5d357668 100644 --- a/include/lobby.h +++ b/include/lobby.h @@ -10,6 +10,7 @@ class QTreeWidgetItem; #include #include "networkmanager.h" +#include "file_functions.h" #ifdef ANDROID #include diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 6116eb204..66df08394 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -4227,9 +4227,9 @@ void Courtroom::on_ooc_return_pressed() #else QStringList command = ooc_message.split(" ", Qt::SkipEmptyParts); #endif - QDir casefolder("base/cases"); + QDir casefolder(get_base_path()+"/cases"); if (!casefolder.exists()) { - QDir::current().mkdir("base/" + casefolder.dirName()); + 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, " @@ -4266,7 +4266,7 @@ void Courtroom::on_ooc_return_pressed() return; } - QSettings casefile("base/cases/" + command[1] + ".ini", + QSettings casefile(get_base_path() + "/cases/" + command[1] + ".ini", QSettings::IniFormat); QString caseauth = casefile.value("author", "").value(); @@ -4327,9 +4327,9 @@ void Courtroom::on_ooc_return_pressed() #else QStringList command = ooc_message.split(" ", Qt::SkipEmptyParts); #endif - QDir casefolder("base/cases"); + QDir casefolder(get_base_path() + "cases"); if (!casefolder.exists()) { - QDir::current().mkdir("base/" + casefolder.dirName()); + 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, " @@ -4363,7 +4363,7 @@ void Courtroom::on_ooc_return_pressed() ui_ooc_chat_message->clear(); return; } - QSettings casefile("base/cases/" + command[1] + ".ini", + QSettings casefile(get_base_path() + "/cases/" + command[1] + ".ini", QSettings::IniFormat); casefile.setValue("author", ui_ooc_chat_name->text()); casefile.setValue("cmdoc", ""); @@ -4583,7 +4583,7 @@ void Courtroom::on_iniswap_dropdown_changed(int p_index) } QString p_path = ao_app->get_real_path(VPath("iniswaps.ini")); if (!file_exists(p_path)) { - p_path = ao_app->get_base_path() + "iniswaps.ini"; + p_path = get_base_path() + "iniswaps.ini"; } ao_app->write_to_file(swaplist.join("\n"), p_path); ui_iniswap_dropdown->blockSignals(true); @@ -4733,7 +4733,7 @@ void Courtroom::on_sfx_context_menu_requested(const QPoint &pos) menu->addSeparator(); menu->addAction(QString("Open base sounds folder"), this, [=] { - QString p_path = ao_app->get_base_path() + "sounds/general/"; + QString p_path = get_base_path() + "sounds/general/"; if (!dir_exists(p_path)) { return; } @@ -4760,7 +4760,7 @@ void Courtroom::on_sfx_edit_requested() } if (!file_exists(p_path)) { - p_path = ao_app->get_base_path() + "soundlist.ini"; + p_path = get_base_path() + "soundlist.ini"; } QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); } @@ -5008,7 +5008,7 @@ void Courtroom::on_music_list_context_menu_requested(const QPoint &pos) menu->addSeparator(); menu->addAction(QString("Open base music folder"), this, [=] { - QString p_path = ao_app->get_base_path() + "sounds/music/"; + QString p_path = get_base_path() + "sounds/music/"; if (!dir_exists(p_path)) { return; } @@ -5646,7 +5646,7 @@ void Courtroom::on_evidence_context_menu_requested(const QPoint &pos) QMenu *menu = new QMenu(this); menu->addAction(QString("Open base evidence folder"), this, [=] { - QString p_path = ao_app->get_base_path() + "evidence/"; + QString p_path = get_base_path() + "evidence/"; if (!dir_exists(p_path)) { return; } diff --git a/src/evidence.cpp b/src/evidence.cpp index 5face62d9..752ca47d5 100644 --- a/src/evidence.cpp +++ b/src/evidence.cpp @@ -401,7 +401,7 @@ void Courtroom::on_evidence_image_name_edited() void Courtroom::on_evidence_image_button_clicked() { - QDir dir("base/evidence/"); + QDir dir(get_base_path() + "/evidence/"); QFileDialog dialog(this); dialog.setFileMode(QFileDialog::ExistingFile); dialog.setNameFilter(tr("Images (*.png)")); @@ -418,7 +418,7 @@ void Courtroom::on_evidence_image_button_clicked() QString filename = filenames.at(0); QStringList bases = Options::getInstance().mountPaths(); - bases.prepend(ao_app->get_base_path()); + bases.prepend(get_base_path()); for (const QString &base : bases) { QDir baseDir(base); if (filename.startsWith(baseDir.absolutePath() + "/")) { diff --git a/src/file_functions.cpp b/src/file_functions.cpp index 95e9b5f40..92e598f85 100644 --- a/src/file_functions.cpp +++ b/src/file_functions.cpp @@ -26,3 +26,23 @@ bool exists(QString p_path) return file.exists(); } + +QString get_base_path() +{ + QString base_path = ""; +#ifdef ANDROID + QString sdcard_storage = getenv("SECONDARY_STORAGE"); + if (dir_exists(sdcard_storage + "/base/")) { + base_path = sdcard_storage + "/base/"; + } + else { + QString external_storage = getenv("EXTERNAL_STORAGE"); + base_path = external_storage + "/base/"; + } +#elif defined(__APPLE__) + base_path = QCoreApplication::applicationDirPath() + "/../../../base/"; +#else + base_path = QCoreApplication::applicationDirPath() + "/base/"; +#endif + return base_path; +} diff --git a/src/lobby.cpp b/src/lobby.cpp index e79f36785..affde2e3a 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -196,7 +196,7 @@ void Lobby::loadUI() FROM_UI(QTextBrowser, game_changelog_text) if (ui_game_changelog_text != nullptr) { QString l_changelog_text = "No changelog found."; - QFile l_changelog(ao_app->get_base_path() + "changelog.md"); + QFile l_changelog(get_base_path() + "changelog.md"); if (!l_changelog.open(QFile::ReadOnly)) { qDebug() << "Unable to locate changelog file. Does it even exist?"; ui_game_changelog_text->setMarkdown(l_changelog_text); diff --git a/src/main.cpp b/src/main.cpp index 9adfbda11..c7c2836b1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -21,7 +21,7 @@ int main(int argc, char *argv[]) QResource::registerResource(main_app.get_asset("themes/" + Options::getInstance().theme() + ".rcc")); QFontDatabase fontDatabase; - QDirIterator it(main_app.get_base_path() + "fonts", + QDirIterator it(get_base_path() + "fonts", QDirIterator::Subdirectories); while (it.hasNext()) fontDatabase.addApplicationFont(it.next()); diff --git a/src/options.cpp b/src/options.cpp index cb53d357a..df9f06173 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -1,4 +1,5 @@ #include "options.h" +#include "file_functions.h" #include #include @@ -14,8 +15,7 @@ void Options::migrateCallwords() QStringList l_callwords; QFile l_file; - l_file.setFileName(QCoreApplication::applicationDirPath() + - "/base/callwords.ini"); + l_file.setFileName(get_base_path() + "callwords.ini"); if (!l_file.open(QIODevice::ReadOnly)) { qWarning() << "Unable to migrate callwords : File not open."; @@ -38,10 +38,10 @@ void Options::migrateCallwords() } Options::Options() - : config(QCoreApplication::applicationDirPath() + "/base/config.ini", + : config(get_base_path() + "config.ini", QSettings::IniFormat, nullptr), - favorite(QCoreApplication::applicationDirPath() + - "/base/favorite_servers.ini", + favorite(get_base_path() + + "favorite_servers.ini", QSettings::IniFormat, nullptr) { #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) @@ -60,8 +60,8 @@ void Options::migrate() if (config.contains("show_custom_shownames")) { config.remove("show_custom_shownames"); } - if (QFile::exists(QCoreApplication::applicationDirPath() + - "/base/callwords.ini")) { + if (QFile::exists(get_base_path() + + "callwords.ini")) { migrateCallwords(); } if (config.contains("ooc_name")) { diff --git a/src/path_functions.cpp b/src/path_functions.cpp index 8cbe5afa4..df76383dc 100644 --- a/src/path_functions.cpp +++ b/src/path_functions.cpp @@ -29,26 +29,6 @@ static bool is_power_2(unsigned int n) { return r == 1; } -QString AOApplication::get_base_path() -{ - QString base_path = ""; -#ifdef ANDROID - QString sdcard_storage = getenv("SECONDARY_STORAGE"); - if (dir_exists(sdcard_storage + "/base/")) { - base_path = sdcard_storage + "/base/"; - } - else { - QString external_storage = getenv("EXTERNAL_STORAGE"); - base_path = external_storage + "/base/"; - } -#elif defined(__APPLE__) - base_path = applicationDirPath() + "/../../../base/"; -#else - base_path = applicationDirPath() + "/base/"; -#endif - return base_path; -} - VPath AOApplication::get_theme_path(QString p_file, QString p_theme) { if (p_theme == "") diff --git a/src/widgets/aooptionsdialog.cpp b/src/widgets/aooptionsdialog.cpp index ce8eb0d73..f8fd1ccbd 100644 --- a/src/widgets/aooptionsdialog.cpp +++ b/src/widgets/aooptionsdialog.cpp @@ -174,7 +174,7 @@ void AOOptionsDialog::updateValues() QSet themes; QStringList bases = Options::getInstance().mountPaths(); - bases.push_front(ao_app->get_base_path()); + bases.push_front(get_base_path()); for (const QString &base : bases) { QDirIterator it(base + "/themes", QDir::Dirs | QDir::NoDotAndDotDot, QDirIterator::NoIteratorFlags); @@ -475,7 +475,7 @@ void AOOptionsDialog::setupUI() // Asset tab FROM_UI(QListWidget, mount_list) auto *defaultMount = - new QListWidgetItem(tr("%1 (default)").arg(ao_app->get_base_path())); + new QListWidgetItem(tr("%1 (default)").arg(get_base_path())); defaultMount->setFlags(Qt::ItemFlag::NoItemFlags); ui_mount_list->addItem(defaultMount); registerOption("mount_list", &Options::mountPaths, From 063b81b44040288d8590a106e118d086b2795a33 Mon Sep 17 00:00:00 2001 From: stonedDiscord Date: Fri, 24 Feb 2023 16:47:19 +0100 Subject: [PATCH 36/61] Android 2 10 1 (#894) * ask for file permissions before trying to load a file * create armv7 gitignore * extract all the abis * don't fail if the dir exists --- .github/workflows/build.yml | 16 +++++++--------- android/libs/armeabi-v7a/.gitignore | 3 +++ src/main.cpp | 6 ++++++ 3 files changed, 16 insertions(+), 9 deletions(-) create mode 100644 android/libs/armeabi-v7a/.gitignore diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 03cf945c7..8e121a3a0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -165,22 +165,21 @@ jobs: - name: Install Android BASS if: matrix.platform == 'android' run: | - mkdir ./android/libs/ - mkdir ./android/libs/armeabi-v7a/ + mkdir -p ./android/libs/armeabi-v7a/ curl http://www.un4seen.com/files/bass24-android.zip -o bass.zip - unzip -d bass -o bass.zip + unzip -o bass.zip -d bass cp ./bass/libs/armeabi-v7a/libbass.so ./lib/ - cp ./bass/libs/armeabi-v7a/libbass.so ./android/libs/armeabi-v7a/ + unzip -o bass.zip "libs/*" -d "./android/libs/" curl http://www.un4seen.com/files/bassmidi24-android.zip -o bassmidi.zip unzip -d bass -o bassmidi.zip cp ./bass/libs/armeabi-v7a/libbassmidi.so ./lib/ - cp ./bass/libs/armeabi-v7a/libbassmidi.so ./android/libs/armeabi-v7a/ + unzip -o bassmidi.zip "libs/*" -d "./android/libs/" curl http://www.un4seen.com/files/bassopus24-android.zip -o bassopus.zip unzip -d bass -o bassopus.zip cp ./bass/libs/armeabi-v7a/libbassopus.so ./lib/ - cp ./bass/libs/armeabi-v7a/libbassopus.so ./android/libs/armeabi-v7a/ + unzip -o bassopus.zip "libs/*" -d "./android/libs/" - name: qmake if: matrix.platform != 'android' @@ -221,7 +220,7 @@ jobs: shell: bash run: | cp ../scripts/launch.sh . - mkdir imageformats + mkdir -p imageformats cp ../QtApng/plugins/imageformats/libqapng.so ./imageformats/libqapng.so chmod +x launch.sh chmod +x Attorney_Online @@ -252,8 +251,7 @@ jobs: working-directory: ${{github.workspace}}/ shell: bash run: | - mkdir ./build/libs/ - mkdir ./build/libs/armeabi-v7a/ + mkdir -p ./build/libs/armeabi-v7a/ mv ./bin/*.so ./build/libs/armeabi-v7a/ cp ./QtApng/plugins/imageformats/libplugins_imageformats_qapng_armeabi-v7a.so ./build/libs/armeabi-v7a/ androiddeployqt --android-platform android-24 --input android-Attorney_Online-deployment-settings.json --output ./build/ --apk ./bin/AttorneyOnline.apk diff --git a/android/libs/armeabi-v7a/.gitignore b/android/libs/armeabi-v7a/.gitignore new file mode 100644 index 000000000..ee1cb905b --- /dev/null +++ b/android/libs/armeabi-v7a/.gitignore @@ -0,0 +1,3 @@ +libbass.so +libbassmidi.so +libbassopus.so \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index c7c2836b1..5b696fef1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -17,6 +17,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"}); + } + #endif + AOApplication::addLibraryPath(AOApplication::applicationDirPath() + "/lib"); QResource::registerResource(main_app.get_asset("themes/" + Options::getInstance().theme() + ".rcc")); From 89c838ae8d91992e0ae16ee2a0b368445aca76c5 Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Sun, 26 Feb 2023 00:27:57 +0100 Subject: [PATCH 37/61] Clear options map before reloading the UI --- src/widgets/aooptionsdialog.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/widgets/aooptionsdialog.cpp b/src/widgets/aooptionsdialog.cpp index f8fd1ccbd..0221efcba 100644 --- a/src/widgets/aooptionsdialog.cpp +++ b/src/widgets/aooptionsdialog.cpp @@ -245,6 +245,7 @@ void AOOptionsDialog::onReloadThemeClicked() ui_animated_theme_cb->isChecked()); emit reloadThemeRequest(); delete ui_settings_widget; + optionEntries.clear(); setupUI(); } From b60765d9bbda373155592a6cd2c6275c7fe225e5 Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Sun, 26 Feb 2023 05:27:13 +0100 Subject: [PATCH 38/61] Fix runtime warning for theme/subtheme combobox Shouldn't do the job of something that the template can do for me. Also fix formatting cause it was busted. Also made the subtheme/theme load code not give me cancer. --- src/widgets/aooptionsdialog.cpp | 746 ++++++++++++++++---------------- 1 file changed, 371 insertions(+), 375 deletions(-) diff --git a/src/widgets/aooptionsdialog.cpp b/src/widgets/aooptionsdialog.cpp index 0221efcba..4b68b081b 100644 --- a/src/widgets/aooptionsdialog.cpp +++ b/src/widgets/aooptionsdialog.cpp @@ -169,42 +169,30 @@ void AOOptionsDialog::registerOption(const QString &widgetName, void AOOptionsDialog::updateValues() { - for (const OptionEntry &entry : qAsConst(optionEntries)) - entry.load(); - QSet themes; QStringList bases = Options::getInstance().mountPaths(); bases.push_front(get_base_path()); + for (const QString &base : bases) { - QDirIterator it(base + "/themes", QDir::Dirs | QDir::NoDotAndDotDot, - QDirIterator::NoIteratorFlags); - while (it.hasNext()) { - QString actualname = QDir(it.next()).dirName(); - if (!themes.contains(actualname)) { - ui_theme_combobox->addItem(actualname); - themes.insert(actualname); + QStringList l_themes = + QDir(base + "themes").entryList(QDir::Dirs | QDir::NoDotAndDotDot); + for (const QString &l_theme : qAsConst(l_themes)) { + if (!themes.contains(l_theme)) { + ui_theme_combobox->addItem(l_theme); + themes.insert(l_theme); } } } - int l_theme_index = - ui_theme_combobox->findText(Options::getInstance().theme()); - if (l_theme_index != -1) // Data found - ui_theme_combobox->setCurrentIndex(l_theme_index); - - QDirIterator it2(ao_app->get_real_path(ao_app->get_theme_path("")), - QDir::Dirs, QDirIterator::NoIteratorFlags); - while (it2.hasNext()) { - QString actualname = QDir(it2.next()).dirName(); - if (actualname != "." && actualname != ".." && - actualname.toLower() != "server" && actualname.toLower() != "default" && - actualname.toLower() != "effects" && actualname.toLower() != "misc") { - ui_subtheme_combobox->addItem(actualname); + + 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); } } - int l_subTheme_index = - ui_subtheme_combobox->findText(Options::getInstance().subTheme()); - if (l_theme_index != -1) // Data found - ui_subtheme_combobox->setCurrentIndex(l_subTheme_index); ao_app->net_manager->request_document( MSDocumentType::PrivacyPolicy, [this](QString document) { @@ -213,16 +201,20 @@ void AOOptionsDialog::updateValues() } ui_privacy_policy->setHtml(document); }); + + for (const OptionEntry &entry : qAsConst(optionEntries)) { + entry.load(); + } } void AOOptionsDialog::savePressed() { for (const OptionEntry &entry : qAsConst(optionEntries)) entry.save(); - this->close(); + close(); } -void AOOptionsDialog::discardPressed() { this->close(); } +void AOOptionsDialog::discardPressed() { close(); } void AOOptionsDialog::buttonClicked(QAbstractButton *button) { @@ -244,6 +236,7 @@ void AOOptionsDialog::onReloadThemeClicked() Options::getInstance().setAnimatedThemeEnabled( ui_animated_theme_cb->isChecked()); emit reloadThemeRequest(); + delete layout(); delete ui_settings_widget; optionEntries.clear(); setupUI(); @@ -255,373 +248,376 @@ void AOOptionsDialog::themeChanged(int i) // Fill the combobox with the names of the themes. ui_subtheme_combobox->addItem("server"); ui_subtheme_combobox->addItem("default"); - QDirIterator it(ao_app->get_real_path(ao_app->get_theme_path( - "", ui_theme_combobox->itemText(i))), - QDir::Dirs | QDir::NoDotAndDotDot, - QDirIterator::NoIteratorFlags); - while (it.hasNext()) { - QString actualname = QDir(it.next()).dirName(); - if (actualname.toLower() != "server" && actualname.toLower() != "default" && - actualname.toLower() != "effects" && actualname.toLower() != "misc") - ui_subtheme_combobox->addItem(actualname); - - QString l_resource = ao_app->get_asset( - "themes/" + ui_theme_combobox->currentText() + ".rcc"); - if (l_resource.isEmpty()) { - QResource::unregisterResource(ao_app->get_asset( - "themes/" + Options::getInstance().theme() + ".rcc")); - qDebug() << "Unable to locate ressource file" << l_resource; - return; + + 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") { + ui_subtheme_combobox->addItem(l_subthemes); } - QResource::registerResource(l_resource); } + + 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)); + qDebug() << "Unable to locate ressource file" << l_ressource_name; + return; + } + QResource::registerResource(l_resource); } void AOOptionsDialog::setupUI() { - QUiLoader l_loader(this); - QFile l_uiFile(Options::getInstance().getUIAsset("options_dialog.ui")); - if (!l_uiFile.open(QFile::ReadOnly)) { - qWarning() << "Unable to open file " << l_uiFile.fileName(); - return; - } + QUiLoader l_loader(this); + QFile l_uiFile(Options::getInstance().getUIAsset("options_dialog.ui")); + if (!l_uiFile.open(QFile::ReadOnly)) { + qWarning() << "Unable to open file " << l_uiFile.fileName(); + return; + } - ui_settings_widget = l_loader.load(&l_uiFile, this); + ui_settings_widget = l_loader.load(&l_uiFile, this); - auto l_layout = new QVBoxLayout(this); - l_layout->addWidget(ui_settings_widget); + auto l_layout = new QVBoxLayout(this); + l_layout->addWidget(ui_settings_widget); - // General dialog element. - FROM_UI(QDialogButtonBox, settings_buttons); + // 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::of(&QComboBox::currentIndexChanged), this, - &AOOptionsDialog::themeChanged); + // Gameplay Tab + FROM_UI(QComboBox, theme_combobox) + connect(ui_theme_combobox, + QOverload::of(&QComboBox::currentIndexChanged), this, + &AOOptionsDialog::themeChanged); - registerOption("theme_combobox", &Options::theme, - &Options::setTheme); + registerOption("theme_combobox", &Options::theme, + &Options::setTheme); - FROM_UI(QComboBox, subtheme_combobox) - registerOption("subtheme_combobox", &Options::subTheme, - &Options::setSubTheme); + FROM_UI(QComboBox, subtheme_combobox) + registerOption("subtheme_combobox", &Options::subTheme, + &Options::setSubTheme); - 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) - 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)) { - return; - } - QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); - }); - - 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("animated_theme_cb", - &Options::animatedThemeEnabled, - &Options::setAnimatedThemeEnabled); - registerOption("stay_time_spinbox", &Options::textStayTime, - &Options::setTextStayTime); - registerOption("instant_objection_cb", - &Options::objectionSkipQueueEnabled, - &Options::setObjectionSkipQueueEnabled); - registerOption("text_crawl_spinbox", &Options::textCrawlSpeed, - &Options::setTextCrawlSpeed); - registerOption("chat_ratelimit_spinbox", - &Options::chatRateLimit, - &Options::setChatRateLimit); - registerOption("username_textbox", &Options::username, - &Options::setUsername); - registerOption("showname_cb", - &Options::customShownameEnabled, - &Options::setCustomShownameEnabled); - registerOption("default_showname_textbox", - &Options::shownameOnJoin, - &Options::setShownameOnJoin); - registerOption("ms_textbox", - &Options::alternativeMasterserver, - &Options::setAlternativeMasterserver); - registerOption("discord_cb", &Options::discordEnabled, - &Options::setDiscordEnabled); - registerOption("language_combobox", &Options::language, - &Options::setLanguage); - registerOption("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("shake_cb", &Options::shakeEnabled, - &Options::setShakeEnabled); - registerOption("effects_cb", &Options::effectsEnabled, - &Options::setEffectsEnabled); - registerOption("framenetwork_cb", - &Options::networkedFrameSfxEnabled, - &Options::setNetworkedFrameSfxEnabled); - registerOption("colorlog_cb", &Options::colorLogEnabled, - &Options::setColorLogEnabled); - registerOption( - "stickysounds_cb", &Options::clearSoundsDropdownOnPlayEnabled, - &Options::setClearSoundsDropdownOnPlayEnabled); - registerOption( - "stickyeffects_cb", &Options::clearEffectsDropdownOnPlayEnabled, - &Options::setClearEffectsDropdownOnPlayEnabled); - registerOption("stickypres_cb", - &Options::clearPreOnPlayEnabled, - &Options::setClearPreOnPlayEnabled); - registerOption("customchat_cb", - &Options::customChatboxEnabled, - &Options::setCustomChatboxEnabled); - registerOption("sticker_cb", - &Options::characterStickerEnabled, - &Options::setCharacterStickerEnabled); - registerOption("continuous_cb", - &Options::continuousPlaybackEnabled, - &Options::setContinuousPlaybackEnabled); - registerOption("category_stop_cb", - &Options::stopMusicOnCategoryEnabled, - &Options::setStopMusicOnCategoryEnabled); - registerOption("sfx_on_idle_cb", - &Options::playSelectedSFXOnIdle, - &Options::setPlaySelectedSFXOnIdle); - registerOption("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( - "callwords_textbox", &Options::callwords, &Options::setCallwords); - - // Audio tab. - FROM_UI(QComboBox, audio_device_combobox) - populateAudioDevices(); - registerOption("audio_device_combobox", - &Options::audioOutputDevice, - &Options::setAudioOutputDevice); - - FROM_UI(QSpinBox, music_volume_spinbox) - FROM_UI(QSpinBox, sfx_volume_spinbox) - FROM_UI(QSpinBox, blips_volume_spinbox) - 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("music_volume_spinbox", &Options::musicVolume, - &Options::setMusicVolume); - registerOption("sfx_volume_spinbox", &Options::sfxVolume, - &Options::setSfxVolume); - registerOption("blips_volume_spinbox", &::Options::blipVolume, - &Options::setBlipVolume); - registerOption("suppress_audio_spinbox", - &::Options::defaultSuppressAudio, - &Options::setDefaultSupressedAudio); - registerOption("bliprate_spinbox", &::Options::blipRate, - &Options::setBlipRate); - registerOption("blank_blips_cb", &Options::blankBlip, - &Options::setBlankBlip); - registerOption("loopsfx_cb", &Options::loopingSfx, - &Options::setLoopingSfx); - registerOption("objectmusic_cb", - &Options::objectionStopMusic, - &Options::setObjectionStopMusic); - registerOption("disablestreams_cb", - &Options::streamingEnabled, - &Options::setStreamingEnabled); - - // Asset tab - 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("mount_list", &Options::mountPaths, - &Options::setMountPaths); - - 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()) { - return; - } - QDir dir(QApplication::applicationDirPath()); - QString relative = dir.relativeFilePath(path); - if (!relative.contains("../")) { - path = relative; - } - QListWidgetItem *dir_item = new QListWidgetItem(path); - ui_mount_list->addItem(dir_item); - ui_mount_list->setCurrentItem(dir_item); - - // quick hack to update buttons - emit ui_mount_list->itemSelectionChanged(); - }); - - FROM_UI(QPushButton, mount_remove) - connect(ui_mount_remove, &QPushButton::clicked, this, [this] { - auto selected = ui_mount_list->selectedItems(); - if (selected.isEmpty()) return; - delete selected[0]; - emit ui_mount_list->itemSelectionChanged(); - asset_cache_dirty = true; - }); - - FROM_UI(QPushButton, mount_up) - connect(ui_mount_up, &QPushButton::clicked, this, [this] { - auto selected = ui_mount_list->selectedItems(); - if (selected.isEmpty()) return; - auto *item = selected[0]; - int row = ui_mount_list->row(item); - ui_mount_list->takeItem(row); - int new_row = qMax(1, row - 1); - ui_mount_list->insertItem(new_row, item); - ui_mount_list->setCurrentRow(new_row); - asset_cache_dirty = true; - }); - - FROM_UI(QPushButton, mount_down) - connect(ui_mount_down, &QPushButton::clicked, this, [this] { - auto selected = ui_mount_list->selectedItems(); - if (selected.isEmpty()) return; - auto *item = selected[0]; - int row = ui_mount_list->row(item); - ui_mount_list->takeItem(row); - int new_row = qMin(ui_mount_list->count() + 1, row + 1); - ui_mount_list->insertItem(new_row, item); - ui_mount_list->setCurrentRow(new_row); - asset_cache_dirty = true; - }); - - 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); - }); - - connect(ui_mount_list, &QListWidget::itemSelectionChanged, this, [this] { - auto selected_items = ui_mount_list->selectedItems(); - bool row_selected = !ui_mount_list->selectedItems().isEmpty(); - ui_mount_remove->setEnabled(row_selected); - ui_mount_up->setEnabled(row_selected); - ui_mount_down->setEnabled(row_selected); - - if (!row_selected) return; - - int row = ui_mount_list->row(selected_items[0]); - if (row <= 1) ui_mount_up->setEnabled(false); - if (row >= ui_mount_list->count() - 1) ui_mount_down->setEnabled(false); - }); - - // 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("downwards_cb", - &Options::logDirectionDownwards, - &Options::setLogDirectionDownwards); - registerOption("length_spinbox", &Options::maxLogSize, - &Options::setMaxLogSize); - registerOption("log_newline_cb", &Options::logNewline, - &Options::setLogNewline); - registerOption("log_margin_spinbox", &Options::logMargin, - &Options::setLogMargin); - - FROM_UI(QCheckBox, log_timestamp_cb) - registerOption("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("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(); - - ui_log_timestamp_format_combobox->setCurrentText(l_current_format); - - if (!Options::getInstance().logTimestampEnabled()) { - ui_log_timestamp_format_combobox->setDisabled(true); + 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)) { + return; + } + QDesktopServices::openUrl(QUrl::fromLocalFile(p_path)); + }); + + 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("animated_theme_cb", + &Options::animatedThemeEnabled, + &Options::setAnimatedThemeEnabled); + registerOption("stay_time_spinbox", &Options::textStayTime, + &Options::setTextStayTime); + registerOption("instant_objection_cb", + &Options::objectionSkipQueueEnabled, + &Options::setObjectionSkipQueueEnabled); + registerOption("text_crawl_spinbox", &Options::textCrawlSpeed, + &Options::setTextCrawlSpeed); + registerOption("chat_ratelimit_spinbox", + &Options::chatRateLimit, + &Options::setChatRateLimit); + registerOption("username_textbox", &Options::username, + &Options::setUsername); + registerOption("showname_cb", + &Options::customShownameEnabled, + &Options::setCustomShownameEnabled); + registerOption("default_showname_textbox", + &Options::shownameOnJoin, + &Options::setShownameOnJoin); + registerOption("ms_textbox", + &Options::alternativeMasterserver, + &Options::setAlternativeMasterserver); + registerOption("discord_cb", &Options::discordEnabled, + &Options::setDiscordEnabled); + registerOption("language_combobox", &Options::language, + &Options::setLanguage); + registerOption("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("shake_cb", &Options::shakeEnabled, + &Options::setShakeEnabled); + registerOption("effects_cb", &Options::effectsEnabled, + &Options::setEffectsEnabled); + registerOption("framenetwork_cb", + &Options::networkedFrameSfxEnabled, + &Options::setNetworkedFrameSfxEnabled); + registerOption("colorlog_cb", &Options::colorLogEnabled, + &Options::setColorLogEnabled); + registerOption( + "stickysounds_cb", &Options::clearSoundsDropdownOnPlayEnabled, + &Options::setClearSoundsDropdownOnPlayEnabled); + registerOption( + "stickyeffects_cb", &Options::clearEffectsDropdownOnPlayEnabled, + &Options::setClearEffectsDropdownOnPlayEnabled); + registerOption("stickypres_cb", + &Options::clearPreOnPlayEnabled, + &Options::setClearPreOnPlayEnabled); + registerOption("customchat_cb", + &Options::customChatboxEnabled, + &Options::setCustomChatboxEnabled); + registerOption("sticker_cb", + &Options::characterStickerEnabled, + &Options::setCharacterStickerEnabled); + registerOption("continuous_cb", + &Options::continuousPlaybackEnabled, + &Options::setContinuousPlaybackEnabled); + registerOption("category_stop_cb", + &Options::stopMusicOnCategoryEnabled, + &Options::setStopMusicOnCategoryEnabled); + registerOption("sfx_on_idle_cb", + &Options::playSelectedSFXOnIdle, + &Options::setPlaySelectedSFXOnIdle); + registerOption("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( + "callwords_textbox", &Options::callwords, &Options::setCallwords); + + // Audio tab. + FROM_UI(QComboBox, audio_device_combobox) + populateAudioDevices(); + registerOption("audio_device_combobox", + &Options::audioOutputDevice, + &Options::setAudioOutputDevice); + + FROM_UI(QSpinBox, music_volume_spinbox) + FROM_UI(QSpinBox, sfx_volume_spinbox) + FROM_UI(QSpinBox, blips_volume_spinbox) + 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("music_volume_spinbox", &Options::musicVolume, + &Options::setMusicVolume); + registerOption("sfx_volume_spinbox", &Options::sfxVolume, + &Options::setSfxVolume); + registerOption("blips_volume_spinbox", &::Options::blipVolume, + &Options::setBlipVolume); + registerOption("suppress_audio_spinbox", + &::Options::defaultSuppressAudio, + &Options::setDefaultSupressedAudio); + registerOption("bliprate_spinbox", &::Options::blipRate, + &Options::setBlipRate); + registerOption("blank_blips_cb", &Options::blankBlip, + &Options::setBlankBlip); + registerOption("loopsfx_cb", &Options::loopingSfx, + &Options::setLoopingSfx); + registerOption("objectmusic_cb", + &Options::objectionStopMusic, + &Options::setObjectionStopMusic); + registerOption("disablestreams_cb", + &Options::streamingEnabled, + &Options::setStreamingEnabled); + + // Asset tab + 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("mount_list", &Options::mountPaths, + &Options::setMountPaths); + + 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()) { + return; + } + QDir dir(QApplication::applicationDirPath()); + QString relative = dir.relativeFilePath(path); + if (!relative.contains("../")) { + path = relative; } + QListWidgetItem *dir_item = new QListWidgetItem(path); + ui_mount_list->addItem(dir_item); + ui_mount_list->setCurrentItem(dir_item); + + // quick hack to update buttons + emit ui_mount_list->itemSelectionChanged(); + }); + + FROM_UI(QPushButton, mount_remove) + connect(ui_mount_remove, &QPushButton::clicked, this, [this] { + auto selected = ui_mount_list->selectedItems(); + if (selected.isEmpty()) return; + delete selected[0]; + emit ui_mount_list->itemSelectionChanged(); + asset_cache_dirty = true; + }); + + FROM_UI(QPushButton, mount_up) + connect(ui_mount_up, &QPushButton::clicked, this, [this] { + auto selected = ui_mount_list->selectedItems(); + if (selected.isEmpty()) return; + auto *item = selected[0]; + int row = ui_mount_list->row(item); + ui_mount_list->takeItem(row); + int new_row = qMax(1, row - 1); + ui_mount_list->insertItem(new_row, item); + ui_mount_list->setCurrentRow(new_row); + asset_cache_dirty = true; + }); + + FROM_UI(QPushButton, mount_down) + connect(ui_mount_down, &QPushButton::clicked, this, [this] { + auto selected = ui_mount_list->selectedItems(); + if (selected.isEmpty()) return; + auto *item = selected[0]; + int row = ui_mount_list->row(item); + ui_mount_list->takeItem(row); + int new_row = qMin(ui_mount_list->count() + 1, row + 1); + ui_mount_list->insertItem(new_row, item); + ui_mount_list->setCurrentRow(new_row); + asset_cache_dirty = true; + }); + + 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); + }); + + connect(ui_mount_list, &QListWidget::itemSelectionChanged, this, [this] { + auto selected_items = ui_mount_list->selectedItems(); + bool row_selected = !ui_mount_list->selectedItems().isEmpty(); + ui_mount_remove->setEnabled(row_selected); + ui_mount_up->setEnabled(row_selected); + ui_mount_down->setEnabled(row_selected); + + if (!row_selected) return; + + int row = ui_mount_list->row(selected_items[0]); + if (row <= 1) ui_mount_up->setEnabled(false); + if (row >= ui_mount_list->count() - 1) ui_mount_down->setEnabled(false); + }); + + // 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("downwards_cb", + &Options::logDirectionDownwards, + &Options::setLogDirectionDownwards); + registerOption("length_spinbox", &Options::maxLogSize, + &Options::setMaxLogSize); + registerOption("log_newline_cb", &Options::logNewline, + &Options::setLogNewline); + registerOption("log_margin_spinbox", &Options::logMargin, + &Options::setLogMargin); + + FROM_UI(QCheckBox, log_timestamp_cb) + registerOption("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("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(); + + ui_log_timestamp_format_combobox->setCurrentText(l_current_format); + + 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("log_ic_actions_cb", &Options::logIcActions, - &Options::setLogIcActions); - registerOption("desync_logs_cb", - &Options::desynchronisedLogsEnabled, - &Options::setDesynchronisedLogsEnabled); - registerOption("log_text_cb", &Options::logToTextFileEnabled, - &Options::setLogToTextFileEnabled); - registerOption("log_demo_cb", &Options::logToDemoFileEnabled, - &Options::setLogToDemoFileEnabled); + registerOption("log_ic_actions_cb", &Options::logIcActions, + &Options::setLogIcActions); + registerOption("desync_logs_cb", + &Options::desynchronisedLogsEnabled, + &Options::setDesynchronisedLogsEnabled); + registerOption("log_text_cb", &Options::logToTextFileEnabled, + &Options::setLogToTextFileEnabled); + registerOption("log_demo_cb", &Options::logToDemoFileEnabled, + &Options::setLogToDemoFileEnabled); - // DSGVO/Privacy tab + // DSGVO/Privacy tab - FROM_UI(QTextBrowser, privacy_policy) - ui_privacy_policy->setPlainText(tr("Getting privacy policy...")); + FROM_UI(QTextBrowser, privacy_policy) + ui_privacy_policy->setPlainText(tr("Getting privacy policy...")); - updateValues(); + updateValues(); } void AOOptionsDialog::onTimestampFormatEdited() From b35baffae5bfdca3d87693f83b5f711adb96eb64 Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Sun, 26 Feb 2023 05:55:52 +0100 Subject: [PATCH 39/61] Sort dropdown numerically to match explorer preview closes #793 --- src/widgets/aooptionsdialog.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/widgets/aooptionsdialog.cpp b/src/widgets/aooptionsdialog.cpp index 4b68b081b..03902ee32 100644 --- a/src/widgets/aooptionsdialog.cpp +++ b/src/widgets/aooptionsdialog.cpp @@ -7,6 +7,7 @@ #include "options.h" #include +#include #include #include #include @@ -176,6 +177,12 @@ void AOOptionsDialog::updateValues() 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)) { ui_theme_combobox->addItem(l_theme); From 8c370fdb11e2d420598f85c21a39ae090610a844 Mon Sep 17 00:00:00 2001 From: stonedDiscord Date: Mon, 27 Feb 2023 22:53:44 +0100 Subject: [PATCH 40/61] fuck bass --- .github/workflows/build.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8e121a3a0..593a7ea06 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -170,16 +170,19 @@ jobs: unzip -o bass.zip -d bass cp ./bass/libs/armeabi-v7a/libbass.so ./lib/ unzip -o bass.zip "libs/*" -d "./android/libs/" + cp ./bass/libs/armeabi-v7a/libbass.so ./android/libs/armeabi-v7a/ curl http://www.un4seen.com/files/bassmidi24-android.zip -o bassmidi.zip unzip -d bass -o bassmidi.zip cp ./bass/libs/armeabi-v7a/libbassmidi.so ./lib/ unzip -o bassmidi.zip "libs/*" -d "./android/libs/" + cp ./bass/libs/armeabi-v7a/libbassmidi.so ./android/libs/armeabi-v7a/ curl http://www.un4seen.com/files/bassopus24-android.zip -o bassopus.zip unzip -d bass -o bassopus.zip cp ./bass/libs/armeabi-v7a/libbassopus.so ./lib/ unzip -o bassopus.zip "libs/*" -d "./android/libs/" + cp ./bass/libs/armeabi-v7a/libbassopus.so ./android/libs/armeabi-v7a/ - name: qmake if: matrix.platform != 'android' From 129447f352fcdaac143caef095ef8596c40b3f15 Mon Sep 17 00:00:00 2001 From: stonedDiscord Date: Mon, 27 Feb 2023 23:36:50 +0100 Subject: [PATCH 41/61] copy mingw --- .github/workflows/build.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 593a7ea06..21ac90dc9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -217,6 +217,13 @@ jobs: rm -r bearer rm -r styles + - name: Copy MingW DLL + if: matrix.platform == 'mingw81_32' + working-directory: ${{github.workspace}}/bin/ + shell: bash + run: | + cp /cygdrive/c/Qt/Tools/mingw810_32/bin/libgcc_s_dw2-1.dll . + - name: Deploy Linux if: matrix.platform == 'gcc_64' working-directory: ${{github.workspace}}/bin/ From d62d8f197cc024f90bd8d472a3a4164ea76be213 Mon Sep 17 00:00:00 2001 From: stonedDiscord Date: Mon, 27 Feb 2023 23:37:41 +0100 Subject: [PATCH 42/61] copy other dll --- .github/workflows/build.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 21ac90dc9..51576b5d8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -223,6 +223,8 @@ jobs: shell: bash run: | cp /cygdrive/c/Qt/Tools/mingw810_32/bin/libgcc_s_dw2-1.dll . + cp /cygdrive/c/Qt/Tools/mingw810_32/bin/libstdc++-6.dll . + cp /cygdrive/c/Qt/Tools/mingw810_32/bin/libwinpthread-1.dll . - name: Deploy Linux if: matrix.platform == 'gcc_64' From e3c9ecc8d422fed5b09071d61896deb161a74887 Mon Sep 17 00:00:00 2001 From: stonedDiscord Date: Mon, 27 Feb 2023 23:46:04 +0100 Subject: [PATCH 43/61] wrong folder --- .github/workflows/build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 51576b5d8..0050b183e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -222,9 +222,9 @@ jobs: working-directory: ${{github.workspace}}/bin/ shell: bash run: | - cp /cygdrive/c/Qt/Tools/mingw810_32/bin/libgcc_s_dw2-1.dll . - cp /cygdrive/c/Qt/Tools/mingw810_32/bin/libstdc++-6.dll . - cp /cygdrive/c/Qt/Tools/mingw810_32/bin/libwinpthread-1.dll . + cp D:/a/AO2-Client/AO2-Client/.cache/qt/Tools/mingw810_32/bin/libgcc_s_dw2-1.dll . + cp D:/a/AO2-Client/AO2-Client/.cache/qt/Tools/mingw810_32/bin/libstdc++-6.dll . + cp D:/a/AO2-Client/AO2-Client/.cache/qt/Tools/mingw810_32/bin/libwinpthread-1.dll . - name: Deploy Linux if: matrix.platform == 'gcc_64' From 4a67e2e0789b9e04029d1a125c9b372367c80bc9 Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Tue, 7 Mar 2023 22:18:49 +0100 Subject: [PATCH 44/61] Account for server subtheme --- include/options.h | 3 ++- src/aoapplication.cpp | 1 + src/options.cpp | 24 ++++++++++++++++-------- src/widgets/aooptionsdialog.cpp | 6 +++--- 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/include/options.h b/include/options.h index 792f84668..aba346ccc 100644 --- a/include/options.h +++ b/include/options.h @@ -228,7 +228,8 @@ class Options { // Get the subtheme from settings QString subTheme() const; - void setSubTheme(QString value); + QString settingsSubTheme() const; + void setSettingsSubTheme(QString value); // Returns the server- QString serverSubTheme() const; diff --git a/src/aoapplication.cpp b/src/aoapplication.cpp index e92904e1d..24682bc2f 100644 --- a/src/aoapplication.cpp +++ b/src/aoapplication.cpp @@ -125,6 +125,7 @@ void AOApplication::server_disconnected() construct_lobby(); destruct_courtroom(); } + Options::getInstance().setServerSubTheme(QString()); } void AOApplication::loading_cancelled() diff --git a/src/options.cpp b/src/options.cpp index df9f06173..4c32e963c 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -38,11 +38,9 @@ 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"); @@ -60,8 +58,7 @@ void Options::migrate() 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")) { @@ -460,11 +457,22 @@ void Options::setLogToDemoFileEnabled(bool value) } QString Options::subTheme() const +{ + if (settingsSubTheme() == "server" && !m_server_subtheme.isEmpty()) { + return m_server_subtheme; + } + return settingsSubTheme(); +} + +QString Options::settingsSubTheme() const { return config.value("subtheme", "server").toString(); } -void Options::setSubTheme(QString value) { config.setValue("subtheme", value); } +void Options::setSettingsSubTheme(QString value) +{ + config.setValue("subtheme", value); +} QString Options::serverSubTheme() const { return m_server_subtheme; } diff --git a/src/widgets/aooptionsdialog.cpp b/src/widgets/aooptionsdialog.cpp index 03902ee32..e12a8452d 100644 --- a/src/widgets/aooptionsdialog.cpp +++ b/src/widgets/aooptionsdialog.cpp @@ -239,7 +239,7 @@ void AOOptionsDialog::buttonClicked(QAbstractButton *button) void AOOptionsDialog::onReloadThemeClicked() { Options::getInstance().setTheme(ui_theme_combobox->currentText()); - Options::getInstance().setSubTheme(ui_subtheme_combobox->currentText()); + Options::getInstance().setSettingsSubTheme(ui_subtheme_combobox->currentText()); Options::getInstance().setAnimatedThemeEnabled( ui_animated_theme_cb->isChecked()); emit reloadThemeRequest(); @@ -314,8 +314,8 @@ void AOOptionsDialog::setupUI() &Options::setTheme); FROM_UI(QComboBox, subtheme_combobox) - registerOption("subtheme_combobox", &Options::subTheme, - &Options::setSubTheme); + registerOption("subtheme_combobox", &Options::settingsSubTheme, + &Options::setSettingsSubTheme); FROM_UI(QPushButton, theme_reload_button) connect(ui_theme_reload_button, &QPushButton::clicked, this, From c85c23d79bfaf27540fc963a4f03f9a25b73ccb7 Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Fri, 10 Mar 2023 21:59:34 +0100 Subject: [PATCH 45/61] Replace incorrect subtheme check --- src/packet_distribution.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index 395ce2f5b..cc6b4112d 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -565,8 +565,7 @@ void AOApplication::server_packet_received(AOPacket *p_packet) subtheme = f_contents.at(0); // Check if we have subthemes set to "server" - QString p_st = Options::getInstance().subTheme(); - if (p_st.toLower() != "server") + if (Options::getInstance().serverSubTheme().toLower() != "server") // We don't. Simply acknowledge the subtheme sent by the server, but don't do anything else. return; From e86ce37e6f26e79726b22ae8fbd2793ae2d5c316 Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Fri, 10 Mar 2023 22:02:58 +0100 Subject: [PATCH 46/61] Settings, not server --- src/packet_distribution.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index cc6b4112d..804021184 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -565,7 +565,8 @@ void AOApplication::server_packet_received(AOPacket *p_packet) subtheme = f_contents.at(0); // Check if we have subthemes set to "server" - if (Options::getInstance().serverSubTheme().toLower() != "server") + qDebug() << Options::getInstance().serverSubTheme().toLower(); + if (Options::getInstance().settingsSubTheme().toLower() != "server") // We don't. Simply acknowledge the subtheme sent by the server, but don't do anything else. return; From d0ebe9e33357c1d04bb14b6a3665cd2ed2fca3c0 Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Fri, 10 Mar 2023 22:17:05 +0100 Subject: [PATCH 47/61] Remove debug --- src/packet_distribution.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index 804021184..9bd4d8f69 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -565,7 +565,6 @@ void AOApplication::server_packet_received(AOPacket *p_packet) subtheme = f_contents.at(0); // Check if we have subthemes set to "server" - qDebug() << Options::getInstance().serverSubTheme().toLower(); if (Options::getInstance().settingsSubTheme().toLower() != "server") // We don't. Simply acknowledge the subtheme sent by the server, but don't do anything else. return; From f20236c4728d4c5d93cab49052c579c5ba05168b Mon Sep 17 00:00:00 2001 From: segfault <128277930+memsecviolator@users.noreply.github.com> Date: Sun, 19 Mar 2023 08:29:04 -0500 Subject: [PATCH 48/61] Add compatibility code, suppress compiler warning (#896) lobby.cpp: * Added compatibility code so 2.10.1 can run on Qt versions older than 5.14, such as the version that ships with Ubuntu 20.04 courtroom.cpp: * Used a Q_UNUSED macro on an unused variable to suppress a compiler warning --- src/courtroom.cpp | 1 + src/lobby.cpp | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 66df08394..a357da249 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1736,6 +1736,7 @@ void Courtroom::list_areas() void Courtroom::debug_message_handler(QtMsgType type, const QMessageLogContext &context, const QString &msg) { + Q_UNUSED(context); const QMap colors = { {QtDebugMsg, "debug"}, {QtInfoMsg, "info"}, diff --git a/src/lobby.cpp b/src/lobby.cpp index affde2e3a..6855b023b 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -199,10 +199,18 @@ void Lobby::loadUI() QFile l_changelog(get_base_path() + "changelog.md"); 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 +#endif return; } +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) ui_game_changelog_text->setMarkdown(l_changelog.readAll()); +#else + ui_game_changelog_text->setPlainText((l_changelog.readAll())); +#endif l_changelog.close(); QTabWidget* l_tabbar = findChild("motd_changelog_tab"); From e027d293757788d4c6f4cf004249c5e1c63ecc2f Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Thu, 23 Mar 2023 20:14:32 +0100 Subject: [PATCH 49/61] Resolve Qt6(.5.0) compiler errors --- src/aolayer.cpp | 3 +++ src/lobby.cpp | 38 +++++++++++++++++++------------------ src/text_file_functions.cpp | 20 +++++++++++++++++-- 3 files changed, 41 insertions(+), 20 deletions(-) diff --git a/src/aolayer.cpp b/src/aolayer.cpp index 71dd6c8da..2db0eea19 100644 --- a/src/aolayer.cpp +++ b/src/aolayer.cpp @@ -337,7 +337,10 @@ void AOLayer::start_playback(QString p_image) frame = 0; continuous = false; } + #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) frame_loader = QtConcurrent::run(thread_pool, this, &AOLayer::populate_vectors); + #endif + frame_loader = QtConcurrent::run(thread_pool, &AOLayer::populate_vectors, this); 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 diff --git a/src/lobby.cpp b/src/lobby.cpp index 6855b023b..264f1e71d 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -7,11 +7,11 @@ #include "widgets/direct_connect_dialog.h" #include "widgets/edit_server_dialog.h" -#include -#include +#include #include #include -#include +#include +#include #include @@ -195,28 +195,30 @@ void Lobby::loadUI() FROM_UI(QTextBrowser, motd_text); 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)) { - qDebug() << "Unable to locate changelog file. Does it even exist?"; + QString l_changelog_text = "No changelog found."; + QFile l_changelog(get_base_path() + "changelog.md"); + 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); + 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; - } + return; + } #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) - ui_game_changelog_text->setMarkdown(l_changelog.readAll()); + ui_game_changelog_text->setMarkdown(l_changelog.readAll()); #else - ui_game_changelog_text->setPlainText((l_changelog.readAll())); + ui_game_changelog_text->setPlainText((l_changelog.readAll())); #endif - l_changelog.close(); + l_changelog.close(); - QTabWidget* l_tabbar = findChild("motd_changelog_tab"); - if (l_tabbar != nullptr) { - l_tabbar->tabBar()->setExpanding(true); - } + QTabWidget *l_tabbar = findChild("motd_changelog_tab"); + if (l_tabbar != nullptr) { + l_tabbar->tabBar()->setExpanding(true); + } } } diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index daf84cd56..8aba93fd1 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -62,7 +62,9 @@ bool AOApplication::write_to_file(QString p_text, QString p_file, bool make_dir) QIODevice::Truncate)) { QTextStream out(&f_log); +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) out.setCodec("UTF-8"); +#endif out << p_text; f_log.flush(); @@ -92,7 +94,9 @@ bool AOApplication::append_to_file(QString p_text, QString p_file, if (f_log.open(QIODevice::WriteOnly | QIODevice::Append)) { QTextStream out(&f_log); +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) out.setCodec("UTF-8"); +#endif out << "\r\n" << p_text; f_log.flush(); @@ -131,7 +135,9 @@ 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) { return value.toStringList().join(","); @@ -392,8 +398,10 @@ QString AOApplication::read_char_ini(QString p_char, QString p_search_line, { QSettings settings(get_real_path(get_character_path(p_char, "char.ini")), QSettings::IniFormat); - settings.beginGroup(target_tag); +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) settings.setIniCodec("UTF-8"); +#endif + settings.beginGroup(target_tag); QString value = settings.value(p_search_line).value(); settings.endGroup(); return value; @@ -404,7 +412,10 @@ void AOApplication::set_char_ini(QString p_char, QString value, { 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(); @@ -415,7 +426,9 @@ QStringList AOApplication::read_ini_tags(VPath p_path, QString target_tag) { QStringList r_values; QSettings settings(get_real_path(p_path), QSettings::IniFormat); +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) settings.setIniCodec("UTF-8"); +#endif if (!target_tag.isEmpty()) settings.beginGroup(target_tag); QStringList keys = settings.allKeys(); @@ -711,8 +724,9 @@ QStringList AOApplication::get_effects(QString p_char) } QSettings l_effects_ini(i_filepath, QSettings::IniFormat); +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) l_effects_ini.setIniCodec("UTF-8"); - +#endif // port legacy effects if (!l_effects_ini.contains("version/major") || l_effects_ini.value("version/major").toInt() < 2) { @@ -791,7 +805,9 @@ QString AOApplication::get_effect_property(QString fx_name, QString p_char, 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"); +#endif QStringList char_effects = settings.childGroups(); for (int i = 0; i < char_effects.size(); ++i) { QString effect = settings.value(char_effects[i] + "/name").toString(); From 0cace9bb082e4f0c3ee8a8a2560b10510bf4bdb2 Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Thu, 23 Mar 2023 20:21:51 +0100 Subject: [PATCH 50/61] Undo incompetence. --- src/aolayer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/aolayer.cpp b/src/aolayer.cpp index 2db0eea19..f9b01d3bd 100644 --- a/src/aolayer.cpp +++ b/src/aolayer.cpp @@ -339,8 +339,9 @@ void AOLayer::start_playback(QString p_image) } #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) frame_loader = QtConcurrent::run(thread_pool, this, &AOLayer::populate_vectors); - #endif + #else frame_loader = QtConcurrent::run(thread_pool, &AOLayer::populate_vectors, this); + #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 From fb755b479f794828bac37c50a6e01fb2d2295cfd Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Tue, 18 Apr 2023 07:28:05 +0200 Subject: [PATCH 51/61] Force theme reload on theme change If a user saves a new theme and does not reload the UI it will cause misplacement of widgets inside of courtroom. This is mitigated by forcing a reload. --- src/widgets/aooptionsdialog.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/widgets/aooptionsdialog.cpp b/src/widgets/aooptionsdialog.cpp index e12a8452d..d9e7dbeaf 100644 --- a/src/widgets/aooptionsdialog.cpp +++ b/src/widgets/aooptionsdialog.cpp @@ -216,8 +216,14 @@ void AOOptionsDialog::updateValues() void AOOptionsDialog::savePressed() { - for (const OptionEntry &entry : qAsConst(optionEntries)) + bool l_reload_theme_required = (ui_theme_combobox->currentText() != Options::getInstance().theme()); + for (const OptionEntry &entry : qAsConst(optionEntries)) { entry.save(); + } + + if (l_reload_theme_required) { + emit reloadThemeRequest(); + } close(); } From e4eb370b4c9e3e21f625bf15c7bdceb1f4b2a454 Mon Sep 17 00:00:00 2001 From: lambdcalculus <64238778+lambdcalculus@users.noreply.github.com> Date: Sun, 23 Apr 2023 09:40:04 -0300 Subject: [PATCH 52/61] make speedlines stretch by default (in *actually* non-stupid way this time) (#901) --- src/courtroom.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index a357da249..115723f52 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -53,6 +53,7 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() ui_vp_background->setObjectName("ui_vp_background"); ui_vp_speedlines = new SplashLayer(ui_viewport, ao_app); 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->setObjectName("ui_vp_player_char"); ui_vp_player_char->masked = false; From 454e1f228d31ed683b512c9dbdc513f4126e25a6 Mon Sep 17 00:00:00 2001 From: lambdcalculus <64238778+lambdcalculus@users.noreply.github.com> Date: Wed, 3 May 2023 10:08:48 -0300 Subject: [PATCH 53/61] Rework default volume settings (#903) * rework volume default settings * remove default volume settings in options dialog * make client remember last volume settings instead * fix options starting tab --- include/widgets/aooptionsdialog.h | 3 - resource/ui/options_dialog.ui | 120 ++++++++---------------------- src/courtroom.cpp | 5 ++ src/widgets/aooptionsdialog.cpp | 9 --- 4 files changed, 35 insertions(+), 102 deletions(-) diff --git a/include/widgets/aooptionsdialog.h b/include/widgets/aooptionsdialog.h index 4f816745e..dcc66c1aa 100644 --- a/include/widgets/aooptionsdialog.h +++ b/include/widgets/aooptionsdialog.h @@ -87,9 +87,6 @@ class AOOptionsDialog : public QDialog { QWidget *ui_audio_tab; QWidget *ui_audio_widget; QComboBox *ui_audio_device_combobox; - QSpinBox *ui_music_volume_spinbox; - QSpinBox *ui_sfx_volume_spinbox; - QSpinBox *ui_blips_volume_spinbox; QSpinBox *ui_suppress_audio_spinbox; QFrame *ui_volume_blip_divider; QSpinBox *ui_bliprate_spinbox; diff --git a/resource/ui/options_dialog.ui b/resource/ui/options_dialog.ui index 419eadd7d..26cfa93cc 100644 --- a/resource/ui/options_dialog.ui +++ b/resource/ui/options_dialog.ui @@ -40,8 +40,8 @@ 0 0 - 389 - 701 + 394 + 826 @@ -613,67 +613,17 @@ - - - - Sets the music's default volume. - - - Music: - - - - - - - % - - - 100 - - - - - - - Sets the SFX's default volume. Interjections and actual sound effects count as 'SFX'. - - - SFX: - - - - - - - % - - - 100 - - - - - - - Sets the volume of the blips, the talking sound effects. - - - Blips: - - - - - - - % + + + + QFrame::HLine - - 100 + + QFrame::Sunken - + How much of the volume to suppress when client is not in focus. @@ -683,7 +633,7 @@ - + % @@ -693,7 +643,17 @@ - + + + + QFrame::HLine + + + QFrame::Sunken + + + + Sets the delay between playing the blip sounds. @@ -703,14 +663,14 @@ - + Play a blip sound \"once per every X symbols\", where X is the blip rate. 0 plays a blip sound only once. - + If true, the game will play a blip sound even when a space is 'being said'. @@ -720,14 +680,14 @@ - + - + If true, the game will allow looping sound effects to play on preanimations. @@ -737,14 +697,14 @@ - + - + If true, AO2 will ask the server to stop music when you use 'Objection!' @@ -754,14 +714,14 @@ - + - + If true, AO2 will not play any streamed audio and show that streaming is disabled. @@ -771,33 +731,13 @@ - + - - - - QFrame::HLine - - - QFrame::Sunken - - - - - - - QFrame::HLine - - - QFrame::Sunken - - - diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 115723f52..1d9b5a251 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -5822,6 +5822,11 @@ void Courtroom::truncate_label_text(QWidget *p_widget, QString p_identifier) 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; diff --git a/src/widgets/aooptionsdialog.cpp b/src/widgets/aooptionsdialog.cpp index d9e7dbeaf..8b7befe98 100644 --- a/src/widgets/aooptionsdialog.cpp +++ b/src/widgets/aooptionsdialog.cpp @@ -450,9 +450,6 @@ void AOOptionsDialog::setupUI() &Options::audioOutputDevice, &Options::setAudioOutputDevice); - FROM_UI(QSpinBox, music_volume_spinbox) - FROM_UI(QSpinBox, sfx_volume_spinbox) - FROM_UI(QSpinBox, blips_volume_spinbox) FROM_UI(QSpinBox, suppress_audio_spinbox) FROM_UI(QSpinBox, bliprate_spinbox) FROM_UI(QCheckBox, blank_blips_cb) @@ -460,12 +457,6 @@ void AOOptionsDialog::setupUI() FROM_UI(QCheckBox, objectmusic_cb) FROM_UI(QCheckBox, disablestreams_cb) - registerOption("music_volume_spinbox", &Options::musicVolume, - &Options::setMusicVolume); - registerOption("sfx_volume_spinbox", &Options::sfxVolume, - &Options::setSfxVolume); - registerOption("blips_volume_spinbox", &::Options::blipVolume, - &Options::setBlipVolume); registerOption("suppress_audio_spinbox", &::Options::defaultSuppressAudio, &Options::setDefaultSupressedAudio); From 1c9c42bc85512fb6bc439c593004034227042b42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leifa=E2=99=A5?= <26681464+TrickyLeifa@users.noreply.github.com> Date: Thu, 4 May 2023 09:32:18 -0700 Subject: [PATCH 54/61] Reworked direct connect (#906) Resolve issue #905 Works as advertised. --- include/widgets/direct_connect_dialog.h | 4 +- resource/ui/direct_connect_dialog.ui | 49 +------------------------ src/widgets/direct_connect_dialog.cpp | 29 ++++++++++++--- 3 files changed, 27 insertions(+), 55 deletions(-) diff --git a/include/widgets/direct_connect_dialog.h b/include/widgets/direct_connect_dialog.h index cd973c178..931752493 100644 --- a/include/widgets/direct_connect_dialog.h +++ b/include/widgets/direct_connect_dialog.h @@ -3,6 +3,7 @@ #include #include +#include class QLabel; class QSpinBox; @@ -26,9 +27,7 @@ private slots: private: NetworkManager* net_manager; - QComboBox* ui_direct_protocol_box; QLineEdit* ui_direct_hostname_edit; - QSpinBox* ui_direct_port_box; QLabel* ui_direct_connection_status_lbl; QPushButton* ui_direct_connect_button; @@ -38,6 +37,7 @@ private slots: 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/resource/ui/direct_connect_dialog.ui b/resource/ui/direct_connect_dialog.ui index 09deb32e5..3cc662079 100644 --- a/resource/ui/direct_connect_dialog.ui +++ b/resource/ui/direct_connect_dialog.ui @@ -16,57 +16,10 @@ - - - - - TCP - - - - - WS - - - - - - - - :// - - - - Hostname - - - - - - - : - - - - - - - - 50 - 0 - - - - 1 - - - 65535 - - - 80 + scheme://hostname.domain:port diff --git a/src/widgets/direct_connect_dialog.cpp b/src/widgets/direct_connect_dialog.cpp index f73cf1882..82eaa23a7 100644 --- a/src/widgets/direct_connect_dialog.cpp +++ b/src/widgets/direct_connect_dialog.cpp @@ -2,6 +2,7 @@ #include "networkmanager.h" #include "options.h" +#include "debug_functions.h" #include #include @@ -10,6 +11,9 @@ #include #include #include +#include +#include +#include #define FROM_UI(type, name) \ ; \ @@ -30,9 +34,7 @@ DirectConnectDialog::DirectConnectDialog(NetworkManager *p_net_manager) : auto l_layout = new QVBoxLayout(this); l_layout->addWidget(ui_widget); - FROM_UI(QComboBox, direct_protocol_box) FROM_UI(QLineEdit, direct_hostname_edit) - FROM_UI(QSpinBox, direct_port_box) FROM_UI(QLabel, direct_connection_status_lbl) @@ -53,10 +55,27 @@ DirectConnectDialog::DirectConnectDialog(NetworkManager *p_net_manager) : void DirectConnectDialog::onConnectPressed() { + QString l_hostname = ui_direct_hostname_edit->text(); + if (!SCHEME_PATTERN.match(l_hostname).hasMatch()) { + l_hostname = "tcp://" % l_hostname; + } + QUrl l_url(l_hostname); + if (!l_url.isValid()) { + call_error(tr("Invalid URL.")); + return; + } + 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) { + call_error(tr("Invalid server port.")); + return; + } server_type l_server; - l_server.socket_type = ui_direct_protocol_box->currentIndex() == TCP_INDEX ? TCP : WEBSOCKETS; - l_server.ip = ui_direct_hostname_edit->text(); - l_server.port = ui_direct_port_box->value(); + l_server.socket_type = to_connection_type[l_url.scheme()]; + l_server.ip = l_url.host(); + l_server.port = l_url.port(); l_server.name = "Direct Connection"; net_manager->connect_to_server(l_server); From fa01488f71f5447776bf92698a40fc81e4fb131c Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Thu, 4 May 2023 20:11:08 +0200 Subject: [PATCH 55/61] Set join text when double-click on connected server Good enough. I would handle this a bit smarter and lock based on the connection state of NetworkManager, but NetworkManager sucks and I refuse to fix it this close before 2.10.1 is done. --- src/lobby.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lobby.cpp b/src/lobby.cpp index 264f1e71d..5e0a89e3f 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -189,6 +189,8 @@ void Lobby::loadUI() 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); @@ -352,6 +354,7 @@ void Lobby::on_list_doubleclicked(QTreeWidgetItem *p_item, int column) { Q_UNUSED(p_item) Q_UNUSED(column) + ui_server_player_count_lbl->setText(tr("Joining Server...")); net_manager->join_to_server(); } From 03acc7434b55f5bde32e282d5fe3ac0a8700d533 Mon Sep 17 00:00:00 2001 From: stonedDiscord Date: Thu, 4 May 2023 22:29:19 +0200 Subject: [PATCH 56/61] remove unused m_looping --- include/aomusicplayer.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/aomusicplayer.h b/include/aomusicplayer.h index 67e6888c5..d0288443d 100644 --- a/include/aomusicplayer.h +++ b/include/aomusicplayer.h @@ -29,7 +29,6 @@ public slots: QWidget *m_parent; AOApplication *ao_app; - bool m_looping = false; bool m_muted = false; int m_volume[4] = {0, 0, 0, 0}; From e42a02c1295065f007869827bdd58b41250afb06 Mon Sep 17 00:00:00 2001 From: stonedDiscord Date: Thu, 4 May 2023 22:34:11 +0200 Subject: [PATCH 57/61] remove useless underflow check --- src/aomusicplayer.cpp | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/aomusicplayer.cpp b/src/aomusicplayer.cpp index 8abd38b6b..366335a48 100644 --- a/src/aomusicplayer.cpp +++ b/src/aomusicplayer.cpp @@ -213,20 +213,18 @@ void AOMusicPlayer::set_looping(bool loop_song, int channel) loop_sync[channel] = 0; } - if (loop_start[channel] >= 0) { - if (loop_start[channel] < 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]); - } - 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]); - } + if (loop_start[channel] < 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]); + } + 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]); } } From dbe09ebae67c86797754a2e50a79e2c02c6e1cbb Mon Sep 17 00:00:00 2001 From: stonedDiscord Date: Thu, 4 May 2023 22:35:58 +0200 Subject: [PATCH 58/61] do not fall from server to favorites --- src/lobby.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lobby.cpp b/src/lobby.cpp index 5e0a89e3f..6db0c64a2 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -79,10 +79,12 @@ int Lobby::get_selected_server() if (auto item = ui_serverlist_tree->currentItem()) { return item->text(0).toInt(); } + break; case FAVORITES: if (auto item = ui_favorites_tree->currentItem()) { return item->text(0).toInt(); } + break; default: break; } From 39d17a04bb0b845f8ab5f72dcafe31fbf6ab9316 Mon Sep 17 00:00:00 2001 From: stonedDiscord Date: Mon, 8 May 2023 14:58:48 +0200 Subject: [PATCH 59/61] Ci android fix (#899) * pro gamer move * remove pregenerated android files * version * install old ass android platform * Revert "remove pregenerated android files" This reverts commit c81a94c6fd337e187af61e9dd706fac5cd51bcc0. * switch to 24 * use android\src\android\templates instead --- android/build.gradle | 77 -------------------------------------------- 1 file changed, 77 deletions(-) delete mode 100644 android/build.gradle diff --git a/android/build.gradle b/android/build.gradle deleted file mode 100644 index 443a80024..000000000 --- a/android/build.gradle +++ /dev/null @@ -1,77 +0,0 @@ -buildscript { - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:3.6.0' - } -} - -repositories { - google() - jcenter() -} - -apply plugin: 'com.android.application' - -dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar']) -} - -android { - /******************************************************* - * The following variables: - * - androidBuildToolsVersion, - * - androidCompileSdkVersion - * - qt5AndroidDir - holds the path to qt android files - * needed to build any Qt application - * on Android. - * - * are defined in gradle.properties file. This file is - * updated by QtCreator and androiddeployqt tools. - * Changing them manually might break the compilation! - *******************************************************/ - - compileSdkVersion androidCompileSdkVersion.toInteger() - - buildToolsVersion '28.0.3' - - sourceSets { - main { - manifest.srcFile 'AndroidManifest.xml' - java.srcDirs = [qt5AndroidDir + '/src', 'src', 'java'] - aidl.srcDirs = [qt5AndroidDir + '/src', 'src', 'aidl'] - res.srcDirs = [qt5AndroidDir + '/res', 'res'] - resources.srcDirs = ['resources'] - renderscript.srcDirs = ['src'] - assets.srcDirs = ['assets'] - jniLibs.srcDirs = ['libs'] - } - } - - tasks.withType(JavaCompile) { - options.incremental = true - } - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - - lintOptions { - abortOnError false - } - - // Do not compress Qt binary resources file - aaptOptions { - noCompress 'rcc' - } - - defaultConfig { - resConfig "en" - minSdkVersion = qtMinSdkVersion - targetSdkVersion = qtTargetSdkVersion - } -} From 40de0e7914f16f6dadb2bc1155aef8c303a8faab Mon Sep 17 00:00:00 2001 From: lambdcalculus <64238778+lambdcalculus@users.noreply.github.com> Date: Sat, 13 May 2023 21:15:56 -0300 Subject: [PATCH 60/61] deprecate "chat" deskmod (#910) * ignore deskmod when zoom speaking * clean up deskmod a bit * adds an enum for deskmods * deprecates the "chat" deskmood * modifies set_scene since it never rly used the deskmod argument meaningfully * actually use the enums i made lol * fix typo --- include/courtroom.h | 2 +- include/datatypes.h | 11 +++++++ src/courtroom.cpp | 75 ++++++++++++++++++++------------------------- 3 files changed, 45 insertions(+), 43 deletions(-) diff --git a/include/courtroom.h b/include/courtroom.h index 6107a7f66..65ef75af7 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -191,7 +191,7 @@ class Courtroom : public QMainWindow { void set_pair_list(); // sets desk and bg based on pos in chatmessage - void set_scene(QString f_desk_mod, QString f_side); + 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); diff --git a/include/datatypes.h b/include/datatypes.h index 682d68a59..3a82efffe 100644 --- a/include/datatypes.h +++ b/include/datatypes.h @@ -120,6 +120,17 @@ enum EMOTE_MOD_TYPE { 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 }; #endif // DATATYPES_H diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 1d9b5a251..65c5e1a30 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -1379,9 +1379,7 @@ void Courtroom::set_background(QString p_background, bool display) QString f_side = current_side; if (current_side == "") f_side = ao_app->get_char_side(current_char); - set_scene( - QString::number(ao_app->get_desk_mod(current_char, current_emote)), - f_side); + set_scene(true, f_side); } } @@ -1838,22 +1836,21 @@ void Courtroom::on_chat_return_pressed() else f_side = current_side; - QString f_desk_mod = "chat"; + int f_desk_mod = DESK_SHOW; if (ao_app->desk_mod_supported) { - f_desk_mod = - QString::number(ao_app->get_desk_mod(current_char, current_emote)); + f_desk_mod = ao_app->get_desk_mod(current_char, current_emote); if (!ao_app->expanded_desk_mods_supported) { - if (f_desk_mod == "2" || f_desk_mod == "4") - f_desk_mod = "0"; - else if (f_desk_mod == "3" || f_desk_mod == "5") - f_desk_mod = "1"; + 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_desk_mod = "chat"; + if (f_desk_mod == -1) + f_desk_mod = DESK_SHOW; } - packet_contents.append(f_desk_mod); + packet_contents.append(QString::number(f_desk_mod)); QString f_pre = ao_app->get_pre_emote(current_char, current_emote); int f_emote_mod = ao_app->get_emote_mod(current_char, current_emote); @@ -2471,8 +2468,6 @@ void Courtroom::display_character() else { ui_vp_sticker->stop(); } - // Initialize the correct pos (called SIDE here for some reason) with DESK_MOD to determine if we should hide the desk or not. - set_scene(m_chatmessage[DESK_MOD], m_chatmessage[SIDE]); // Arrange the netstrings of the frame SFX for the character to know about if (!m_chatmessage[FRAME_SFX].isEmpty() && @@ -3475,20 +3470,20 @@ 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 4: + 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 2: - set_scene("0", m_chatmessage[SIDE]); - break; - case 5: - case 3: - set_scene("1", m_chatmessage[SIDE]); + case DESK_EMOTE_ONLY: + case DESK_HIDE: + set_scene(false, m_chatmessage[SIDE]); break; - default: - set_scene(m_chatmessage[DESK_MOD], m_chatmessage[SIDE]); + + case DESK_PRE_ONLY_EX: + case DESK_PRE_ONLY: + case DESK_SHOW: + set_scene(true, m_chatmessage[SIDE]); break; } @@ -3526,21 +3521,21 @@ void Courtroom::start_chat_ticking() // handle expanded desk mods switch(m_chatmessage[DESK_MOD].toInt()) { - case 4: + case DESK_EMOTE_ONLY_EX: set_self_offset(m_chatmessage[SELF_OFFSET]); [[fallthrough]]; - case 2: - set_scene("1", m_chatmessage[SIDE]); + case DESK_EMOTE_ONLY: + case DESK_SHOW: + set_scene(true, m_chatmessage[SIDE]); break; - case 5: + + case DESK_PRE_ONLY_EX: ui_vp_sideplayer_char->hide(); ui_vp_player_char->move_and_center(0, 0); [[fallthrough]]; - case 3: - set_scene("0", m_chatmessage[SIDE]); - break; - default: - set_scene(m_chatmessage[DESK_MOD], m_chatmessage[SIDE]); + case DESK_PRE_ONLY: + case DESK_HIDE: + set_scene(false, m_chatmessage[SIDE]); break; } @@ -3912,19 +3907,15 @@ void Courtroom::play_sfx() ao_app->get_sfx_looping(current_char, current_emote) == "1"); } -void Courtroom::set_scene(const QString f_desk_mod, const QString f_side) +void Courtroom::set_scene(bool show_desk, const QString f_side) { ui_vp_background->load_image(ao_app->get_pos_path(f_side)); ui_vp_desk->load_image(ao_app->get_pos_path(f_side, true)); - if (f_desk_mod == "0" || - (f_desk_mod != "1" && - (f_side == "jud" || f_side == "hld" || f_side == "hlp"))) { - ui_vp_desk->hide(); - } - else { + if (show_desk) ui_vp_desk->show(); - } + else + ui_vp_desk->hide(); } void Courtroom::set_self_offset(const QString& p_list) { From 548ae8c1a32193ff46faa726cb86e92d030cfffb Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Fri, 26 May 2023 11:31:05 +0200 Subject: [PATCH 61/61] Add credits for lamdacalculus --- src/lobby.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/lobby.cpp b/src/lobby.cpp index 6db0c64a2..a705b262c 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -191,8 +191,9 @@ void Lobby::loadUI() 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(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); @@ -286,7 +287,7 @@ void Lobby::on_about_clicked() "OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, " "Crystalwarrior, Iamgoofball, in1tiate" "

Client development:
" - "Cents02, windrammer, skyedeving, TrickyLeifa, Salanto" + "Cents02, windrammer, skyedeving, TrickyLeifa, Salanto, lambdcalculus" "

QA testing:
" "CaseyCazy, CedricDewitt, Chewable Tablets, CrazyJC, Fantos, " "Fury McFlurry, Geck, Gin-Gi, Jamania, Minx, Pandae, "