From 77694d76e843c55f11aa488baa7b33ca42a41c4e Mon Sep 17 00:00:00 2001 From: VodBox Date: Sat, 3 Jul 2021 17:55:47 +1200 Subject: [PATCH] UI: Add Accessibility menu to settings This change introduces an accessibility menu to settings, along with options for overriding the colors used by OBS in the mixer and in the preview to be more color blind friendly than the options provided by the current theme. --- UI/CMakeLists.txt | 1 + UI/data/locale/en-US.ini | 17 + UI/data/themes/Dark.qss | 1 + .../themes/Dark/settings/accessibility.svg | 1 + UI/data/themes/Yami.qss | 1 + UI/forms/OBSBasicSettings.ui | 1164 +++++++++++++++++ UI/forms/images/settings/accessibility.svg | 1 + UI/forms/obs.qrc | 1 + UI/volume-control.cpp | 97 +- UI/volume-control.hpp | 9 + UI/window-basic-main.cpp | 46 + UI/window-basic-main.hpp | 10 + UI/window-basic-preview.cpp | 21 +- UI/window-basic-settings-a11y.cpp | 398 ++++++ UI/window-basic-settings.cpp | 30 +- UI/window-basic-settings.hpp | 39 +- 16 files changed, 1816 insertions(+), 21 deletions(-) create mode 100644 UI/data/themes/Dark/settings/accessibility.svg create mode 100644 UI/forms/images/settings/accessibility.svg create mode 100644 UI/window-basic-settings-a11y.cpp diff --git a/UI/CMakeLists.txt b/UI/CMakeLists.txt index 8e25b0d6c..b94b03b8d 100644 --- a/UI/CMakeLists.txt +++ b/UI/CMakeLists.txt @@ -247,6 +247,7 @@ target_sources( window-basic-properties.hpp window-basic-settings.cpp window-basic-settings.hpp + window-basic-settings-a11y.cpp window-basic-settings-stream.cpp window-basic-source-select.cpp window-basic-source-select.hpp diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini index 3403d966c..cf64f902f 100644 --- a/UI/data/locale/en-US.ini +++ b/UI/data/locale/en-US.ini @@ -1060,6 +1060,23 @@ Basic.Settings.Audio.LowLatencyBufferingWarning="Low latency audio buffering mod Basic.Settings.Audio.LowLatencyBufferingWarning.Title="Enable low latency audio buffering mode?" Basic.Settings.Audio.LowLatencyBufferingWarning.Confirm="Are you sure you want to enable low latency audio buffering mode?" +# basic mode 'accessibility' settings +Basic.Settings.Accessibility="Accessibility" +Basic.Settings.Accessibility.ColorOverrides="Use Different Colors" +Basic.Settings.Accessibility.ColorOverrides.SelectRed="Source Border (Selection)" +Basic.Settings.Accessibility.ColorOverrides.SelectGreen="Source Border (Crop)" +Basic.Settings.Accessibility.ColorOverrides.SelectBlue="Source Border (Hover)" +Basic.Settings.Accessibility.ColorOverrides.MixerGreen="Mixer Volume Band (-60 to -20dB)" +Basic.Settings.Accessibility.ColorOverrides.MixerYellow="Mixer Volume Band (-20 to -9dB)" +Basic.Settings.Accessibility.ColorOverrides.MixerRed="Mixer Volume Band (-9 to 0dB)" +Basic.Settings.Accessibility.ColorOverrides.MixerGreenActive="Mixer Volume Band (-60 to -20dB) (active)" +Basic.Settings.Accessibility.ColorOverrides.MixerYellowActive="Mixer Volume Band (-20 to -9dB) (active)" +Basic.Settings.Accessibility.ColorOverrides.MixerRedActive="Mixer Volume Band (-9 to 0dB) (active)" +Basic.Settings.Accessibility.ColorOverrides.Preset="Color Preset" +Basic.Settings.Accessibility.ColorOverrides.Preset.Default="Default" +Basic.Settings.Accessibility.ColorOverrides.Preset.Custom="Custom" +Basic.Settings.Accessibility.ColorOverrides.Preset.ColorBlind1="Color Blind Alternative" + # basic mode 'advanced' settings Basic.Settings.Advanced="Advanced" Basic.Settings.Advanced.General.ConfirmOnExit="Show active outputs warning on exit" diff --git a/UI/data/themes/Dark.qss b/UI/data/themes/Dark.qss index 5c95fa857..51ac1ac65 100644 --- a/UI/data/themes/Dark.qss +++ b/UI/data/themes/Dark.qss @@ -737,6 +737,7 @@ OBSBasicSettings { qproperty-audioIcon: url(./Dark/settings/audio.svg); qproperty-videoIcon: url(./Dark/settings/video.svg); qproperty-hotkeysIcon: url(./Dark/settings/hotkeys.svg); + qproperty-accessibilityIcon: url(./Dark/settings/accessibility.svg); qproperty-advancedIcon: url(./Dark/settings/advanced.svg); } diff --git a/UI/data/themes/Dark/settings/accessibility.svg b/UI/data/themes/Dark/settings/accessibility.svg new file mode 100644 index 000000000..a630eb49e --- /dev/null +++ b/UI/data/themes/Dark/settings/accessibility.svg @@ -0,0 +1 @@ + diff --git a/UI/data/themes/Yami.qss b/UI/data/themes/Yami.qss index 4ed932da9..b1ba69aaa 100644 --- a/UI/data/themes/Yami.qss +++ b/UI/data/themes/Yami.qss @@ -1022,6 +1022,7 @@ OBSBasicSettings { qproperty-audioIcon: url(./Dark/settings/audio.svg); qproperty-videoIcon: url(./Dark/settings/video.svg); qproperty-hotkeysIcon: url(./Dark/settings/hotkeys.svg); + qproperty-accessibilityIcon: url(./Dark/settings/accessibility.svg); qproperty-advancedIcon: url(./Dark/settings/advanced.svg); } diff --git a/UI/forms/OBSBasicSettings.ui b/UI/forms/OBSBasicSettings.ui index 46a56d68e..2bc6ef245 100644 --- a/UI/forms/OBSBasicSettings.ui +++ b/UI/forms/OBSBasicSettings.ui @@ -105,6 +105,15 @@ :/settings/images/settings/hotkeys.svg:/settings/images/settings/hotkeys.svg + + + Basic.Settings.Accessibility + + + + :/settings/images/settings/accessibility.svg:/settings/images/settings/accessibility.svg + + Basic.Settings.Advanced @@ -4881,6 +4890,1161 @@ + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Plain + + + true + + + + + 0 + 0 + 820 + 677 + + + + + 0 + + + 0 + + + 0 + + + 9 + + + + + + + + 0 + 0 + + + + Basic.Settings.Accessibility.ColorOverrides + + + true + + + false + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 2 + + + + + Basic.Settings.Accessibility.ColorOverrides.Preset + + + colorPreset + + + + + + + + Basic.Settings.Accessibility.ColorOverrides.Preset.Default + + + + + Basic.Settings.Accessibility.ColorOverrides.Preset.ColorBlind1 + + + + + Basic.Settings.Accessibility.ColorOverrides.Preset.Custom + + + + + + + + Basic.Settings.Accessibility.ColorOverrides.SelectRed + + + colorSelect1 + + + + + + + + 0 + 0 + 565 + 22 + + + + + 0 + 0 + + + + + 0 + 22 + + + + + 16777215 + 16777215 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 80 + 22 + + + + + 16777215 + 22 + + + + color here + + + Qt::AlignCenter + + + + + + + + 0 + 22 + + + + + 16777215 + 22 + + + + Basic.PropertiesWindow.SelectColor + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Basic.Settings.Accessibility.ColorOverrides.SelectGreen + + + colorSelect2 + + + + + + + + 0 + 0 + 565 + 22 + + + + + 0 + 0 + + + + + 0 + 22 + + + + + 16777215 + 16777215 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 80 + 22 + + + + + 16777215 + 22 + + + + color here + + + Qt::AlignCenter + + + + + + + + 0 + 22 + + + + + 16777215 + 22 + + + + Basic.PropertiesWindow.SelectColor + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Basic.Settings.Accessibility.ColorOverrides.SelectBlue + + + colorSelect3 + + + + + + + + 0 + 0 + 565 + 22 + + + + + 0 + 0 + + + + + 0 + 22 + + + + + 16777215 + 16777215 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 80 + 22 + + + + + 16777215 + 22 + + + + color here + + + Qt::AlignCenter + + + + + + + + 0 + 22 + + + + + 16777215 + 22 + + + + Basic.PropertiesWindow.SelectColor + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Basic.Settings.Accessibility.ColorOverrides.MixerGreen + + + colorSelect4 + + + + + + + + 0 + 0 + 565 + 22 + + + + + 0 + 0 + + + + + 0 + 22 + + + + + 16777215 + 16777215 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 80 + 22 + + + + + 16777215 + 22 + + + + color here + + + Qt::AlignCenter + + + + + + + + 0 + 22 + + + + + 16777215 + 22 + + + + Basic.PropertiesWindow.SelectColor + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Basic.Settings.Accessibility.ColorOverrides.MixerYellow + + + colorSelect5 + + + + + + + + 0 + 0 + 565 + 22 + + + + + 0 + 0 + + + + + 0 + 22 + + + + + 16777215 + 16777215 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 80 + 22 + + + + + 16777215 + 22 + + + + color here + + + Qt::AlignCenter + + + + + + + + 0 + 22 + + + + + 16777215 + 22 + + + + Basic.PropertiesWindow.SelectColor + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Basic.Settings.Accessibility.ColorOverrides.MixerRed + + + colorSelect6 + + + + + + + + 0 + 0 + 565 + 22 + + + + + 0 + 0 + + + + + 0 + 22 + + + + + 16777215 + 16777215 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 80 + 22 + + + + + 16777215 + 22 + + + + color here + + + Qt::AlignCenter + + + + + + + + 0 + 22 + + + + + 16777215 + 22 + + + + Basic.PropertiesWindow.SelectColor + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Basic.Settings.Accessibility.ColorOverrides.MixerGreenActive + + + colorSelect7 + + + + + + + + 0 + 0 + 565 + 22 + + + + + 0 + 0 + + + + + 0 + 22 + + + + + 16777215 + 16777215 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 80 + 22 + + + + + 16777215 + 22 + + + + color here + + + Qt::AlignCenter + + + + + + + + 0 + 22 + + + + + 16777215 + 22 + + + + Basic.PropertiesWindow.SelectColor + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Basic.Settings.Accessibility.ColorOverrides.MixerYellowActive + + + colorSelect8 + + + + + + + + 0 + 0 + 565 + 22 + + + + + 0 + 0 + + + + + 0 + 22 + + + + + 16777215 + 16777215 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 80 + 22 + + + + + 16777215 + 22 + + + + color here + + + Qt::AlignCenter + + + + + + + + 0 + 22 + + + + + 16777215 + 22 + + + + Basic.PropertiesWindow.SelectColor + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Basic.Settings.Accessibility.ColorOverrides.MixerRedActive + + + colorSelect9 + + + + + + + + 0 + 0 + 565 + 22 + + + + + 0 + 0 + + + + + 0 + 22 + + + + + 16777215 + 16777215 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 80 + 22 + + + + + 16777215 + 22 + + + + color here + + + Qt::AlignCenter + + + + + + + + 0 + 22 + + + + + 16777215 + 22 + + + + Basic.PropertiesWindow.SelectColor + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 40 + + + + + + + + + + + + diff --git a/UI/forms/images/settings/accessibility.svg b/UI/forms/images/settings/accessibility.svg new file mode 100644 index 000000000..1587b8933 --- /dev/null +++ b/UI/forms/images/settings/accessibility.svg @@ -0,0 +1 @@ + diff --git a/UI/forms/obs.qrc b/UI/forms/obs.qrc index f3b275ddf..977cfa39d 100644 --- a/UI/forms/obs.qrc +++ b/UI/forms/obs.qrc @@ -70,5 +70,6 @@ images/settings/audio.svg images/settings/general.svg images/settings/hotkeys.svg + images/settings/accessibility.svg diff --git a/UI/volume-control.cpp b/UI/volume-control.cpp index 9102016d9..67e128995 100644 --- a/UI/volume-control.cpp +++ b/UI/volume-control.cpp @@ -336,9 +336,18 @@ VolControl::~VolControl() contextMenu->close(); } +static inline QColor color_from_int(long long val) +{ + QColor color(val & 0xff, (val >> 8) & 0xff, (val >> 16) & 0xff, + (val >> 24) & 0xff); + color.setAlpha(255); + + return color; +} + QColor VolumeMeter::getBackgroundNominalColor() const { - return backgroundNominalColor; + return p_backgroundNominalColor; } QColor VolumeMeter::getBackgroundNominalColorDisabled() const @@ -348,7 +357,15 @@ QColor VolumeMeter::getBackgroundNominalColorDisabled() const void VolumeMeter::setBackgroundNominalColor(QColor c) { - backgroundNominalColor = std::move(c); + p_backgroundNominalColor = std::move(c); + + if (config_get_bool(GetGlobalConfig(), "Accessibility", + "OverrideColors")) { + backgroundNominalColor = color_from_int(config_get_int( + GetGlobalConfig(), "Accessibility", "MixerGreen")); + } else { + backgroundNominalColor = p_backgroundNominalColor; + } } void VolumeMeter::setBackgroundNominalColorDisabled(QColor c) @@ -358,7 +375,7 @@ void VolumeMeter::setBackgroundNominalColorDisabled(QColor c) QColor VolumeMeter::getBackgroundWarningColor() const { - return backgroundWarningColor; + return p_backgroundWarningColor; } QColor VolumeMeter::getBackgroundWarningColorDisabled() const @@ -368,7 +385,15 @@ QColor VolumeMeter::getBackgroundWarningColorDisabled() const void VolumeMeter::setBackgroundWarningColor(QColor c) { - backgroundWarningColor = std::move(c); + p_backgroundWarningColor = std::move(c); + + if (config_get_bool(GetGlobalConfig(), "Accessibility", + "OverrideColors")) { + backgroundWarningColor = color_from_int(config_get_int( + GetGlobalConfig(), "Accessibility", "MixerYellow")); + } else { + backgroundWarningColor = p_backgroundWarningColor; + } } void VolumeMeter::setBackgroundWarningColorDisabled(QColor c) @@ -378,7 +403,7 @@ void VolumeMeter::setBackgroundWarningColorDisabled(QColor c) QColor VolumeMeter::getBackgroundErrorColor() const { - return backgroundErrorColor; + return p_backgroundErrorColor; } QColor VolumeMeter::getBackgroundErrorColorDisabled() const @@ -388,7 +413,15 @@ QColor VolumeMeter::getBackgroundErrorColorDisabled() const void VolumeMeter::setBackgroundErrorColor(QColor c) { - backgroundErrorColor = std::move(c); + p_backgroundErrorColor = std::move(c); + + if (config_get_bool(GetGlobalConfig(), "Accessibility", + "OverrideColors")) { + backgroundErrorColor = color_from_int(config_get_int( + GetGlobalConfig(), "Accessibility", "MixerRed")); + } else { + backgroundErrorColor = p_backgroundErrorColor; + } } void VolumeMeter::setBackgroundErrorColorDisabled(QColor c) @@ -398,7 +431,7 @@ void VolumeMeter::setBackgroundErrorColorDisabled(QColor c) QColor VolumeMeter::getForegroundNominalColor() const { - return foregroundNominalColor; + return p_foregroundNominalColor; } QColor VolumeMeter::getForegroundNominalColorDisabled() const @@ -408,7 +441,16 @@ QColor VolumeMeter::getForegroundNominalColorDisabled() const void VolumeMeter::setForegroundNominalColor(QColor c) { - foregroundNominalColor = std::move(c); + p_foregroundNominalColor = std::move(c); + + if (config_get_bool(GetGlobalConfig(), "Accessibility", + "OverrideColors")) { + foregroundNominalColor = color_from_int( + config_get_int(GetGlobalConfig(), "Accessibility", + "MixerGreenActive")); + } else { + foregroundNominalColor = p_foregroundNominalColor; + } } void VolumeMeter::setForegroundNominalColorDisabled(QColor c) @@ -418,7 +460,7 @@ void VolumeMeter::setForegroundNominalColorDisabled(QColor c) QColor VolumeMeter::getForegroundWarningColor() const { - return foregroundWarningColor; + return p_foregroundWarningColor; } QColor VolumeMeter::getForegroundWarningColorDisabled() const @@ -428,7 +470,16 @@ QColor VolumeMeter::getForegroundWarningColorDisabled() const void VolumeMeter::setForegroundWarningColor(QColor c) { - foregroundWarningColor = std::move(c); + p_foregroundWarningColor = std::move(c); + + if (config_get_bool(GetGlobalConfig(), "Accessibility", + "OverrideColors")) { + foregroundWarningColor = color_from_int( + config_get_int(GetGlobalConfig(), "Accessibility", + "MixerYellowActive")); + } else { + foregroundWarningColor = p_foregroundWarningColor; + } } void VolumeMeter::setForegroundWarningColorDisabled(QColor c) @@ -438,7 +489,7 @@ void VolumeMeter::setForegroundWarningColorDisabled(QColor c) QColor VolumeMeter::getForegroundErrorColor() const { - return foregroundErrorColor; + return p_foregroundErrorColor; } QColor VolumeMeter::getForegroundErrorColorDisabled() const @@ -448,7 +499,15 @@ QColor VolumeMeter::getForegroundErrorColorDisabled() const void VolumeMeter::setForegroundErrorColor(QColor c) { - foregroundErrorColor = std::move(c); + p_foregroundErrorColor = std::move(c); + + if (config_get_bool(GetGlobalConfig(), "Accessibility", + "OverrideColors")) { + foregroundErrorColor = color_from_int(config_get_int( + GetGlobalConfig(), "Accessibility", "MixerRedActive")); + } else { + foregroundErrorColor = p_foregroundErrorColor; + } } void VolumeMeter::setForegroundErrorColorDisabled(QColor c) @@ -518,6 +577,20 @@ void VolumeMeter::setMeterFontScaling(qreal v) recalculateLayout = true; } +void VolControl::refreshColors() +{ + volMeter->setBackgroundNominalColor( + volMeter->getBackgroundNominalColor()); + volMeter->setBackgroundWarningColor( + volMeter->getBackgroundWarningColor()); + volMeter->setBackgroundErrorColor(volMeter->getBackgroundErrorColor()); + volMeter->setForegroundNominalColor( + volMeter->getForegroundNominalColor()); + volMeter->setForegroundWarningColor( + volMeter->getForegroundWarningColor()); + volMeter->setForegroundErrorColor(volMeter->getForegroundErrorColor()); +} + qreal VolumeMeter::getMinimumLevel() const { return minimumLevel; diff --git a/UI/volume-control.hpp b/UI/volume-control.hpp index ceceebcbf..45ef608a7 100644 --- a/UI/volume-control.hpp +++ b/UI/volume-control.hpp @@ -168,6 +168,13 @@ private: qreal peakHoldDuration; qreal inputPeakHoldDuration; + QColor p_backgroundNominalColor; + QColor p_backgroundWarningColor; + QColor p_backgroundErrorColor; + QColor p_foregroundNominalColor; + QColor p_foregroundWarningColor; + QColor p_foregroundErrorColor; + uint64_t lastRedrawTime = 0; int channels = 0; bool clipping = false; @@ -322,4 +329,6 @@ public: void EnableSlider(bool enable); inline void SetContextMenu(QMenu *cm) { contextMenu = cm; } + + void refreshColors(); }; diff --git a/UI/window-basic-main.cpp b/UI/window-basic-main.cpp index e9cf9075c..e66ca53e7 100644 --- a/UI/window-basic-main.cpp +++ b/UI/window-basic-main.cpp @@ -623,6 +623,13 @@ void OBSBasic::ClearVolumeControls() volumes.clear(); } +void OBSBasic::RefreshVolumeColors() +{ + for (VolControl *vol : volumes) { + vol->refreshColors(); + } +} + obs_data_array_t *OBSBasic::SaveSceneListOrder() { obs_data_array_t *sceneOrder = obs_data_array_create(); @@ -10099,3 +10106,42 @@ void OBSBasic::SetDisplayAffinity(QWindow *window) UNUSED_PARAMETER(hideFromCapture); #endif } + +static inline QColor color_from_int(long long val) +{ + return QColor(val & 0xff, (val >> 8) & 0xff, (val >> 16) & 0xff, + (val >> 24) & 0xff); +} + +QColor OBSBasic::GetSelectionColor() const +{ + if (config_get_bool(GetGlobalConfig(), "Accessibility", + "OverrideColors")) { + return color_from_int(config_get_int( + GetGlobalConfig(), "Accessibility", "SelectRed")); + } else { + return QColor::fromRgb(255, 0, 0); + } +} + +QColor OBSBasic::GetCropColor() const +{ + if (config_get_bool(GetGlobalConfig(), "Accessibility", + "OverrideColors")) { + return color_from_int(config_get_int( + GetGlobalConfig(), "Accessibility", "SelectGreen")); + } else { + return QColor::fromRgb(0, 255, 0); + } +} + +QColor OBSBasic::GetHoverColor() const +{ + if (config_get_bool(GetGlobalConfig(), "Accessibility", + "OverrideColors")) { + return color_from_int(config_get_int( + GetGlobalConfig(), "Accessibility", "SelectBlue")); + } else { + return QColor::fromRgb(0, 127, 255); + } +} diff --git a/UI/window-basic-main.hpp b/UI/window-basic-main.hpp index 3dee95a4a..3e9695f2a 100644 --- a/UI/window-basic-main.hpp +++ b/UI/window-basic-main.hpp @@ -624,6 +624,14 @@ private: void CenterSelectedSceneItems(const CenterType ¢erType); void ShowMissingFilesDialog(obs_missing_files_t *files); + QColor selectionColor; + QColor cropColor; + QColor hoverColor; + + QColor GetSelectionColor() const; + QColor GetCropColor() const; + QColor GetHoverColor() const; + public slots: void DeferSaveBegin(); void DeferSaveEnd(); @@ -866,6 +874,8 @@ public: void AddVCamButton(); void ResetOutputs(); + void RefreshVolumeColors(); + void ResetAudioDevice(const char *sourceId, const char *deviceId, const char *deviceDesc, int channel); diff --git a/UI/window-basic-preview.cpp b/UI/window-basic-preview.cpp index adfb8a44b..ee58d10f5 100644 --- a/UI/window-basic-preview.cpp +++ b/UI/window-basic-preview.cpp @@ -1829,13 +1829,22 @@ bool OBSBasicPreview::DrawSelectedItem(obs_scene_t *scene, {{{1.f, 1.f, 0.f}}}, }; + main->GetCameraIcon(); + + QColor selColor = main->GetSelectionColor(); + QColor cropColor = main->GetCropColor(); + QColor hoverColor = main->GetHoverColor(); + vec4 red; vec4 green; vec4 blue; - vec4_set(&red, 1.0f, 0.0f, 0.0f, 1.0f); - vec4_set(&green, 0.0f, 1.0f, 0.0f, 1.0f); - vec4_set(&blue, 0.0f, 0.5f, 1.0f, 1.0f); + vec4_set(&red, selColor.redF(), selColor.greenF(), selColor.blueF(), + 1.0f); + vec4_set(&green, cropColor.redF(), cropColor.greenF(), + cropColor.blueF(), 1.0f); + vec4_set(&blue, hoverColor.redF(), hoverColor.greenF(), + hoverColor.blueF(), 1.0f); bool visible = std::all_of( std::begin(bounds), std::end(bounds), [&](const vec3 &b) { @@ -1869,6 +1878,8 @@ bool OBSBasicPreview::DrawSelectedItem(obs_scene_t *scene, gs_effect_t *eff = gs_get_effect(); gs_eparam_t *colParam = gs_effect_get_param_by_name(eff, "color"); + gs_effect_set_vec4(colParam, &red); + if (info.bounds_type == OBS_BOUNDS_NONE && crop_enabled(&crop)) { #define DRAW_SIDE(side, x1, y1, x2, y2) \ if (hovered && !selected) { \ @@ -2003,10 +2014,6 @@ void OBSBasicPreview::DrawSceneEditing() gs_effect_t *solid = obs_get_base_effect(OBS_EFFECT_SOLID); gs_technique_t *tech = gs_effect_get_technique(solid, "Solid"); - vec4 color; - vec4_set(&color, 1.0f, 0.0f, 0.0f, 1.0f); - gs_effect_set_vec4(gs_effect_get_param_by_name(solid, "color"), &color); - gs_technique_begin(tech); gs_technique_begin_pass(tech, 0); diff --git a/UI/window-basic-settings-a11y.cpp b/UI/window-basic-settings-a11y.cpp new file mode 100644 index 000000000..136e36ee5 --- /dev/null +++ b/UI/window-basic-settings-a11y.cpp @@ -0,0 +1,398 @@ +#include "window-basic-settings.hpp" +#include "window-basic-main.hpp" +#include "obs-frontend-api.h" +#include "obs-app.hpp" +#include "qt-wrappers.hpp" +#include + +#define I18nStr(str) QTStr(str).toStdString().c_str() + +enum ColorPreset { + COLOR_PRESET_DEFAULT, + COLOR_PRESET_COLOR_BLIND_1, + COLOR_PRESET_CUSTOM = 99, +}; + +static inline bool WidgetChanged(QWidget *widget) +{ + return widget->property("changed").toBool(); +} + +static inline QColor color_from_int(long long val) +{ + return QColor(val & 0xff, (val >> 8) & 0xff, (val >> 16) & 0xff, + (val >> 24) & 0xff); +} + +static inline long long color_to_int(QColor color) +{ + auto shift = [&](unsigned val, int shift) { + return ((val & 0xff) << shift); + }; + + return shift(color.red(), 0) | shift(color.green(), 8) | + shift(color.blue(), 16) | shift(color.alpha(), 24); +} + +QColor OBSBasicSettings::GetColor(uint32_t colorVal, QString label) +{ + QColorDialog::ColorDialogOptions options; + +#ifndef _WIN32 + options |= QColorDialog::DontUseNativeDialog; +#endif + + QColor color = color_from_int(colorVal); + + return QColorDialog::getColor(color, this, label, options); +} + +void OBSBasicSettings::LoadA11ySettings(bool presetChange) +{ + config_t *config = GetGlobalConfig(); + + if (!presetChange) { + preset = config_get_int(config, "Accessibility", "ColorPreset"); + + bool block = ui->colorPreset->blockSignals(true); + ui->colorPreset->setCurrentIndex(std::min( + preset, (uint32_t)ui->colorPreset->count() - 1)); + ui->colorPreset->blockSignals(block); + + bool checked = config_get_bool(config, "Accessibility", + "OverrideColors"); + + ui->colorsGroupBox->setChecked(checked); + } + + if (preset == COLOR_PRESET_DEFAULT) { + ResetDefaultColors(); + SetDefaultColors(); + } else if (preset == COLOR_PRESET_COLOR_BLIND_1) { + ResetDefaultColors(); + + mixerGreenActive = 0x742E94; + mixerGreen = 0x4A1A60; + mixerYellowActive = 0x3349F9; + mixerYellow = 0x1F2C97; + mixerRedActive = 0xBEAC63; + mixerRed = 0x675B28; + + selectRed = 0x3349F9; + selectGreen = 0xFF56C9; + selectBlue = 0xB09B44; + + SetDefaultColors(); + } else if (preset == COLOR_PRESET_CUSTOM) { + SetDefaultColors(); + + selectRed = + config_get_int(config, "Accessibility", "SelectRed"); + selectGreen = + config_get_int(config, "Accessibility", "SelectGreen"); + selectBlue = + config_get_int(config, "Accessibility", "SelectBlue"); + + mixerGreen = + config_get_int(config, "Accessibility", "MixerGreen"); + mixerYellow = + config_get_int(config, "Accessibility", "MixerYellow"); + mixerRed = config_get_int(config, "Accessibility", "MixerRed"); + + mixerGreenActive = config_get_int(config, "Accessibility", + "MixerGreenActive"); + mixerYellowActive = config_get_int(config, "Accessibility", + "MixerYellowActive"); + mixerRedActive = config_get_int(config, "Accessibility", + "MixerRedActive"); + } + + UpdateA11yColors(); +} + +void OBSBasicSettings::SaveA11ySettings() +{ + config_t *config = GetGlobalConfig(); + + config_set_bool(config, "Accessibility", "OverrideColors", + ui->colorsGroupBox->isChecked()); + config_set_int(config, "Accessibility", "ColorPreset", preset); + + config_set_int(config, "Accessibility", "SelectRed", selectRed); + config_set_int(config, "Accessibility", "SelectGreen", selectGreen); + config_set_int(config, "Accessibility", "SelectBlue", selectBlue); + config_set_int(config, "Accessibility", "MixerGreen", mixerGreen); + config_set_int(config, "Accessibility", "MixerYellow", mixerYellow); + config_set_int(config, "Accessibility", "MixerRed", mixerRed); + config_set_int(config, "Accessibility", "MixerGreenActive", + mixerGreenActive); + config_set_int(config, "Accessibility", "MixerYellowActive", + mixerYellowActive); + config_set_int(config, "Accessibility", "MixerRedActive", + mixerRedActive); + + main->RefreshVolumeColors(); +} + +#define SetStyle(label, colorVal) \ + color = color_from_int(colorVal); \ + color.setAlpha(255); \ + palette = QPalette(color); \ + label->setFrameStyle(QFrame::Sunken | QFrame::Panel); \ + label->setText(color.name(QColor::HexRgb)); \ + label->setPalette(palette); \ + label->setStyleSheet(QString("background-color: %1; color: %2;") \ + .arg(palette.color(QPalette::Window) \ + .name(QColor::HexRgb)) \ + .arg(palette.color(QPalette::WindowText) \ + .name(QColor::HexRgb))); \ + label->setAutoFillBackground(true); \ + label->setAlignment(Qt::AlignCenter); + +void OBSBasicSettings::UpdateA11yColors() +{ + QPalette palette; + QColor color; + + SetStyle(ui->color1, selectRed); + SetStyle(ui->color2, selectGreen); + SetStyle(ui->color3, selectBlue); + SetStyle(ui->color4, mixerGreen); + SetStyle(ui->color5, mixerYellow); + SetStyle(ui->color6, mixerRed); + SetStyle(ui->color7, mixerGreenActive); + SetStyle(ui->color8, mixerYellowActive); + SetStyle(ui->color9, mixerRedActive); +} + +void OBSBasicSettings::SetDefaultColors() +{ + config_t *config = GetGlobalConfig(); + config_set_default_int(config, "Accessibility", "SelectRed", selectRed); + config_set_default_int(config, "Accessibility", "SelectGreen", + selectGreen); + config_set_default_int(config, "Accessibility", "SelectBlue", + selectBlue); + + config_set_default_int(config, "Accessibility", "MixerGreen", + mixerGreen); + config_set_default_int(config, "Accessibility", "MixerYellow", + mixerYellow); + config_set_default_int(config, "Accessibility", "MixerRed", mixerRed); + + config_set_default_int(config, "Accessibility", "MixerGreenActive", + mixerGreenActive); + config_set_default_int(config, "Accessibility", "MixerYellowActive", + mixerYellowActive); + config_set_default_int(config, "Accessibility", "MixerRedActive", + mixerRedActive); +} + +void OBSBasicSettings::ResetDefaultColors() +{ + selectRed = 0x0000FF; + selectGreen = 0x00FF00; + selectBlue = 0xFF7F00; + mixerGreen = 0x267f26; + mixerYellow = 0x267f7f; + mixerRed = 0x26267f; + mixerGreenActive = 0x4cff4c; + mixerYellowActive = 0x4cffff; + mixerRedActive = 0x4c4cff; +} + +void OBSBasicSettings::on_colorPreset_currentIndexChanged(int idx) +{ + preset = idx == ui->colorPreset->count() - 1 ? COLOR_PRESET_CUSTOM + : idx; + LoadA11ySettings(true); +} + +void OBSBasicSettings::on_choose1_clicked() +{ + QColor color = GetColor( + selectRed, + QTStr("Basic.Settings.Accessibility.ColorOverrides.SelectRed")); + + if (!color.isValid()) + return; + + selectRed = color_to_int(color); + + preset = COLOR_PRESET_CUSTOM; + bool block = ui->colorPreset->blockSignals(true); + ui->colorPreset->setCurrentIndex(ui->colorPreset->count() - 1); + ui->colorPreset->blockSignals(block); + + A11yChanged(); + + UpdateA11yColors(); +} + +void OBSBasicSettings::on_choose2_clicked() +{ + QColor color = GetColor( + selectGreen, + QTStr("Basic.Settings.Accessibility.ColorOverrides.SelectGreen")); + + if (!color.isValid()) + return; + + selectGreen = color_to_int(color); + + preset = COLOR_PRESET_CUSTOM; + bool block = ui->colorPreset->blockSignals(true); + ui->colorPreset->setCurrentIndex(ui->colorPreset->count() - 1); + ui->colorPreset->blockSignals(block); + + A11yChanged(); + + UpdateA11yColors(); +} + +void OBSBasicSettings::on_choose3_clicked() +{ + QColor color = GetColor( + selectBlue, + QTStr("Basic.Settings.Accessibility.ColorOverrides.SelectBlue")); + + if (!color.isValid()) + return; + + selectBlue = color_to_int(color); + + preset = COLOR_PRESET_CUSTOM; + bool block = ui->colorPreset->blockSignals(true); + ui->colorPreset->setCurrentIndex(ui->colorPreset->count() - 1); + ui->colorPreset->blockSignals(block); + + A11yChanged(); + + UpdateA11yColors(); +} + +void OBSBasicSettings::on_choose4_clicked() +{ + QColor color = GetColor( + mixerGreen, + QTStr("Basic.Settings.Accessibility.ColorOverrides.MixerGreen")); + + if (!color.isValid()) + return; + + mixerGreen = color_to_int(color); + + preset = COLOR_PRESET_CUSTOM; + bool block = ui->colorPreset->blockSignals(true); + ui->colorPreset->setCurrentIndex(ui->colorPreset->count() - 1); + ui->colorPreset->blockSignals(block); + + A11yChanged(); + + UpdateA11yColors(); +} + +void OBSBasicSettings::on_choose5_clicked() +{ + QColor color = GetColor( + mixerYellow, + QTStr("Basic.Settings.Accessibility.ColorOverrides.MixerYellow")); + + if (!color.isValid()) + return; + + mixerYellow = color_to_int(color); + + preset = COLOR_PRESET_CUSTOM; + bool block = ui->colorPreset->blockSignals(true); + ui->colorPreset->setCurrentIndex(ui->colorPreset->count() - 1); + ui->colorPreset->blockSignals(block); + + A11yChanged(); + + UpdateA11yColors(); +} + +void OBSBasicSettings::on_choose6_clicked() +{ + QColor color = GetColor( + mixerRed, + QTStr("Basic.Settings.Accessibility.ColorOverrides.MixerRed")); + + if (!color.isValid()) + return; + + mixerRed = color_to_int(color); + + preset = COLOR_PRESET_CUSTOM; + bool block = ui->colorPreset->blockSignals(true); + ui->colorPreset->setCurrentIndex(ui->colorPreset->count() - 1); + ui->colorPreset->blockSignals(block); + + A11yChanged(); + + UpdateA11yColors(); +} + +void OBSBasicSettings::on_choose7_clicked() +{ + QColor color = GetColor( + mixerGreenActive, + QTStr("Basic.Settings.Accessibility.ColorOverrides.MixerGreenActive")); + + if (!color.isValid()) + return; + + mixerGreenActive = color_to_int(color); + + preset = COLOR_PRESET_CUSTOM; + bool block = ui->colorPreset->blockSignals(true); + ui->colorPreset->setCurrentIndex(ui->colorPreset->count() - 1); + ui->colorPreset->blockSignals(block); + + A11yChanged(); + + UpdateA11yColors(); +} + +void OBSBasicSettings::on_choose8_clicked() +{ + QColor color = GetColor( + mixerYellowActive, + QTStr("Basic.Settings.Accessibility.ColorOverrides.MixerYellowActive")); + + if (!color.isValid()) + return; + + mixerYellowActive = color_to_int(color); + + preset = COLOR_PRESET_CUSTOM; + bool block = ui->colorPreset->blockSignals(true); + ui->colorPreset->setCurrentIndex(ui->colorPreset->count() - 1); + ui->colorPreset->blockSignals(block); + + A11yChanged(); + + UpdateA11yColors(); +} + +void OBSBasicSettings::on_choose9_clicked() +{ + QColor color = GetColor( + mixerRedActive, + QTStr("Basic.Settings.Accessibility.ColorOverrides.MixerRedActive")); + + if (!color.isValid()) + return; + + mixerRedActive = color_to_int(color); + + preset = COLOR_PRESET_CUSTOM; + bool block = ui->colorPreset->blockSignals(true); + ui->colorPreset->setCurrentIndex(ui->colorPreset->count() - 1); + ui->colorPreset->blockSignals(block); + + A11yChanged(); + + UpdateA11yColors(); +} diff --git a/UI/window-basic-settings.cpp b/UI/window-basic-settings.cpp index ee59fd5c6..bc75e9142 100644 --- a/UI/window-basic-settings.cpp +++ b/UI/window-basic-settings.cpp @@ -350,6 +350,7 @@ void OBSBasicSettings::HookWidget(QWidget *widget, const char *signal, #define VIDEO_RESTART SLOT(VideoChangedRestart()) #define VIDEO_RES SLOT(VideoChangedResolution()) #define VIDEO_CHANGED SLOT(VideoChanged()) +#define A11Y_CHANGED SLOT(A11yChanged()) #define ADV_CHANGED SLOT(AdvancedChanged()) #define ADV_RESTART SLOT(AdvancedChangedRestart()) /* clang-format on */ @@ -528,6 +529,8 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent) HookWidget(ui->fpsInteger, SCROLL_CHANGED, VIDEO_CHANGED); HookWidget(ui->fpsNumerator, SCROLL_CHANGED, VIDEO_CHANGED); HookWidget(ui->fpsDenominator, SCROLL_CHANGED, VIDEO_CHANGED); + HookWidget(ui->colorsGroupBox, CHECK_CHANGED, A11Y_CHANGED); + HookWidget(ui->colorPreset, COMBO_CHANGED, A11Y_CHANGED); HookWidget(ui->renderer, COMBO_CHANGED, ADV_RESTART); HookWidget(ui->adapter, COMBO_CHANGED, ADV_RESTART); HookWidget(ui->colorFormat, COMBO_CHANGED, ADV_CHANGED); @@ -3026,6 +3029,8 @@ void OBSBasicSettings::LoadSettings(bool changedOnly) LoadVideoSettings(); if (!changedOnly || hotkeysChanged) LoadHotkeySettings(); + if (!changedOnly || a11yChanged) + LoadA11ySettings(); if (!changedOnly || advancedChanged) LoadAdvancedSettings(); } @@ -3806,6 +3811,8 @@ void OBSBasicSettings::SaveSettings() SaveVideoSettings(); if (hotkeysChanged) SaveHotkeySettings(); + if (a11yChanged) + SaveA11ySettings(); if (advancedChanged) SaveAdvancedSettings(); @@ -3830,6 +3837,8 @@ void OBSBasicSettings::SaveSettings() AddChangedVal(changed, "video"); if (hotkeysChanged) AddChangedVal(changed, "hotkeys"); + if (a11yChanged) + AddChangedVal(changed, "a11y"); if (advancedChanged) AddChangedVal(changed, "advanced"); @@ -4544,6 +4553,15 @@ void OBSBasicSettings::ReloadHotkeys(obs_hotkey_id ignoreKey) LoadHotkeySettings(ignoreKey); } +void OBSBasicSettings::A11yChanged() +{ + if (!loading) { + a11yChanged = true; + sender()->setProperty("changed", QVariant(true)); + EnableApplyButton(true); + } +} + void OBSBasicSettings::AdvancedChanged() { if (!loading) { @@ -5278,6 +5296,11 @@ QIcon OBSBasicSettings::GetHotkeysIcon() const return hotkeysIcon; } +QIcon OBSBasicSettings::GetAccessibilityIcon() const +{ + return accessibilityIcon; +} + QIcon OBSBasicSettings::GetAdvancedIcon() const { return advancedIcon; @@ -5313,11 +5336,16 @@ void OBSBasicSettings::SetHotkeysIcon(const QIcon &icon) ui->listWidget->item(5)->setIcon(icon); } -void OBSBasicSettings::SetAdvancedIcon(const QIcon &icon) +void OBSBasicSettings::SetAccessibilityIcon(const QIcon &icon) { ui->listWidget->item(6)->setIcon(icon); } +void OBSBasicSettings::SetAdvancedIcon(const QIcon &icon) +{ + ui->listWidget->item(7)->setIcon(icon); +} + int OBSBasicSettings::CurrentFLVTrack() { if (ui->flvTrack1->isChecked()) diff --git a/UI/window-basic-settings.hpp b/UI/window-basic-settings.hpp index c511c719b..9a96418d3 100644 --- a/UI/window-basic-settings.hpp +++ b/UI/window-basic-settings.hpp @@ -97,6 +97,8 @@ class OBSBasicSettings : public QDialog { DESIGNABLE true) Q_PROPERTY(QIcon hotkeysIcon READ GetHotkeysIcon WRITE SetHotkeysIcon DESIGNABLE true) + Q_PROPERTY(QIcon accessibilityIcon READ GetAccessibilityIcon WRITE + SetAccessibilityIcon DESIGNABLE true) Q_PROPERTY(QIcon advancedIcon READ GetAdvancedIcon WRITE SetAdvancedIcon DESIGNABLE true) @@ -113,6 +115,7 @@ private: bool audioChanged = false; bool videoChanged = false; bool hotkeysChanged = false; + bool a11yChanged = false; bool advancedChanged = false; int pageIndex = 0; bool loading = true; @@ -194,7 +197,7 @@ private: { return generalChanged || outputsChanged || stream1Changed || audioChanged || videoChanged || advancedChanged || - hotkeysChanged; + hotkeysChanged || a11yChanged; } inline void EnableApplyButton(bool en) @@ -210,6 +213,7 @@ private: audioChanged = false; videoChanged = false; hotkeysChanged = false; + a11yChanged = false; advancedChanged = false; EnableApplyButton(false); } @@ -240,6 +244,7 @@ private: void LoadVideoSettings(); void LoadHotkeySettings(obs_hotkey_id ignoreKey = OBS_INVALID_HOTKEY_ID); + void LoadA11ySettings(bool presetChange = false); void LoadAdvancedSettings(); void LoadSettings(bool changedOnly); @@ -306,12 +311,29 @@ private: void LoadResolutionLists(); void LoadFPSData(); + /* a11y */ + void UpdateA11yColors(); + void SetDefaultColors(); + void ResetDefaultColors(); + QColor GetColor(uint32_t colorVal, QString label); + uint32_t preset = 0; + uint32_t selectRed = 0x0000FF; + uint32_t selectGreen = 0x00FF00; + uint32_t selectBlue = 0xFF7F00; + uint32_t mixerGreen = 0x267f26; + uint32_t mixerYellow = 0x267f7f; + uint32_t mixerRed = 0x26267f; + uint32_t mixerGreenActive = 0x4cff4c; + uint32_t mixerYellowActive = 0x4cffff; + uint32_t mixerRedActive = 0x4c4cff; + void SaveGeneralSettings(); void SaveStream1Settings(); void SaveOutputSettings(); void SaveAudioSettings(); void SaveVideoSettings(); void SaveHotkeySettings(); + void SaveA11ySettings(); void SaveAdvancedSettings(); void SaveSettings(); @@ -334,6 +356,7 @@ private: QIcon audioIcon; QIcon videoIcon; QIcon hotkeysIcon; + QIcon accessibilityIcon; QIcon advancedIcon; QIcon GetGeneralIcon() const; @@ -342,6 +365,7 @@ private: QIcon GetAudioIcon() const; QIcon GetVideoIcon() const; QIcon GetHotkeysIcon() const; + QIcon GetAccessibilityIcon() const; QIcon GetAdvancedIcon() const; int CurrentFLVTrack(); @@ -380,6 +404,17 @@ private slots: void on_disableOSXVSync_clicked(); + void on_choose1_clicked(); + void on_choose2_clicked(); + void on_choose3_clicked(); + void on_choose4_clicked(); + void on_choose5_clicked(); + void on_choose6_clicked(); + void on_choose7_clicked(); + void on_choose8_clicked(); + void on_choose9_clicked(); + void on_colorPreset_currentIndexChanged(int idx); + void GeneralChanged(); void HideOBSWindowWarning(int state); void AudioChanged(); @@ -397,6 +432,7 @@ private slots: void HotkeysChanged(); bool ScanDuplicateHotkeys(QFormLayout *layout); void ReloadHotkeys(obs_hotkey_id ignoreKey = OBS_INVALID_HOTKEY_ID); + void A11yChanged(); void AdvancedChanged(); void AdvancedChangedRestart(); @@ -426,6 +462,7 @@ private slots: void SetAudioIcon(const QIcon &icon); void SetVideoIcon(const QIcon &icon); void SetHotkeysIcon(const QIcon &icon); + void SetAccessibilityIcon(const QIcon &icon); void SetAdvancedIcon(const QIcon &icon); void UseStreamKeyAdvClicked();