diff --git a/frontend/components/ApplicationAudioCaptureToolbar.cpp b/frontend/components/ApplicationAudioCaptureToolbar.cpp index c45d06976..b91a00b11 100644 --- a/frontend/components/ApplicationAudioCaptureToolbar.cpp +++ b/frontend/components/ApplicationAudioCaptureToolbar.cpp @@ -1,255 +1,6 @@ -#include "window-basic-main.hpp" -#include "moc_context-bar-controls.cpp" -#include "obs-app.hpp" - -#include -#include -#include -#include - -#include "ui_browser-source-toolbar.h" +#include "ApplicationAudioCaptureToolbar.hpp" #include "ui_device-select-toolbar.h" -#include "ui_game-capture-toolbar.h" -#include "ui_image-source-toolbar.h" -#include "ui_color-source-toolbar.h" -#include "ui_text-source-toolbar.h" - -#ifdef _WIN32 -#define get_os_module(win, mac, linux) obs_get_module(win) -#define get_os_text(mod, win, mac, linux) obs_module_get_locale_text(mod, win) -#elif __APPLE__ -#define get_os_module(win, mac, linux) obs_get_module(mac) -#define get_os_text(mod, win, mac, linux) obs_module_get_locale_text(mod, mac) -#else -#define get_os_module(win, mac, linux) obs_get_module(linux) -#define get_os_text(mod, win, mac, linux) obs_module_get_locale_text(mod, linux) -#endif - -/* ========================================================================= */ - -SourceToolbar::SourceToolbar(QWidget *parent, OBSSource source) - : QWidget(parent), - weakSource(OBSGetWeakRef(source)), - props(obs_source_properties(source), obs_properties_destroy) -{ -} - -void SourceToolbar::SaveOldProperties(obs_source_t *source) -{ - oldData = obs_data_create(); - - OBSDataAutoRelease oldSettings = obs_source_get_settings(source); - obs_data_apply(oldData, oldSettings); - obs_data_set_string(oldData, "undo_suuid", obs_source_get_uuid(source)); -} - -void SourceToolbar::SetUndoProperties(obs_source_t *source, bool repeatable) -{ - if (!oldData) { - blog(LOG_ERROR, "%s: somehow oldData was null.", __FUNCTION__); - return; - } - - OBSBasic *main = reinterpret_cast(App()->GetMainWindow()); - - OBSSource currentSceneSource = main->GetCurrentSceneSource(); - if (!currentSceneSource) - return; - std::string scene_uuid = obs_source_get_uuid(currentSceneSource); - auto undo_redo = [scene_uuid = std::move(scene_uuid), main](const std::string &data) { - OBSDataAutoRelease settings = obs_data_create_from_json(data.c_str()); - OBSSourceAutoRelease source = obs_get_source_by_uuid(obs_data_get_string(settings, "undo_suuid")); - obs_source_reset_settings(source, settings); - - OBSSourceAutoRelease scene_source = obs_get_source_by_uuid(scene_uuid.c_str()); - main->SetCurrentScene(scene_source.Get(), true); - - main->UpdateContextBar(); - }; - - OBSDataAutoRelease new_settings = obs_data_create(); - OBSDataAutoRelease curr_settings = obs_source_get_settings(source); - obs_data_apply(new_settings, curr_settings); - obs_data_set_string(new_settings, "undo_suuid", obs_source_get_uuid(source)); - - std::string undo_data(obs_data_get_json(oldData)); - std::string redo_data(obs_data_get_json(new_settings)); - - if (undo_data.compare(redo_data) != 0) - main->undo_s.add_action(QTStr("Undo.Properties").arg(obs_source_get_name(source)), undo_redo, undo_redo, - undo_data, redo_data, repeatable); - - oldData = nullptr; -} - -/* ========================================================================= */ - -BrowserToolbar::BrowserToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_BrowserSourceToolbar) -{ - ui->setupUi(this); -} - -BrowserToolbar::~BrowserToolbar() {} - -void BrowserToolbar::on_refresh_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - obs_property_t *p = obs_properties_get(props.get(), "refreshnocache"); - obs_property_button_clicked(p, source.Get()); -} - -/* ========================================================================= */ - -ComboSelectToolbar::ComboSelectToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_DeviceSelectToolbar) -{ - ui->setupUi(this); -} - -ComboSelectToolbar::~ComboSelectToolbar() {} - -static int FillPropertyCombo(QComboBox *c, obs_property_t *p, const std::string &cur_id, bool is_int = false) -{ - size_t count = obs_property_list_item_count(p); - int cur_idx = -1; - - for (size_t i = 0; i < count; i++) { - const char *name = obs_property_list_item_name(p, i); - std::string id; - - if (is_int) { - id = std::to_string(obs_property_list_item_int(p, i)); - } else { - const char *val = obs_property_list_item_string(p, i); - id = val ? val : ""; - } - - if (cur_id == id) - cur_idx = (int)i; - - c->addItem(name, id.c_str()); - } - - return cur_idx; -} - -void UpdateSourceComboToolbarProperties(QComboBox *combo, OBSSource source, obs_properties_t *props, - const char *prop_name, bool is_int) -{ - std::string cur_id; - - OBSDataAutoRelease settings = obs_source_get_settings(source); - if (is_int) { - cur_id = std::to_string(obs_data_get_int(settings, prop_name)); - } else { - cur_id = obs_data_get_string(settings, prop_name); - } - - combo->blockSignals(true); - - obs_property_t *p = obs_properties_get(props, prop_name); - int cur_idx = FillPropertyCombo(combo, p, cur_id, is_int); - - if (cur_idx == -1 || obs_property_list_item_disabled(p, cur_idx)) { - if (cur_idx == -1) { - combo->insertItem(0, QTStr("Basic.Settings.Audio.UnknownAudioDevice")); - cur_idx = 0; - } - - SetComboItemEnabled(combo, cur_idx, false); - } - - combo->setCurrentIndex(cur_idx); - combo->blockSignals(false); -} - -void ComboSelectToolbar::Init() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - UpdateSourceComboToolbarProperties(ui->device, source, props.get(), prop_name, is_int); -} - -void UpdateSourceComboToolbarValue(QComboBox *combo, OBSSource source, int idx, const char *prop_name, bool is_int) -{ - QString id = combo->itemData(idx).toString(); - - OBSDataAutoRelease settings = obs_data_create(); - if (is_int) { - obs_data_set_int(settings, prop_name, id.toInt()); - } else { - obs_data_set_string(settings, prop_name, QT_TO_UTF8(id)); - } - obs_source_update(source, settings); -} - -void ComboSelectToolbar::on_device_currentIndexChanged(int idx) -{ - OBSSource source = GetSource(); - if (idx == -1 || !source) { - return; - } - - SaveOldProperties(source); - UpdateSourceComboToolbarValue(ui->device, source, idx, prop_name, is_int); - SetUndoProperties(source); -} - -AudioCaptureToolbar::AudioCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) {} - -void AudioCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = get_os_module("win-wasapi", "mac-capture", "linux-pulseaudio"); - if (!mod) - return; - - const char *device_str = get_os_text(mod, "Device", "CoreAudio.Device", "Device"); - ui->deviceLabel->setText(device_str); - - prop_name = "device_id"; - - ComboSelectToolbar::Init(); -} - -WindowCaptureToolbar::WindowCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) {} - -void WindowCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = get_os_module("win-capture", "mac-capture", "linux-capture"); - if (!mod) - return; - - const char *device_str = get_os_text(mod, "WindowCapture.Window", "WindowUtils.Window", "Window"); - ui->deviceLabel->setText(device_str); - -#if !defined(_WIN32) && !defined(__APPLE__) //linux - prop_name = "capture_window"; -#else - prop_name = "window"; -#endif - -#ifdef __APPLE__ - is_int = true; -#endif - - ComboSelectToolbar::Init(); -} +#include "moc_ApplicationAudioCaptureToolbar.cpp" ApplicationAudioCaptureToolbar::ApplicationAudioCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) @@ -269,439 +20,3 @@ void ApplicationAudioCaptureToolbar::Init() ComboSelectToolbar::Init(); } - -DisplayCaptureToolbar::DisplayCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) {} - -void DisplayCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = get_os_module("win-capture", "mac-capture", "linux-capture"); - if (!mod) - return; - - const char *device_str = get_os_text(mod, "Monitor", "DisplayCapture.Display", "Screen"); - ui->deviceLabel->setText(device_str); - -#ifdef _WIN32 - prop_name = "monitor_id"; -#elif __APPLE__ - prop_name = "display_uuid"; -#else - is_int = true; - prop_name = "screen"; -#endif - - ComboSelectToolbar::Init(); -} - -/* ========================================================================= */ - -DeviceCaptureToolbar::DeviceCaptureToolbar(QWidget *parent, OBSSource source) - : QWidget(parent), - weakSource(OBSGetWeakRef(source)), - ui(new Ui_DeviceSelectToolbar) -{ - ui->setupUi(this); - - delete ui->deviceLabel; - delete ui->device; - ui->deviceLabel = nullptr; - ui->device = nullptr; - - OBSDataAutoRelease settings = obs_source_get_settings(source); - active = obs_data_get_bool(settings, "active"); - - obs_module_t *mod = obs_get_module("win-dshow"); - if (!mod) - return; - - activateText = obs_module_get_locale_text(mod, "Activate"); - deactivateText = obs_module_get_locale_text(mod, "Deactivate"); - - ui->activateButton->setText(active ? deactivateText : activateText); -} - -DeviceCaptureToolbar::~DeviceCaptureToolbar() {} - -void DeviceCaptureToolbar::on_activateButton_clicked() -{ - OBSSource source = OBSGetStrongRef(weakSource); - if (!source) { - return; - } - - OBSDataAutoRelease settings = obs_source_get_settings(source); - bool now_active = obs_data_get_bool(settings, "active"); - - bool desyncedSetting = now_active != active; - - active = !active; - - const char *text = active ? deactivateText : activateText; - ui->activateButton->setText(text); - - if (desyncedSetting) { - return; - } - - calldata_t cd = {}; - calldata_set_bool(&cd, "active", active); - proc_handler_t *ph = obs_source_get_proc_handler(source); - proc_handler_call(ph, "activate", &cd); - calldata_free(&cd); -} - -/* ========================================================================= */ - -GameCaptureToolbar::GameCaptureToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_GameCaptureToolbar) -{ - obs_property_t *p; - int cur_idx; - - ui->setupUi(this); - - obs_module_t *mod = obs_get_module("win-capture"); - if (!mod) - return; - - ui->modeLabel->setText(obs_module_get_locale_text(mod, "Mode")); - ui->windowLabel->setText(obs_module_get_locale_text(mod, "WindowCapture.Window")); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - std::string cur_mode = obs_data_get_string(settings, "capture_mode"); - std::string cur_window = obs_data_get_string(settings, "window"); - - ui->mode->blockSignals(true); - p = obs_properties_get(props.get(), "capture_mode"); - cur_idx = FillPropertyCombo(ui->mode, p, cur_mode); - ui->mode->setCurrentIndex(cur_idx); - ui->mode->blockSignals(false); - - ui->window->blockSignals(true); - p = obs_properties_get(props.get(), "window"); - cur_idx = FillPropertyCombo(ui->window, p, cur_window); - ui->window->setCurrentIndex(cur_idx); - ui->window->blockSignals(false); - - if (cur_idx != -1 && obs_property_list_item_disabled(p, cur_idx)) { - SetComboItemEnabled(ui->window, cur_idx, false); - } - - UpdateWindowVisibility(); -} - -GameCaptureToolbar::~GameCaptureToolbar() {} - -void GameCaptureToolbar::UpdateWindowVisibility() -{ - QString mode = ui->mode->currentData().toString(); - bool is_window = (mode == "window"); - ui->windowLabel->setVisible(is_window); - ui->window->setVisible(is_window); -} - -void GameCaptureToolbar::on_mode_currentIndexChanged(int idx) -{ - OBSSource source = GetSource(); - if (idx == -1 || !source) { - return; - } - - QString id = ui->mode->itemData(idx).toString(); - - SaveOldProperties(source); - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_string(settings, "capture_mode", QT_TO_UTF8(id)); - obs_source_update(source, settings); - SetUndoProperties(source); - - UpdateWindowVisibility(); -} - -void GameCaptureToolbar::on_window_currentIndexChanged(int idx) -{ - OBSSource source = GetSource(); - if (idx == -1 || !source) { - return; - } - - QString id = ui->window->itemData(idx).toString(); - - SaveOldProperties(source); - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_string(settings, "window", QT_TO_UTF8(id)); - obs_source_update(source, settings); - SetUndoProperties(source); -} - -/* ========================================================================= */ - -ImageSourceToolbar::ImageSourceToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_ImageSourceToolbar) -{ - ui->setupUi(this); - - obs_module_t *mod = obs_get_module("image-source"); - ui->pathLabel->setText(obs_module_get_locale_text(mod, "File")); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - std::string file = obs_data_get_string(settings, "file"); - - ui->path->setText(file.c_str()); -} - -ImageSourceToolbar::~ImageSourceToolbar() {} - -void ImageSourceToolbar::on_browse_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - obs_property_t *p = obs_properties_get(props.get(), "file"); - const char *desc = obs_property_description(p); - const char *filter = obs_property_path_filter(p); - const char *default_path = obs_property_path_default_path(p); - - QString startDir = ui->path->text(); - if (startDir.isEmpty()) - startDir = default_path; - - QString path = OpenFile(this, desc, startDir, filter); - if (path.isEmpty()) { - return; - } - - ui->path->setText(path); - - SaveOldProperties(source); - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_string(settings, "file", QT_TO_UTF8(path)); - obs_source_update(source, settings); - SetUndoProperties(source); -} - -/* ========================================================================= */ - -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); -} - -ColorSourceToolbar::ColorSourceToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_ColorSourceToolbar) -{ - ui->setupUi(this); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - unsigned int val = (unsigned int)obs_data_get_int(settings, "color"); - - color = color_from_int(val); - UpdateColor(); -} - -ColorSourceToolbar::~ColorSourceToolbar() {} - -void ColorSourceToolbar::UpdateColor() -{ - QPalette palette = QPalette(color); - ui->color->setFrameStyle(QFrame::Sunken | QFrame::Panel); - ui->color->setText(color.name(QColor::HexRgb)); - ui->color->setPalette(palette); - ui->color->setStyleSheet(QString("background-color :%1; color: %2;") - .arg(palette.color(QPalette::Window).name(QColor::HexRgb)) - .arg(palette.color(QPalette::WindowText).name(QColor::HexRgb))); - ui->color->setAutoFillBackground(true); - ui->color->setAlignment(Qt::AlignCenter); -} - -void ColorSourceToolbar::on_choose_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - obs_property_t *p = obs_properties_get(props.get(), "color"); - const char *desc = obs_property_description(p); - - QColorDialog::ColorDialogOptions options; - - options |= QColorDialog::ShowAlphaChannel; -#ifdef __linux__ - // TODO: Revisit hang on Ubuntu with native dialog - options |= QColorDialog::DontUseNativeDialog; -#endif - - QColor newColor = QColorDialog::getColor(color, this, desc, options); - if (!newColor.isValid()) { - return; - } - - color = newColor; - UpdateColor(); - - SaveOldProperties(source); - - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_int(settings, "color", color_to_int(color)); - obs_source_update(source, settings); - - SetUndoProperties(source); -} - -/* ========================================================================= */ - -extern void MakeQFont(obs_data_t *font_obj, QFont &font, bool limit = false); - -TextSourceToolbar::TextSourceToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_TextSourceToolbar) -{ - ui->setupUi(this); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - - const char *id = obs_source_get_unversioned_id(source); - bool ft2 = strcmp(id, "text_ft2_source") == 0; - bool read_from_file = obs_data_get_bool(settings, ft2 ? "from_file" : "read_from_file"); - - OBSDataAutoRelease font_obj = obs_data_get_obj(settings, "font"); - MakeQFont(font_obj, font); - - // Use "color1" if it's a freetype source and "color" elsewise - unsigned int val = (unsigned int)obs_data_get_int( - settings, (strncmp(obs_source_get_id(source), "text_ft2_source", 15) == 0) ? "color1" : "color"); - - color = color_from_int(val); - - const char *text = obs_data_get_string(settings, "text"); - - bool single_line = !read_from_file && (!text || (strchr(text, '\n') == nullptr)); - ui->emptySpace->setVisible(!single_line); - ui->text->setVisible(single_line); - if (single_line) - ui->text->setText(text); -} - -TextSourceToolbar::~TextSourceToolbar() {} - -void TextSourceToolbar::on_selectFont_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - QFontDialog::FontDialogOptions options; - uint32_t flags; - bool success; - -#ifndef _WIN32 - options = QFontDialog::DontUseNativeDialog; -#endif - - font = QFontDialog::getFont(&success, font, this, QTStr("Basic.PropertiesWindow.SelectFont.WindowTitle"), - options); - if (!success) { - return; - } - - OBSDataAutoRelease font_obj = obs_data_create(); - - obs_data_set_string(font_obj, "face", QT_TO_UTF8(font.family())); - obs_data_set_string(font_obj, "style", QT_TO_UTF8(font.styleName())); - obs_data_set_int(font_obj, "size", font.pointSize()); - flags = font.bold() ? OBS_FONT_BOLD : 0; - flags |= font.italic() ? OBS_FONT_ITALIC : 0; - flags |= font.underline() ? OBS_FONT_UNDERLINE : 0; - flags |= font.strikeOut() ? OBS_FONT_STRIKEOUT : 0; - obs_data_set_int(font_obj, "flags", flags); - - SaveOldProperties(source); - - OBSDataAutoRelease settings = obs_data_create(); - - obs_data_set_obj(settings, "font", font_obj); - - obs_source_update(source, settings); - - SetUndoProperties(source); -} - -void TextSourceToolbar::on_selectColor_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - bool freetype = strncmp(obs_source_get_id(source), "text_ft2_source", 15) == 0; - - obs_property_t *p = obs_properties_get(props.get(), freetype ? "color1" : "color"); - - const char *desc = obs_property_description(p); - - QColorDialog::ColorDialogOptions options; - - options |= QColorDialog::ShowAlphaChannel; -#ifdef __linux__ - // TODO: Revisit hang on Ubuntu with native dialog - options |= QColorDialog::DontUseNativeDialog; -#endif - - QColor newColor = QColorDialog::getColor(color, this, desc, options); - if (!newColor.isValid()) { - return; - } - - color = newColor; - - SaveOldProperties(source); - - OBSDataAutoRelease settings = obs_data_create(); - if (freetype) { - obs_data_set_int(settings, "color1", color_to_int(color)); - obs_data_set_int(settings, "color2", color_to_int(color)); - } else { - obs_data_set_int(settings, "color", color_to_int(color)); - } - obs_source_update(source, settings); - - SetUndoProperties(source); -} - -void TextSourceToolbar::on_text_textChanged() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - std::string newText = QT_TO_UTF8(ui->text->text()); - OBSDataAutoRelease settings = obs_source_get_settings(source); - if (newText == obs_data_get_string(settings, "text")) { - return; - } - SaveOldProperties(source); - - obs_data_set_string(settings, "text", newText.c_str()); - obs_source_update(source, nullptr); - - SetUndoProperties(source, true); -} diff --git a/frontend/components/ApplicationAudioCaptureToolbar.hpp b/frontend/components/ApplicationAudioCaptureToolbar.hpp index acf88a5fb..bb916e762 100644 --- a/frontend/components/ApplicationAudioCaptureToolbar.hpp +++ b/frontend/components/ApplicationAudioCaptureToolbar.hpp @@ -1,85 +1,6 @@ #pragma once -#include -#include -#include - -class Ui_BrowserSourceToolbar; -class Ui_DeviceSelectToolbar; -class Ui_GameCaptureToolbar; -class Ui_ImageSourceToolbar; -class Ui_ColorSourceToolbar; -class Ui_TextSourceToolbar; - -class SourceToolbar : public QWidget { - Q_OBJECT - - OBSWeakSource weakSource; - -protected: - using properties_delete_t = decltype(&obs_properties_destroy); - using properties_t = std::unique_ptr; - - properties_t props; - OBSDataAutoRelease oldData; - - void SaveOldProperties(obs_source_t *source); - void SetUndoProperties(obs_source_t *source, bool repeatable = false); - -public: - SourceToolbar(QWidget *parent, OBSSource source); - - OBSSource GetSource() { return OBSGetStrongRef(weakSource); } - -public slots: - virtual void Update() {} -}; - -class BrowserToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - -public: - BrowserToolbar(QWidget *parent, OBSSource source); - ~BrowserToolbar(); - -public slots: - void on_refresh_clicked(); -}; - -class ComboSelectToolbar : public SourceToolbar { - Q_OBJECT - -protected: - std::unique_ptr ui; - const char *prop_name; - bool is_int = false; - -public: - ComboSelectToolbar(QWidget *parent, OBSSource source); - ~ComboSelectToolbar(); - virtual void Init(); - -public slots: - void on_device_currentIndexChanged(int idx); -}; - -class AudioCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - AudioCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class WindowCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - WindowCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; +#include "ComboSelectToolbar.hpp" class ApplicationAudioCaptureToolbar : public ComboSelectToolbar { Q_OBJECT @@ -88,91 +9,3 @@ public: ApplicationAudioCaptureToolbar(QWidget *parent, OBSSource source); void Init() override; }; - -class DisplayCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - DisplayCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class DeviceCaptureToolbar : public QWidget { - Q_OBJECT - - OBSWeakSource weakSource; - - std::unique_ptr ui; - const char *activateText; - const char *deactivateText; - bool active; - -public: - DeviceCaptureToolbar(QWidget *parent, OBSSource source); - ~DeviceCaptureToolbar(); - -public slots: - void on_activateButton_clicked(); -}; - -class GameCaptureToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - - void UpdateWindowVisibility(); - -public: - GameCaptureToolbar(QWidget *parent, OBSSource source); - ~GameCaptureToolbar(); - -public slots: - void on_mode_currentIndexChanged(int idx); - void on_window_currentIndexChanged(int idx); -}; - -class ImageSourceToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - -public: - ImageSourceToolbar(QWidget *parent, OBSSource source); - ~ImageSourceToolbar(); - -public slots: - void on_browse_clicked(); -}; - -class ColorSourceToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - QColor color; - - void UpdateColor(); - -public: - ColorSourceToolbar(QWidget *parent, OBSSource source); - ~ColorSourceToolbar(); - -public slots: - void on_choose_clicked(); -}; - -class TextSourceToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - QFont font; - QColor color; - -public: - TextSourceToolbar(QWidget *parent, OBSSource source); - ~TextSourceToolbar(); - -public slots: - void on_selectFont_clicked(); - void on_selectColor_clicked(); - void on_text_textChanged(); -}; diff --git a/frontend/components/AudioCaptureToolbar.cpp b/frontend/components/AudioCaptureToolbar.cpp index c45d06976..f61eb6eae 100644 --- a/frontend/components/AudioCaptureToolbar.cpp +++ b/frontend/components/AudioCaptureToolbar.cpp @@ -1,18 +1,6 @@ -#include "window-basic-main.hpp" -#include "moc_context-bar-controls.cpp" -#include "obs-app.hpp" - -#include -#include -#include -#include - -#include "ui_browser-source-toolbar.h" +#include "AudioCaptureToolbar.hpp" #include "ui_device-select-toolbar.h" -#include "ui_game-capture-toolbar.h" -#include "ui_image-source-toolbar.h" -#include "ui_color-source-toolbar.h" -#include "ui_text-source-toolbar.h" +#include "moc_AudioCaptureToolbar.cpp" #ifdef _WIN32 #define get_os_module(win, mac, linux) obs_get_module(win) @@ -25,186 +13,6 @@ #define get_os_text(mod, win, mac, linux) obs_module_get_locale_text(mod, linux) #endif -/* ========================================================================= */ - -SourceToolbar::SourceToolbar(QWidget *parent, OBSSource source) - : QWidget(parent), - weakSource(OBSGetWeakRef(source)), - props(obs_source_properties(source), obs_properties_destroy) -{ -} - -void SourceToolbar::SaveOldProperties(obs_source_t *source) -{ - oldData = obs_data_create(); - - OBSDataAutoRelease oldSettings = obs_source_get_settings(source); - obs_data_apply(oldData, oldSettings); - obs_data_set_string(oldData, "undo_suuid", obs_source_get_uuid(source)); -} - -void SourceToolbar::SetUndoProperties(obs_source_t *source, bool repeatable) -{ - if (!oldData) { - blog(LOG_ERROR, "%s: somehow oldData was null.", __FUNCTION__); - return; - } - - OBSBasic *main = reinterpret_cast(App()->GetMainWindow()); - - OBSSource currentSceneSource = main->GetCurrentSceneSource(); - if (!currentSceneSource) - return; - std::string scene_uuid = obs_source_get_uuid(currentSceneSource); - auto undo_redo = [scene_uuid = std::move(scene_uuid), main](const std::string &data) { - OBSDataAutoRelease settings = obs_data_create_from_json(data.c_str()); - OBSSourceAutoRelease source = obs_get_source_by_uuid(obs_data_get_string(settings, "undo_suuid")); - obs_source_reset_settings(source, settings); - - OBSSourceAutoRelease scene_source = obs_get_source_by_uuid(scene_uuid.c_str()); - main->SetCurrentScene(scene_source.Get(), true); - - main->UpdateContextBar(); - }; - - OBSDataAutoRelease new_settings = obs_data_create(); - OBSDataAutoRelease curr_settings = obs_source_get_settings(source); - obs_data_apply(new_settings, curr_settings); - obs_data_set_string(new_settings, "undo_suuid", obs_source_get_uuid(source)); - - std::string undo_data(obs_data_get_json(oldData)); - std::string redo_data(obs_data_get_json(new_settings)); - - if (undo_data.compare(redo_data) != 0) - main->undo_s.add_action(QTStr("Undo.Properties").arg(obs_source_get_name(source)), undo_redo, undo_redo, - undo_data, redo_data, repeatable); - - oldData = nullptr; -} - -/* ========================================================================= */ - -BrowserToolbar::BrowserToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_BrowserSourceToolbar) -{ - ui->setupUi(this); -} - -BrowserToolbar::~BrowserToolbar() {} - -void BrowserToolbar::on_refresh_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - obs_property_t *p = obs_properties_get(props.get(), "refreshnocache"); - obs_property_button_clicked(p, source.Get()); -} - -/* ========================================================================= */ - -ComboSelectToolbar::ComboSelectToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_DeviceSelectToolbar) -{ - ui->setupUi(this); -} - -ComboSelectToolbar::~ComboSelectToolbar() {} - -static int FillPropertyCombo(QComboBox *c, obs_property_t *p, const std::string &cur_id, bool is_int = false) -{ - size_t count = obs_property_list_item_count(p); - int cur_idx = -1; - - for (size_t i = 0; i < count; i++) { - const char *name = obs_property_list_item_name(p, i); - std::string id; - - if (is_int) { - id = std::to_string(obs_property_list_item_int(p, i)); - } else { - const char *val = obs_property_list_item_string(p, i); - id = val ? val : ""; - } - - if (cur_id == id) - cur_idx = (int)i; - - c->addItem(name, id.c_str()); - } - - return cur_idx; -} - -void UpdateSourceComboToolbarProperties(QComboBox *combo, OBSSource source, obs_properties_t *props, - const char *prop_name, bool is_int) -{ - std::string cur_id; - - OBSDataAutoRelease settings = obs_source_get_settings(source); - if (is_int) { - cur_id = std::to_string(obs_data_get_int(settings, prop_name)); - } else { - cur_id = obs_data_get_string(settings, prop_name); - } - - combo->blockSignals(true); - - obs_property_t *p = obs_properties_get(props, prop_name); - int cur_idx = FillPropertyCombo(combo, p, cur_id, is_int); - - if (cur_idx == -1 || obs_property_list_item_disabled(p, cur_idx)) { - if (cur_idx == -1) { - combo->insertItem(0, QTStr("Basic.Settings.Audio.UnknownAudioDevice")); - cur_idx = 0; - } - - SetComboItemEnabled(combo, cur_idx, false); - } - - combo->setCurrentIndex(cur_idx); - combo->blockSignals(false); -} - -void ComboSelectToolbar::Init() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - UpdateSourceComboToolbarProperties(ui->device, source, props.get(), prop_name, is_int); -} - -void UpdateSourceComboToolbarValue(QComboBox *combo, OBSSource source, int idx, const char *prop_name, bool is_int) -{ - QString id = combo->itemData(idx).toString(); - - OBSDataAutoRelease settings = obs_data_create(); - if (is_int) { - obs_data_set_int(settings, prop_name, id.toInt()); - } else { - obs_data_set_string(settings, prop_name, QT_TO_UTF8(id)); - } - obs_source_update(source, settings); -} - -void ComboSelectToolbar::on_device_currentIndexChanged(int idx) -{ - OBSSource source = GetSource(); - if (idx == -1 || !source) { - return; - } - - SaveOldProperties(source); - UpdateSourceComboToolbarValue(ui->device, source, idx, prop_name, is_int); - SetUndoProperties(source); -} - AudioCaptureToolbar::AudioCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) {} void AudioCaptureToolbar::Init() @@ -223,485 +31,3 @@ void AudioCaptureToolbar::Init() ComboSelectToolbar::Init(); } - -WindowCaptureToolbar::WindowCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) {} - -void WindowCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = get_os_module("win-capture", "mac-capture", "linux-capture"); - if (!mod) - return; - - const char *device_str = get_os_text(mod, "WindowCapture.Window", "WindowUtils.Window", "Window"); - ui->deviceLabel->setText(device_str); - -#if !defined(_WIN32) && !defined(__APPLE__) //linux - prop_name = "capture_window"; -#else - prop_name = "window"; -#endif - -#ifdef __APPLE__ - is_int = true; -#endif - - ComboSelectToolbar::Init(); -} - -ApplicationAudioCaptureToolbar::ApplicationAudioCaptureToolbar(QWidget *parent, OBSSource source) - : ComboSelectToolbar(parent, source) -{ -} - -void ApplicationAudioCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = obs_get_module("win-wasapi"); - const char *device_str = obs_module_get_locale_text(mod, "Window"); - ui->deviceLabel->setText(device_str); - - prop_name = "window"; - - ComboSelectToolbar::Init(); -} - -DisplayCaptureToolbar::DisplayCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) {} - -void DisplayCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = get_os_module("win-capture", "mac-capture", "linux-capture"); - if (!mod) - return; - - const char *device_str = get_os_text(mod, "Monitor", "DisplayCapture.Display", "Screen"); - ui->deviceLabel->setText(device_str); - -#ifdef _WIN32 - prop_name = "monitor_id"; -#elif __APPLE__ - prop_name = "display_uuid"; -#else - is_int = true; - prop_name = "screen"; -#endif - - ComboSelectToolbar::Init(); -} - -/* ========================================================================= */ - -DeviceCaptureToolbar::DeviceCaptureToolbar(QWidget *parent, OBSSource source) - : QWidget(parent), - weakSource(OBSGetWeakRef(source)), - ui(new Ui_DeviceSelectToolbar) -{ - ui->setupUi(this); - - delete ui->deviceLabel; - delete ui->device; - ui->deviceLabel = nullptr; - ui->device = nullptr; - - OBSDataAutoRelease settings = obs_source_get_settings(source); - active = obs_data_get_bool(settings, "active"); - - obs_module_t *mod = obs_get_module("win-dshow"); - if (!mod) - return; - - activateText = obs_module_get_locale_text(mod, "Activate"); - deactivateText = obs_module_get_locale_text(mod, "Deactivate"); - - ui->activateButton->setText(active ? deactivateText : activateText); -} - -DeviceCaptureToolbar::~DeviceCaptureToolbar() {} - -void DeviceCaptureToolbar::on_activateButton_clicked() -{ - OBSSource source = OBSGetStrongRef(weakSource); - if (!source) { - return; - } - - OBSDataAutoRelease settings = obs_source_get_settings(source); - bool now_active = obs_data_get_bool(settings, "active"); - - bool desyncedSetting = now_active != active; - - active = !active; - - const char *text = active ? deactivateText : activateText; - ui->activateButton->setText(text); - - if (desyncedSetting) { - return; - } - - calldata_t cd = {}; - calldata_set_bool(&cd, "active", active); - proc_handler_t *ph = obs_source_get_proc_handler(source); - proc_handler_call(ph, "activate", &cd); - calldata_free(&cd); -} - -/* ========================================================================= */ - -GameCaptureToolbar::GameCaptureToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_GameCaptureToolbar) -{ - obs_property_t *p; - int cur_idx; - - ui->setupUi(this); - - obs_module_t *mod = obs_get_module("win-capture"); - if (!mod) - return; - - ui->modeLabel->setText(obs_module_get_locale_text(mod, "Mode")); - ui->windowLabel->setText(obs_module_get_locale_text(mod, "WindowCapture.Window")); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - std::string cur_mode = obs_data_get_string(settings, "capture_mode"); - std::string cur_window = obs_data_get_string(settings, "window"); - - ui->mode->blockSignals(true); - p = obs_properties_get(props.get(), "capture_mode"); - cur_idx = FillPropertyCombo(ui->mode, p, cur_mode); - ui->mode->setCurrentIndex(cur_idx); - ui->mode->blockSignals(false); - - ui->window->blockSignals(true); - p = obs_properties_get(props.get(), "window"); - cur_idx = FillPropertyCombo(ui->window, p, cur_window); - ui->window->setCurrentIndex(cur_idx); - ui->window->blockSignals(false); - - if (cur_idx != -1 && obs_property_list_item_disabled(p, cur_idx)) { - SetComboItemEnabled(ui->window, cur_idx, false); - } - - UpdateWindowVisibility(); -} - -GameCaptureToolbar::~GameCaptureToolbar() {} - -void GameCaptureToolbar::UpdateWindowVisibility() -{ - QString mode = ui->mode->currentData().toString(); - bool is_window = (mode == "window"); - ui->windowLabel->setVisible(is_window); - ui->window->setVisible(is_window); -} - -void GameCaptureToolbar::on_mode_currentIndexChanged(int idx) -{ - OBSSource source = GetSource(); - if (idx == -1 || !source) { - return; - } - - QString id = ui->mode->itemData(idx).toString(); - - SaveOldProperties(source); - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_string(settings, "capture_mode", QT_TO_UTF8(id)); - obs_source_update(source, settings); - SetUndoProperties(source); - - UpdateWindowVisibility(); -} - -void GameCaptureToolbar::on_window_currentIndexChanged(int idx) -{ - OBSSource source = GetSource(); - if (idx == -1 || !source) { - return; - } - - QString id = ui->window->itemData(idx).toString(); - - SaveOldProperties(source); - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_string(settings, "window", QT_TO_UTF8(id)); - obs_source_update(source, settings); - SetUndoProperties(source); -} - -/* ========================================================================= */ - -ImageSourceToolbar::ImageSourceToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_ImageSourceToolbar) -{ - ui->setupUi(this); - - obs_module_t *mod = obs_get_module("image-source"); - ui->pathLabel->setText(obs_module_get_locale_text(mod, "File")); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - std::string file = obs_data_get_string(settings, "file"); - - ui->path->setText(file.c_str()); -} - -ImageSourceToolbar::~ImageSourceToolbar() {} - -void ImageSourceToolbar::on_browse_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - obs_property_t *p = obs_properties_get(props.get(), "file"); - const char *desc = obs_property_description(p); - const char *filter = obs_property_path_filter(p); - const char *default_path = obs_property_path_default_path(p); - - QString startDir = ui->path->text(); - if (startDir.isEmpty()) - startDir = default_path; - - QString path = OpenFile(this, desc, startDir, filter); - if (path.isEmpty()) { - return; - } - - ui->path->setText(path); - - SaveOldProperties(source); - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_string(settings, "file", QT_TO_UTF8(path)); - obs_source_update(source, settings); - SetUndoProperties(source); -} - -/* ========================================================================= */ - -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); -} - -ColorSourceToolbar::ColorSourceToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_ColorSourceToolbar) -{ - ui->setupUi(this); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - unsigned int val = (unsigned int)obs_data_get_int(settings, "color"); - - color = color_from_int(val); - UpdateColor(); -} - -ColorSourceToolbar::~ColorSourceToolbar() {} - -void ColorSourceToolbar::UpdateColor() -{ - QPalette palette = QPalette(color); - ui->color->setFrameStyle(QFrame::Sunken | QFrame::Panel); - ui->color->setText(color.name(QColor::HexRgb)); - ui->color->setPalette(palette); - ui->color->setStyleSheet(QString("background-color :%1; color: %2;") - .arg(palette.color(QPalette::Window).name(QColor::HexRgb)) - .arg(palette.color(QPalette::WindowText).name(QColor::HexRgb))); - ui->color->setAutoFillBackground(true); - ui->color->setAlignment(Qt::AlignCenter); -} - -void ColorSourceToolbar::on_choose_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - obs_property_t *p = obs_properties_get(props.get(), "color"); - const char *desc = obs_property_description(p); - - QColorDialog::ColorDialogOptions options; - - options |= QColorDialog::ShowAlphaChannel; -#ifdef __linux__ - // TODO: Revisit hang on Ubuntu with native dialog - options |= QColorDialog::DontUseNativeDialog; -#endif - - QColor newColor = QColorDialog::getColor(color, this, desc, options); - if (!newColor.isValid()) { - return; - } - - color = newColor; - UpdateColor(); - - SaveOldProperties(source); - - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_int(settings, "color", color_to_int(color)); - obs_source_update(source, settings); - - SetUndoProperties(source); -} - -/* ========================================================================= */ - -extern void MakeQFont(obs_data_t *font_obj, QFont &font, bool limit = false); - -TextSourceToolbar::TextSourceToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_TextSourceToolbar) -{ - ui->setupUi(this); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - - const char *id = obs_source_get_unversioned_id(source); - bool ft2 = strcmp(id, "text_ft2_source") == 0; - bool read_from_file = obs_data_get_bool(settings, ft2 ? "from_file" : "read_from_file"); - - OBSDataAutoRelease font_obj = obs_data_get_obj(settings, "font"); - MakeQFont(font_obj, font); - - // Use "color1" if it's a freetype source and "color" elsewise - unsigned int val = (unsigned int)obs_data_get_int( - settings, (strncmp(obs_source_get_id(source), "text_ft2_source", 15) == 0) ? "color1" : "color"); - - color = color_from_int(val); - - const char *text = obs_data_get_string(settings, "text"); - - bool single_line = !read_from_file && (!text || (strchr(text, '\n') == nullptr)); - ui->emptySpace->setVisible(!single_line); - ui->text->setVisible(single_line); - if (single_line) - ui->text->setText(text); -} - -TextSourceToolbar::~TextSourceToolbar() {} - -void TextSourceToolbar::on_selectFont_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - QFontDialog::FontDialogOptions options; - uint32_t flags; - bool success; - -#ifndef _WIN32 - options = QFontDialog::DontUseNativeDialog; -#endif - - font = QFontDialog::getFont(&success, font, this, QTStr("Basic.PropertiesWindow.SelectFont.WindowTitle"), - options); - if (!success) { - return; - } - - OBSDataAutoRelease font_obj = obs_data_create(); - - obs_data_set_string(font_obj, "face", QT_TO_UTF8(font.family())); - obs_data_set_string(font_obj, "style", QT_TO_UTF8(font.styleName())); - obs_data_set_int(font_obj, "size", font.pointSize()); - flags = font.bold() ? OBS_FONT_BOLD : 0; - flags |= font.italic() ? OBS_FONT_ITALIC : 0; - flags |= font.underline() ? OBS_FONT_UNDERLINE : 0; - flags |= font.strikeOut() ? OBS_FONT_STRIKEOUT : 0; - obs_data_set_int(font_obj, "flags", flags); - - SaveOldProperties(source); - - OBSDataAutoRelease settings = obs_data_create(); - - obs_data_set_obj(settings, "font", font_obj); - - obs_source_update(source, settings); - - SetUndoProperties(source); -} - -void TextSourceToolbar::on_selectColor_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - bool freetype = strncmp(obs_source_get_id(source), "text_ft2_source", 15) == 0; - - obs_property_t *p = obs_properties_get(props.get(), freetype ? "color1" : "color"); - - const char *desc = obs_property_description(p); - - QColorDialog::ColorDialogOptions options; - - options |= QColorDialog::ShowAlphaChannel; -#ifdef __linux__ - // TODO: Revisit hang on Ubuntu with native dialog - options |= QColorDialog::DontUseNativeDialog; -#endif - - QColor newColor = QColorDialog::getColor(color, this, desc, options); - if (!newColor.isValid()) { - return; - } - - color = newColor; - - SaveOldProperties(source); - - OBSDataAutoRelease settings = obs_data_create(); - if (freetype) { - obs_data_set_int(settings, "color1", color_to_int(color)); - obs_data_set_int(settings, "color2", color_to_int(color)); - } else { - obs_data_set_int(settings, "color", color_to_int(color)); - } - obs_source_update(source, settings); - - SetUndoProperties(source); -} - -void TextSourceToolbar::on_text_textChanged() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - std::string newText = QT_TO_UTF8(ui->text->text()); - OBSDataAutoRelease settings = obs_source_get_settings(source); - if (newText == obs_data_get_string(settings, "text")) { - return; - } - SaveOldProperties(source); - - obs_data_set_string(settings, "text", newText.c_str()); - obs_source_update(source, nullptr); - - SetUndoProperties(source, true); -} diff --git a/frontend/components/AudioCaptureToolbar.hpp b/frontend/components/AudioCaptureToolbar.hpp index acf88a5fb..713ea322f 100644 --- a/frontend/components/AudioCaptureToolbar.hpp +++ b/frontend/components/AudioCaptureToolbar.hpp @@ -1,69 +1,6 @@ #pragma once -#include -#include -#include - -class Ui_BrowserSourceToolbar; -class Ui_DeviceSelectToolbar; -class Ui_GameCaptureToolbar; -class Ui_ImageSourceToolbar; -class Ui_ColorSourceToolbar; -class Ui_TextSourceToolbar; - -class SourceToolbar : public QWidget { - Q_OBJECT - - OBSWeakSource weakSource; - -protected: - using properties_delete_t = decltype(&obs_properties_destroy); - using properties_t = std::unique_ptr; - - properties_t props; - OBSDataAutoRelease oldData; - - void SaveOldProperties(obs_source_t *source); - void SetUndoProperties(obs_source_t *source, bool repeatable = false); - -public: - SourceToolbar(QWidget *parent, OBSSource source); - - OBSSource GetSource() { return OBSGetStrongRef(weakSource); } - -public slots: - virtual void Update() {} -}; - -class BrowserToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - -public: - BrowserToolbar(QWidget *parent, OBSSource source); - ~BrowserToolbar(); - -public slots: - void on_refresh_clicked(); -}; - -class ComboSelectToolbar : public SourceToolbar { - Q_OBJECT - -protected: - std::unique_ptr ui; - const char *prop_name; - bool is_int = false; - -public: - ComboSelectToolbar(QWidget *parent, OBSSource source); - ~ComboSelectToolbar(); - virtual void Init(); - -public slots: - void on_device_currentIndexChanged(int idx); -}; +#include "ComboSelectToolbar.hpp" class AudioCaptureToolbar : public ComboSelectToolbar { Q_OBJECT @@ -72,107 +9,3 @@ public: AudioCaptureToolbar(QWidget *parent, OBSSource source); void Init() override; }; - -class WindowCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - WindowCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class ApplicationAudioCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - ApplicationAudioCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class DisplayCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - DisplayCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class DeviceCaptureToolbar : public QWidget { - Q_OBJECT - - OBSWeakSource weakSource; - - std::unique_ptr ui; - const char *activateText; - const char *deactivateText; - bool active; - -public: - DeviceCaptureToolbar(QWidget *parent, OBSSource source); - ~DeviceCaptureToolbar(); - -public slots: - void on_activateButton_clicked(); -}; - -class GameCaptureToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - - void UpdateWindowVisibility(); - -public: - GameCaptureToolbar(QWidget *parent, OBSSource source); - ~GameCaptureToolbar(); - -public slots: - void on_mode_currentIndexChanged(int idx); - void on_window_currentIndexChanged(int idx); -}; - -class ImageSourceToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - -public: - ImageSourceToolbar(QWidget *parent, OBSSource source); - ~ImageSourceToolbar(); - -public slots: - void on_browse_clicked(); -}; - -class ColorSourceToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - QColor color; - - void UpdateColor(); - -public: - ColorSourceToolbar(QWidget *parent, OBSSource source); - ~ColorSourceToolbar(); - -public slots: - void on_choose_clicked(); -}; - -class TextSourceToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - QFont font; - QColor color; - -public: - TextSourceToolbar(QWidget *parent, OBSSource source); - ~TextSourceToolbar(); - -public slots: - void on_selectFont_clicked(); - void on_selectColor_clicked(); - void on_text_textChanged(); -}; diff --git a/frontend/components/BrowserToolbar.cpp b/frontend/components/BrowserToolbar.cpp index c45d06976..b41360dd5 100644 --- a/frontend/components/BrowserToolbar.cpp +++ b/frontend/components/BrowserToolbar.cpp @@ -1,88 +1,6 @@ -#include "window-basic-main.hpp" -#include "moc_context-bar-controls.cpp" -#include "obs-app.hpp" - -#include -#include -#include -#include - +#include "BrowserToolbar.hpp" #include "ui_browser-source-toolbar.h" -#include "ui_device-select-toolbar.h" -#include "ui_game-capture-toolbar.h" -#include "ui_image-source-toolbar.h" -#include "ui_color-source-toolbar.h" -#include "ui_text-source-toolbar.h" - -#ifdef _WIN32 -#define get_os_module(win, mac, linux) obs_get_module(win) -#define get_os_text(mod, win, mac, linux) obs_module_get_locale_text(mod, win) -#elif __APPLE__ -#define get_os_module(win, mac, linux) obs_get_module(mac) -#define get_os_text(mod, win, mac, linux) obs_module_get_locale_text(mod, mac) -#else -#define get_os_module(win, mac, linux) obs_get_module(linux) -#define get_os_text(mod, win, mac, linux) obs_module_get_locale_text(mod, linux) -#endif - -/* ========================================================================= */ - -SourceToolbar::SourceToolbar(QWidget *parent, OBSSource source) - : QWidget(parent), - weakSource(OBSGetWeakRef(source)), - props(obs_source_properties(source), obs_properties_destroy) -{ -} - -void SourceToolbar::SaveOldProperties(obs_source_t *source) -{ - oldData = obs_data_create(); - - OBSDataAutoRelease oldSettings = obs_source_get_settings(source); - obs_data_apply(oldData, oldSettings); - obs_data_set_string(oldData, "undo_suuid", obs_source_get_uuid(source)); -} - -void SourceToolbar::SetUndoProperties(obs_source_t *source, bool repeatable) -{ - if (!oldData) { - blog(LOG_ERROR, "%s: somehow oldData was null.", __FUNCTION__); - return; - } - - OBSBasic *main = reinterpret_cast(App()->GetMainWindow()); - - OBSSource currentSceneSource = main->GetCurrentSceneSource(); - if (!currentSceneSource) - return; - std::string scene_uuid = obs_source_get_uuid(currentSceneSource); - auto undo_redo = [scene_uuid = std::move(scene_uuid), main](const std::string &data) { - OBSDataAutoRelease settings = obs_data_create_from_json(data.c_str()); - OBSSourceAutoRelease source = obs_get_source_by_uuid(obs_data_get_string(settings, "undo_suuid")); - obs_source_reset_settings(source, settings); - - OBSSourceAutoRelease scene_source = obs_get_source_by_uuid(scene_uuid.c_str()); - main->SetCurrentScene(scene_source.Get(), true); - - main->UpdateContextBar(); - }; - - OBSDataAutoRelease new_settings = obs_data_create(); - OBSDataAutoRelease curr_settings = obs_source_get_settings(source); - obs_data_apply(new_settings, curr_settings); - obs_data_set_string(new_settings, "undo_suuid", obs_source_get_uuid(source)); - - std::string undo_data(obs_data_get_json(oldData)); - std::string redo_data(obs_data_get_json(new_settings)); - - if (undo_data.compare(redo_data) != 0) - main->undo_s.add_action(QTStr("Undo.Properties").arg(obs_source_get_name(source)), undo_redo, undo_redo, - undo_data, redo_data, repeatable); - - oldData = nullptr; -} - -/* ========================================================================= */ +#include "moc_BrowserToolbar.cpp" BrowserToolbar::BrowserToolbar(QWidget *parent, OBSSource source) : SourceToolbar(parent, source), @@ -103,605 +21,3 @@ void BrowserToolbar::on_refresh_clicked() obs_property_t *p = obs_properties_get(props.get(), "refreshnocache"); obs_property_button_clicked(p, source.Get()); } - -/* ========================================================================= */ - -ComboSelectToolbar::ComboSelectToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_DeviceSelectToolbar) -{ - ui->setupUi(this); -} - -ComboSelectToolbar::~ComboSelectToolbar() {} - -static int FillPropertyCombo(QComboBox *c, obs_property_t *p, const std::string &cur_id, bool is_int = false) -{ - size_t count = obs_property_list_item_count(p); - int cur_idx = -1; - - for (size_t i = 0; i < count; i++) { - const char *name = obs_property_list_item_name(p, i); - std::string id; - - if (is_int) { - id = std::to_string(obs_property_list_item_int(p, i)); - } else { - const char *val = obs_property_list_item_string(p, i); - id = val ? val : ""; - } - - if (cur_id == id) - cur_idx = (int)i; - - c->addItem(name, id.c_str()); - } - - return cur_idx; -} - -void UpdateSourceComboToolbarProperties(QComboBox *combo, OBSSource source, obs_properties_t *props, - const char *prop_name, bool is_int) -{ - std::string cur_id; - - OBSDataAutoRelease settings = obs_source_get_settings(source); - if (is_int) { - cur_id = std::to_string(obs_data_get_int(settings, prop_name)); - } else { - cur_id = obs_data_get_string(settings, prop_name); - } - - combo->blockSignals(true); - - obs_property_t *p = obs_properties_get(props, prop_name); - int cur_idx = FillPropertyCombo(combo, p, cur_id, is_int); - - if (cur_idx == -1 || obs_property_list_item_disabled(p, cur_idx)) { - if (cur_idx == -1) { - combo->insertItem(0, QTStr("Basic.Settings.Audio.UnknownAudioDevice")); - cur_idx = 0; - } - - SetComboItemEnabled(combo, cur_idx, false); - } - - combo->setCurrentIndex(cur_idx); - combo->blockSignals(false); -} - -void ComboSelectToolbar::Init() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - UpdateSourceComboToolbarProperties(ui->device, source, props.get(), prop_name, is_int); -} - -void UpdateSourceComboToolbarValue(QComboBox *combo, OBSSource source, int idx, const char *prop_name, bool is_int) -{ - QString id = combo->itemData(idx).toString(); - - OBSDataAutoRelease settings = obs_data_create(); - if (is_int) { - obs_data_set_int(settings, prop_name, id.toInt()); - } else { - obs_data_set_string(settings, prop_name, QT_TO_UTF8(id)); - } - obs_source_update(source, settings); -} - -void ComboSelectToolbar::on_device_currentIndexChanged(int idx) -{ - OBSSource source = GetSource(); - if (idx == -1 || !source) { - return; - } - - SaveOldProperties(source); - UpdateSourceComboToolbarValue(ui->device, source, idx, prop_name, is_int); - SetUndoProperties(source); -} - -AudioCaptureToolbar::AudioCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) {} - -void AudioCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = get_os_module("win-wasapi", "mac-capture", "linux-pulseaudio"); - if (!mod) - return; - - const char *device_str = get_os_text(mod, "Device", "CoreAudio.Device", "Device"); - ui->deviceLabel->setText(device_str); - - prop_name = "device_id"; - - ComboSelectToolbar::Init(); -} - -WindowCaptureToolbar::WindowCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) {} - -void WindowCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = get_os_module("win-capture", "mac-capture", "linux-capture"); - if (!mod) - return; - - const char *device_str = get_os_text(mod, "WindowCapture.Window", "WindowUtils.Window", "Window"); - ui->deviceLabel->setText(device_str); - -#if !defined(_WIN32) && !defined(__APPLE__) //linux - prop_name = "capture_window"; -#else - prop_name = "window"; -#endif - -#ifdef __APPLE__ - is_int = true; -#endif - - ComboSelectToolbar::Init(); -} - -ApplicationAudioCaptureToolbar::ApplicationAudioCaptureToolbar(QWidget *parent, OBSSource source) - : ComboSelectToolbar(parent, source) -{ -} - -void ApplicationAudioCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = obs_get_module("win-wasapi"); - const char *device_str = obs_module_get_locale_text(mod, "Window"); - ui->deviceLabel->setText(device_str); - - prop_name = "window"; - - ComboSelectToolbar::Init(); -} - -DisplayCaptureToolbar::DisplayCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) {} - -void DisplayCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = get_os_module("win-capture", "mac-capture", "linux-capture"); - if (!mod) - return; - - const char *device_str = get_os_text(mod, "Monitor", "DisplayCapture.Display", "Screen"); - ui->deviceLabel->setText(device_str); - -#ifdef _WIN32 - prop_name = "monitor_id"; -#elif __APPLE__ - prop_name = "display_uuid"; -#else - is_int = true; - prop_name = "screen"; -#endif - - ComboSelectToolbar::Init(); -} - -/* ========================================================================= */ - -DeviceCaptureToolbar::DeviceCaptureToolbar(QWidget *parent, OBSSource source) - : QWidget(parent), - weakSource(OBSGetWeakRef(source)), - ui(new Ui_DeviceSelectToolbar) -{ - ui->setupUi(this); - - delete ui->deviceLabel; - delete ui->device; - ui->deviceLabel = nullptr; - ui->device = nullptr; - - OBSDataAutoRelease settings = obs_source_get_settings(source); - active = obs_data_get_bool(settings, "active"); - - obs_module_t *mod = obs_get_module("win-dshow"); - if (!mod) - return; - - activateText = obs_module_get_locale_text(mod, "Activate"); - deactivateText = obs_module_get_locale_text(mod, "Deactivate"); - - ui->activateButton->setText(active ? deactivateText : activateText); -} - -DeviceCaptureToolbar::~DeviceCaptureToolbar() {} - -void DeviceCaptureToolbar::on_activateButton_clicked() -{ - OBSSource source = OBSGetStrongRef(weakSource); - if (!source) { - return; - } - - OBSDataAutoRelease settings = obs_source_get_settings(source); - bool now_active = obs_data_get_bool(settings, "active"); - - bool desyncedSetting = now_active != active; - - active = !active; - - const char *text = active ? deactivateText : activateText; - ui->activateButton->setText(text); - - if (desyncedSetting) { - return; - } - - calldata_t cd = {}; - calldata_set_bool(&cd, "active", active); - proc_handler_t *ph = obs_source_get_proc_handler(source); - proc_handler_call(ph, "activate", &cd); - calldata_free(&cd); -} - -/* ========================================================================= */ - -GameCaptureToolbar::GameCaptureToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_GameCaptureToolbar) -{ - obs_property_t *p; - int cur_idx; - - ui->setupUi(this); - - obs_module_t *mod = obs_get_module("win-capture"); - if (!mod) - return; - - ui->modeLabel->setText(obs_module_get_locale_text(mod, "Mode")); - ui->windowLabel->setText(obs_module_get_locale_text(mod, "WindowCapture.Window")); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - std::string cur_mode = obs_data_get_string(settings, "capture_mode"); - std::string cur_window = obs_data_get_string(settings, "window"); - - ui->mode->blockSignals(true); - p = obs_properties_get(props.get(), "capture_mode"); - cur_idx = FillPropertyCombo(ui->mode, p, cur_mode); - ui->mode->setCurrentIndex(cur_idx); - ui->mode->blockSignals(false); - - ui->window->blockSignals(true); - p = obs_properties_get(props.get(), "window"); - cur_idx = FillPropertyCombo(ui->window, p, cur_window); - ui->window->setCurrentIndex(cur_idx); - ui->window->blockSignals(false); - - if (cur_idx != -1 && obs_property_list_item_disabled(p, cur_idx)) { - SetComboItemEnabled(ui->window, cur_idx, false); - } - - UpdateWindowVisibility(); -} - -GameCaptureToolbar::~GameCaptureToolbar() {} - -void GameCaptureToolbar::UpdateWindowVisibility() -{ - QString mode = ui->mode->currentData().toString(); - bool is_window = (mode == "window"); - ui->windowLabel->setVisible(is_window); - ui->window->setVisible(is_window); -} - -void GameCaptureToolbar::on_mode_currentIndexChanged(int idx) -{ - OBSSource source = GetSource(); - if (idx == -1 || !source) { - return; - } - - QString id = ui->mode->itemData(idx).toString(); - - SaveOldProperties(source); - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_string(settings, "capture_mode", QT_TO_UTF8(id)); - obs_source_update(source, settings); - SetUndoProperties(source); - - UpdateWindowVisibility(); -} - -void GameCaptureToolbar::on_window_currentIndexChanged(int idx) -{ - OBSSource source = GetSource(); - if (idx == -1 || !source) { - return; - } - - QString id = ui->window->itemData(idx).toString(); - - SaveOldProperties(source); - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_string(settings, "window", QT_TO_UTF8(id)); - obs_source_update(source, settings); - SetUndoProperties(source); -} - -/* ========================================================================= */ - -ImageSourceToolbar::ImageSourceToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_ImageSourceToolbar) -{ - ui->setupUi(this); - - obs_module_t *mod = obs_get_module("image-source"); - ui->pathLabel->setText(obs_module_get_locale_text(mod, "File")); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - std::string file = obs_data_get_string(settings, "file"); - - ui->path->setText(file.c_str()); -} - -ImageSourceToolbar::~ImageSourceToolbar() {} - -void ImageSourceToolbar::on_browse_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - obs_property_t *p = obs_properties_get(props.get(), "file"); - const char *desc = obs_property_description(p); - const char *filter = obs_property_path_filter(p); - const char *default_path = obs_property_path_default_path(p); - - QString startDir = ui->path->text(); - if (startDir.isEmpty()) - startDir = default_path; - - QString path = OpenFile(this, desc, startDir, filter); - if (path.isEmpty()) { - return; - } - - ui->path->setText(path); - - SaveOldProperties(source); - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_string(settings, "file", QT_TO_UTF8(path)); - obs_source_update(source, settings); - SetUndoProperties(source); -} - -/* ========================================================================= */ - -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); -} - -ColorSourceToolbar::ColorSourceToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_ColorSourceToolbar) -{ - ui->setupUi(this); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - unsigned int val = (unsigned int)obs_data_get_int(settings, "color"); - - color = color_from_int(val); - UpdateColor(); -} - -ColorSourceToolbar::~ColorSourceToolbar() {} - -void ColorSourceToolbar::UpdateColor() -{ - QPalette palette = QPalette(color); - ui->color->setFrameStyle(QFrame::Sunken | QFrame::Panel); - ui->color->setText(color.name(QColor::HexRgb)); - ui->color->setPalette(palette); - ui->color->setStyleSheet(QString("background-color :%1; color: %2;") - .arg(palette.color(QPalette::Window).name(QColor::HexRgb)) - .arg(palette.color(QPalette::WindowText).name(QColor::HexRgb))); - ui->color->setAutoFillBackground(true); - ui->color->setAlignment(Qt::AlignCenter); -} - -void ColorSourceToolbar::on_choose_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - obs_property_t *p = obs_properties_get(props.get(), "color"); - const char *desc = obs_property_description(p); - - QColorDialog::ColorDialogOptions options; - - options |= QColorDialog::ShowAlphaChannel; -#ifdef __linux__ - // TODO: Revisit hang on Ubuntu with native dialog - options |= QColorDialog::DontUseNativeDialog; -#endif - - QColor newColor = QColorDialog::getColor(color, this, desc, options); - if (!newColor.isValid()) { - return; - } - - color = newColor; - UpdateColor(); - - SaveOldProperties(source); - - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_int(settings, "color", color_to_int(color)); - obs_source_update(source, settings); - - SetUndoProperties(source); -} - -/* ========================================================================= */ - -extern void MakeQFont(obs_data_t *font_obj, QFont &font, bool limit = false); - -TextSourceToolbar::TextSourceToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_TextSourceToolbar) -{ - ui->setupUi(this); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - - const char *id = obs_source_get_unversioned_id(source); - bool ft2 = strcmp(id, "text_ft2_source") == 0; - bool read_from_file = obs_data_get_bool(settings, ft2 ? "from_file" : "read_from_file"); - - OBSDataAutoRelease font_obj = obs_data_get_obj(settings, "font"); - MakeQFont(font_obj, font); - - // Use "color1" if it's a freetype source and "color" elsewise - unsigned int val = (unsigned int)obs_data_get_int( - settings, (strncmp(obs_source_get_id(source), "text_ft2_source", 15) == 0) ? "color1" : "color"); - - color = color_from_int(val); - - const char *text = obs_data_get_string(settings, "text"); - - bool single_line = !read_from_file && (!text || (strchr(text, '\n') == nullptr)); - ui->emptySpace->setVisible(!single_line); - ui->text->setVisible(single_line); - if (single_line) - ui->text->setText(text); -} - -TextSourceToolbar::~TextSourceToolbar() {} - -void TextSourceToolbar::on_selectFont_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - QFontDialog::FontDialogOptions options; - uint32_t flags; - bool success; - -#ifndef _WIN32 - options = QFontDialog::DontUseNativeDialog; -#endif - - font = QFontDialog::getFont(&success, font, this, QTStr("Basic.PropertiesWindow.SelectFont.WindowTitle"), - options); - if (!success) { - return; - } - - OBSDataAutoRelease font_obj = obs_data_create(); - - obs_data_set_string(font_obj, "face", QT_TO_UTF8(font.family())); - obs_data_set_string(font_obj, "style", QT_TO_UTF8(font.styleName())); - obs_data_set_int(font_obj, "size", font.pointSize()); - flags = font.bold() ? OBS_FONT_BOLD : 0; - flags |= font.italic() ? OBS_FONT_ITALIC : 0; - flags |= font.underline() ? OBS_FONT_UNDERLINE : 0; - flags |= font.strikeOut() ? OBS_FONT_STRIKEOUT : 0; - obs_data_set_int(font_obj, "flags", flags); - - SaveOldProperties(source); - - OBSDataAutoRelease settings = obs_data_create(); - - obs_data_set_obj(settings, "font", font_obj); - - obs_source_update(source, settings); - - SetUndoProperties(source); -} - -void TextSourceToolbar::on_selectColor_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - bool freetype = strncmp(obs_source_get_id(source), "text_ft2_source", 15) == 0; - - obs_property_t *p = obs_properties_get(props.get(), freetype ? "color1" : "color"); - - const char *desc = obs_property_description(p); - - QColorDialog::ColorDialogOptions options; - - options |= QColorDialog::ShowAlphaChannel; -#ifdef __linux__ - // TODO: Revisit hang on Ubuntu with native dialog - options |= QColorDialog::DontUseNativeDialog; -#endif - - QColor newColor = QColorDialog::getColor(color, this, desc, options); - if (!newColor.isValid()) { - return; - } - - color = newColor; - - SaveOldProperties(source); - - OBSDataAutoRelease settings = obs_data_create(); - if (freetype) { - obs_data_set_int(settings, "color1", color_to_int(color)); - obs_data_set_int(settings, "color2", color_to_int(color)); - } else { - obs_data_set_int(settings, "color", color_to_int(color)); - } - obs_source_update(source, settings); - - SetUndoProperties(source); -} - -void TextSourceToolbar::on_text_textChanged() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - std::string newText = QT_TO_UTF8(ui->text->text()); - OBSDataAutoRelease settings = obs_source_get_settings(source); - if (newText == obs_data_get_string(settings, "text")) { - return; - } - SaveOldProperties(source); - - obs_data_set_string(settings, "text", newText.c_str()); - obs_source_update(source, nullptr); - - SetUndoProperties(source, true); -} diff --git a/frontend/components/BrowserToolbar.hpp b/frontend/components/BrowserToolbar.hpp index acf88a5fb..6f37223c3 100644 --- a/frontend/components/BrowserToolbar.hpp +++ b/frontend/components/BrowserToolbar.hpp @@ -1,39 +1,8 @@ #pragma once -#include -#include -#include +#include "SourceToolbar.hpp" class Ui_BrowserSourceToolbar; -class Ui_DeviceSelectToolbar; -class Ui_GameCaptureToolbar; -class Ui_ImageSourceToolbar; -class Ui_ColorSourceToolbar; -class Ui_TextSourceToolbar; - -class SourceToolbar : public QWidget { - Q_OBJECT - - OBSWeakSource weakSource; - -protected: - using properties_delete_t = decltype(&obs_properties_destroy); - using properties_t = std::unique_ptr; - - properties_t props; - OBSDataAutoRelease oldData; - - void SaveOldProperties(obs_source_t *source); - void SetUndoProperties(obs_source_t *source, bool repeatable = false); - -public: - SourceToolbar(QWidget *parent, OBSSource source); - - OBSSource GetSource() { return OBSGetStrongRef(weakSource); } - -public slots: - virtual void Update() {} -}; class BrowserToolbar : public SourceToolbar { Q_OBJECT @@ -47,132 +16,3 @@ public: public slots: void on_refresh_clicked(); }; - -class ComboSelectToolbar : public SourceToolbar { - Q_OBJECT - -protected: - std::unique_ptr ui; - const char *prop_name; - bool is_int = false; - -public: - ComboSelectToolbar(QWidget *parent, OBSSource source); - ~ComboSelectToolbar(); - virtual void Init(); - -public slots: - void on_device_currentIndexChanged(int idx); -}; - -class AudioCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - AudioCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class WindowCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - WindowCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class ApplicationAudioCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - ApplicationAudioCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class DisplayCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - DisplayCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class DeviceCaptureToolbar : public QWidget { - Q_OBJECT - - OBSWeakSource weakSource; - - std::unique_ptr ui; - const char *activateText; - const char *deactivateText; - bool active; - -public: - DeviceCaptureToolbar(QWidget *parent, OBSSource source); - ~DeviceCaptureToolbar(); - -public slots: - void on_activateButton_clicked(); -}; - -class GameCaptureToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - - void UpdateWindowVisibility(); - -public: - GameCaptureToolbar(QWidget *parent, OBSSource source); - ~GameCaptureToolbar(); - -public slots: - void on_mode_currentIndexChanged(int idx); - void on_window_currentIndexChanged(int idx); -}; - -class ImageSourceToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - -public: - ImageSourceToolbar(QWidget *parent, OBSSource source); - ~ImageSourceToolbar(); - -public slots: - void on_browse_clicked(); -}; - -class ColorSourceToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - QColor color; - - void UpdateColor(); - -public: - ColorSourceToolbar(QWidget *parent, OBSSource source); - ~ColorSourceToolbar(); - -public slots: - void on_choose_clicked(); -}; - -class TextSourceToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - QFont font; - QColor color; - -public: - TextSourceToolbar(QWidget *parent, OBSSource source); - ~TextSourceToolbar(); - -public slots: - void on_selectFont_clicked(); - void on_selectColor_clicked(); - void on_text_textChanged(); -}; diff --git a/frontend/components/ColorSourceToolbar.cpp b/frontend/components/ColorSourceToolbar.cpp index c45d06976..dc4081acf 100644 --- a/frontend/components/ColorSourceToolbar.cpp +++ b/frontend/components/ColorSourceToolbar.cpp @@ -1,500 +1,16 @@ -#include "window-basic-main.hpp" -#include "moc_context-bar-controls.cpp" -#include "obs-app.hpp" - -#include -#include -#include -#include - -#include "ui_browser-source-toolbar.h" -#include "ui_device-select-toolbar.h" -#include "ui_game-capture-toolbar.h" -#include "ui_image-source-toolbar.h" +#include "ColorSourceToolbar.hpp" #include "ui_color-source-toolbar.h" -#include "ui_text-source-toolbar.h" -#ifdef _WIN32 -#define get_os_module(win, mac, linux) obs_get_module(win) -#define get_os_text(mod, win, mac, linux) obs_module_get_locale_text(mod, win) -#elif __APPLE__ -#define get_os_module(win, mac, linux) obs_get_module(mac) -#define get_os_text(mod, win, mac, linux) obs_module_get_locale_text(mod, mac) -#else -#define get_os_module(win, mac, linux) obs_get_module(linux) -#define get_os_text(mod, win, mac, linux) obs_module_get_locale_text(mod, linux) -#endif +#include -/* ========================================================================= */ +#include "moc_ColorSourceToolbar.cpp" -SourceToolbar::SourceToolbar(QWidget *parent, OBSSource source) - : QWidget(parent), - weakSource(OBSGetWeakRef(source)), - props(obs_source_properties(source), obs_properties_destroy) -{ -} - -void SourceToolbar::SaveOldProperties(obs_source_t *source) -{ - oldData = obs_data_create(); - - OBSDataAutoRelease oldSettings = obs_source_get_settings(source); - obs_data_apply(oldData, oldSettings); - obs_data_set_string(oldData, "undo_suuid", obs_source_get_uuid(source)); -} - -void SourceToolbar::SetUndoProperties(obs_source_t *source, bool repeatable) -{ - if (!oldData) { - blog(LOG_ERROR, "%s: somehow oldData was null.", __FUNCTION__); - return; - } - - OBSBasic *main = reinterpret_cast(App()->GetMainWindow()); - - OBSSource currentSceneSource = main->GetCurrentSceneSource(); - if (!currentSceneSource) - return; - std::string scene_uuid = obs_source_get_uuid(currentSceneSource); - auto undo_redo = [scene_uuid = std::move(scene_uuid), main](const std::string &data) { - OBSDataAutoRelease settings = obs_data_create_from_json(data.c_str()); - OBSSourceAutoRelease source = obs_get_source_by_uuid(obs_data_get_string(settings, "undo_suuid")); - obs_source_reset_settings(source, settings); - - OBSSourceAutoRelease scene_source = obs_get_source_by_uuid(scene_uuid.c_str()); - main->SetCurrentScene(scene_source.Get(), true); - - main->UpdateContextBar(); - }; - - OBSDataAutoRelease new_settings = obs_data_create(); - OBSDataAutoRelease curr_settings = obs_source_get_settings(source); - obs_data_apply(new_settings, curr_settings); - obs_data_set_string(new_settings, "undo_suuid", obs_source_get_uuid(source)); - - std::string undo_data(obs_data_get_json(oldData)); - std::string redo_data(obs_data_get_json(new_settings)); - - if (undo_data.compare(redo_data) != 0) - main->undo_s.add_action(QTStr("Undo.Properties").arg(obs_source_get_name(source)), undo_redo, undo_redo, - undo_data, redo_data, repeatable); - - oldData = nullptr; -} - -/* ========================================================================= */ - -BrowserToolbar::BrowserToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_BrowserSourceToolbar) -{ - ui->setupUi(this); -} - -BrowserToolbar::~BrowserToolbar() {} - -void BrowserToolbar::on_refresh_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - obs_property_t *p = obs_properties_get(props.get(), "refreshnocache"); - obs_property_button_clicked(p, source.Get()); -} - -/* ========================================================================= */ - -ComboSelectToolbar::ComboSelectToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_DeviceSelectToolbar) -{ - ui->setupUi(this); -} - -ComboSelectToolbar::~ComboSelectToolbar() {} - -static int FillPropertyCombo(QComboBox *c, obs_property_t *p, const std::string &cur_id, bool is_int = false) -{ - size_t count = obs_property_list_item_count(p); - int cur_idx = -1; - - for (size_t i = 0; i < count; i++) { - const char *name = obs_property_list_item_name(p, i); - std::string id; - - if (is_int) { - id = std::to_string(obs_property_list_item_int(p, i)); - } else { - const char *val = obs_property_list_item_string(p, i); - id = val ? val : ""; - } - - if (cur_id == id) - cur_idx = (int)i; - - c->addItem(name, id.c_str()); - } - - return cur_idx; -} - -void UpdateSourceComboToolbarProperties(QComboBox *combo, OBSSource source, obs_properties_t *props, - const char *prop_name, bool is_int) -{ - std::string cur_id; - - OBSDataAutoRelease settings = obs_source_get_settings(source); - if (is_int) { - cur_id = std::to_string(obs_data_get_int(settings, prop_name)); - } else { - cur_id = obs_data_get_string(settings, prop_name); - } - - combo->blockSignals(true); - - obs_property_t *p = obs_properties_get(props, prop_name); - int cur_idx = FillPropertyCombo(combo, p, cur_id, is_int); - - if (cur_idx == -1 || obs_property_list_item_disabled(p, cur_idx)) { - if (cur_idx == -1) { - combo->insertItem(0, QTStr("Basic.Settings.Audio.UnknownAudioDevice")); - cur_idx = 0; - } - - SetComboItemEnabled(combo, cur_idx, false); - } - - combo->setCurrentIndex(cur_idx); - combo->blockSignals(false); -} - -void ComboSelectToolbar::Init() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - UpdateSourceComboToolbarProperties(ui->device, source, props.get(), prop_name, is_int); -} - -void UpdateSourceComboToolbarValue(QComboBox *combo, OBSSource source, int idx, const char *prop_name, bool is_int) -{ - QString id = combo->itemData(idx).toString(); - - OBSDataAutoRelease settings = obs_data_create(); - if (is_int) { - obs_data_set_int(settings, prop_name, id.toInt()); - } else { - obs_data_set_string(settings, prop_name, QT_TO_UTF8(id)); - } - obs_source_update(source, settings); -} - -void ComboSelectToolbar::on_device_currentIndexChanged(int idx) -{ - OBSSource source = GetSource(); - if (idx == -1 || !source) { - return; - } - - SaveOldProperties(source); - UpdateSourceComboToolbarValue(ui->device, source, idx, prop_name, is_int); - SetUndoProperties(source); -} - -AudioCaptureToolbar::AudioCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) {} - -void AudioCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = get_os_module("win-wasapi", "mac-capture", "linux-pulseaudio"); - if (!mod) - return; - - const char *device_str = get_os_text(mod, "Device", "CoreAudio.Device", "Device"); - ui->deviceLabel->setText(device_str); - - prop_name = "device_id"; - - ComboSelectToolbar::Init(); -} - -WindowCaptureToolbar::WindowCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) {} - -void WindowCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = get_os_module("win-capture", "mac-capture", "linux-capture"); - if (!mod) - return; - - const char *device_str = get_os_text(mod, "WindowCapture.Window", "WindowUtils.Window", "Window"); - ui->deviceLabel->setText(device_str); - -#if !defined(_WIN32) && !defined(__APPLE__) //linux - prop_name = "capture_window"; -#else - prop_name = "window"; -#endif - -#ifdef __APPLE__ - is_int = true; -#endif - - ComboSelectToolbar::Init(); -} - -ApplicationAudioCaptureToolbar::ApplicationAudioCaptureToolbar(QWidget *parent, OBSSource source) - : ComboSelectToolbar(parent, source) -{ -} - -void ApplicationAudioCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = obs_get_module("win-wasapi"); - const char *device_str = obs_module_get_locale_text(mod, "Window"); - ui->deviceLabel->setText(device_str); - - prop_name = "window"; - - ComboSelectToolbar::Init(); -} - -DisplayCaptureToolbar::DisplayCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) {} - -void DisplayCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = get_os_module("win-capture", "mac-capture", "linux-capture"); - if (!mod) - return; - - const char *device_str = get_os_text(mod, "Monitor", "DisplayCapture.Display", "Screen"); - ui->deviceLabel->setText(device_str); - -#ifdef _WIN32 - prop_name = "monitor_id"; -#elif __APPLE__ - prop_name = "display_uuid"; -#else - is_int = true; - prop_name = "screen"; -#endif - - ComboSelectToolbar::Init(); -} - -/* ========================================================================= */ - -DeviceCaptureToolbar::DeviceCaptureToolbar(QWidget *parent, OBSSource source) - : QWidget(parent), - weakSource(OBSGetWeakRef(source)), - ui(new Ui_DeviceSelectToolbar) -{ - ui->setupUi(this); - - delete ui->deviceLabel; - delete ui->device; - ui->deviceLabel = nullptr; - ui->device = nullptr; - - OBSDataAutoRelease settings = obs_source_get_settings(source); - active = obs_data_get_bool(settings, "active"); - - obs_module_t *mod = obs_get_module("win-dshow"); - if (!mod) - return; - - activateText = obs_module_get_locale_text(mod, "Activate"); - deactivateText = obs_module_get_locale_text(mod, "Deactivate"); - - ui->activateButton->setText(active ? deactivateText : activateText); -} - -DeviceCaptureToolbar::~DeviceCaptureToolbar() {} - -void DeviceCaptureToolbar::on_activateButton_clicked() -{ - OBSSource source = OBSGetStrongRef(weakSource); - if (!source) { - return; - } - - OBSDataAutoRelease settings = obs_source_get_settings(source); - bool now_active = obs_data_get_bool(settings, "active"); - - bool desyncedSetting = now_active != active; - - active = !active; - - const char *text = active ? deactivateText : activateText; - ui->activateButton->setText(text); - - if (desyncedSetting) { - return; - } - - calldata_t cd = {}; - calldata_set_bool(&cd, "active", active); - proc_handler_t *ph = obs_source_get_proc_handler(source); - proc_handler_call(ph, "activate", &cd); - calldata_free(&cd); -} - -/* ========================================================================= */ - -GameCaptureToolbar::GameCaptureToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_GameCaptureToolbar) -{ - obs_property_t *p; - int cur_idx; - - ui->setupUi(this); - - obs_module_t *mod = obs_get_module("win-capture"); - if (!mod) - return; - - ui->modeLabel->setText(obs_module_get_locale_text(mod, "Mode")); - ui->windowLabel->setText(obs_module_get_locale_text(mod, "WindowCapture.Window")); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - std::string cur_mode = obs_data_get_string(settings, "capture_mode"); - std::string cur_window = obs_data_get_string(settings, "window"); - - ui->mode->blockSignals(true); - p = obs_properties_get(props.get(), "capture_mode"); - cur_idx = FillPropertyCombo(ui->mode, p, cur_mode); - ui->mode->setCurrentIndex(cur_idx); - ui->mode->blockSignals(false); - - ui->window->blockSignals(true); - p = obs_properties_get(props.get(), "window"); - cur_idx = FillPropertyCombo(ui->window, p, cur_window); - ui->window->setCurrentIndex(cur_idx); - ui->window->blockSignals(false); - - if (cur_idx != -1 && obs_property_list_item_disabled(p, cur_idx)) { - SetComboItemEnabled(ui->window, cur_idx, false); - } - - UpdateWindowVisibility(); -} - -GameCaptureToolbar::~GameCaptureToolbar() {} - -void GameCaptureToolbar::UpdateWindowVisibility() -{ - QString mode = ui->mode->currentData().toString(); - bool is_window = (mode == "window"); - ui->windowLabel->setVisible(is_window); - ui->window->setVisible(is_window); -} - -void GameCaptureToolbar::on_mode_currentIndexChanged(int idx) -{ - OBSSource source = GetSource(); - if (idx == -1 || !source) { - return; - } - - QString id = ui->mode->itemData(idx).toString(); - - SaveOldProperties(source); - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_string(settings, "capture_mode", QT_TO_UTF8(id)); - obs_source_update(source, settings); - SetUndoProperties(source); - - UpdateWindowVisibility(); -} - -void GameCaptureToolbar::on_window_currentIndexChanged(int idx) -{ - OBSSource source = GetSource(); - if (idx == -1 || !source) { - return; - } - - QString id = ui->window->itemData(idx).toString(); - - SaveOldProperties(source); - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_string(settings, "window", QT_TO_UTF8(id)); - obs_source_update(source, settings); - SetUndoProperties(source); -} - -/* ========================================================================= */ - -ImageSourceToolbar::ImageSourceToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_ImageSourceToolbar) -{ - ui->setupUi(this); - - obs_module_t *mod = obs_get_module("image-source"); - ui->pathLabel->setText(obs_module_get_locale_text(mod, "File")); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - std::string file = obs_data_get_string(settings, "file"); - - ui->path->setText(file.c_str()); -} - -ImageSourceToolbar::~ImageSourceToolbar() {} - -void ImageSourceToolbar::on_browse_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - obs_property_t *p = obs_properties_get(props.get(), "file"); - const char *desc = obs_property_description(p); - const char *filter = obs_property_path_filter(p); - const char *default_path = obs_property_path_default_path(p); - - QString startDir = ui->path->text(); - if (startDir.isEmpty()) - startDir = default_path; - - QString path = OpenFile(this, desc, startDir, filter); - if (path.isEmpty()) { - return; - } - - ui->path->setText(path); - - SaveOldProperties(source); - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_string(settings, "file", QT_TO_UTF8(path)); - obs_source_update(source, settings); - SetUndoProperties(source); -} - -/* ========================================================================= */ - -static inline QColor color_from_int(long long val) +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) +long long color_to_int(QColor color) { auto shift = [&](unsigned val, int shift) { return ((val & 0xff) << shift); @@ -565,143 +81,3 @@ void ColorSourceToolbar::on_choose_clicked() SetUndoProperties(source); } - -/* ========================================================================= */ - -extern void MakeQFont(obs_data_t *font_obj, QFont &font, bool limit = false); - -TextSourceToolbar::TextSourceToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_TextSourceToolbar) -{ - ui->setupUi(this); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - - const char *id = obs_source_get_unversioned_id(source); - bool ft2 = strcmp(id, "text_ft2_source") == 0; - bool read_from_file = obs_data_get_bool(settings, ft2 ? "from_file" : "read_from_file"); - - OBSDataAutoRelease font_obj = obs_data_get_obj(settings, "font"); - MakeQFont(font_obj, font); - - // Use "color1" if it's a freetype source and "color" elsewise - unsigned int val = (unsigned int)obs_data_get_int( - settings, (strncmp(obs_source_get_id(source), "text_ft2_source", 15) == 0) ? "color1" : "color"); - - color = color_from_int(val); - - const char *text = obs_data_get_string(settings, "text"); - - bool single_line = !read_from_file && (!text || (strchr(text, '\n') == nullptr)); - ui->emptySpace->setVisible(!single_line); - ui->text->setVisible(single_line); - if (single_line) - ui->text->setText(text); -} - -TextSourceToolbar::~TextSourceToolbar() {} - -void TextSourceToolbar::on_selectFont_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - QFontDialog::FontDialogOptions options; - uint32_t flags; - bool success; - -#ifndef _WIN32 - options = QFontDialog::DontUseNativeDialog; -#endif - - font = QFontDialog::getFont(&success, font, this, QTStr("Basic.PropertiesWindow.SelectFont.WindowTitle"), - options); - if (!success) { - return; - } - - OBSDataAutoRelease font_obj = obs_data_create(); - - obs_data_set_string(font_obj, "face", QT_TO_UTF8(font.family())); - obs_data_set_string(font_obj, "style", QT_TO_UTF8(font.styleName())); - obs_data_set_int(font_obj, "size", font.pointSize()); - flags = font.bold() ? OBS_FONT_BOLD : 0; - flags |= font.italic() ? OBS_FONT_ITALIC : 0; - flags |= font.underline() ? OBS_FONT_UNDERLINE : 0; - flags |= font.strikeOut() ? OBS_FONT_STRIKEOUT : 0; - obs_data_set_int(font_obj, "flags", flags); - - SaveOldProperties(source); - - OBSDataAutoRelease settings = obs_data_create(); - - obs_data_set_obj(settings, "font", font_obj); - - obs_source_update(source, settings); - - SetUndoProperties(source); -} - -void TextSourceToolbar::on_selectColor_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - bool freetype = strncmp(obs_source_get_id(source), "text_ft2_source", 15) == 0; - - obs_property_t *p = obs_properties_get(props.get(), freetype ? "color1" : "color"); - - const char *desc = obs_property_description(p); - - QColorDialog::ColorDialogOptions options; - - options |= QColorDialog::ShowAlphaChannel; -#ifdef __linux__ - // TODO: Revisit hang on Ubuntu with native dialog - options |= QColorDialog::DontUseNativeDialog; -#endif - - QColor newColor = QColorDialog::getColor(color, this, desc, options); - if (!newColor.isValid()) { - return; - } - - color = newColor; - - SaveOldProperties(source); - - OBSDataAutoRelease settings = obs_data_create(); - if (freetype) { - obs_data_set_int(settings, "color1", color_to_int(color)); - obs_data_set_int(settings, "color2", color_to_int(color)); - } else { - obs_data_set_int(settings, "color", color_to_int(color)); - } - obs_source_update(source, settings); - - SetUndoProperties(source); -} - -void TextSourceToolbar::on_text_textChanged() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - std::string newText = QT_TO_UTF8(ui->text->text()); - OBSDataAutoRelease settings = obs_source_get_settings(source); - if (newText == obs_data_get_string(settings, "text")) { - return; - } - SaveOldProperties(source); - - obs_data_set_string(settings, "text", newText.c_str()); - obs_source_update(source, nullptr); - - SetUndoProperties(source, true); -} diff --git a/frontend/components/ColorSourceToolbar.hpp b/frontend/components/ColorSourceToolbar.hpp index acf88a5fb..dc05f0736 100644 --- a/frontend/components/ColorSourceToolbar.hpp +++ b/frontend/components/ColorSourceToolbar.hpp @@ -1,148 +1,8 @@ #pragma once -#include -#include -#include +#include "SourceToolbar.hpp" -class Ui_BrowserSourceToolbar; -class Ui_DeviceSelectToolbar; -class Ui_GameCaptureToolbar; -class Ui_ImageSourceToolbar; class Ui_ColorSourceToolbar; -class Ui_TextSourceToolbar; - -class SourceToolbar : public QWidget { - Q_OBJECT - - OBSWeakSource weakSource; - -protected: - using properties_delete_t = decltype(&obs_properties_destroy); - using properties_t = std::unique_ptr; - - properties_t props; - OBSDataAutoRelease oldData; - - void SaveOldProperties(obs_source_t *source); - void SetUndoProperties(obs_source_t *source, bool repeatable = false); - -public: - SourceToolbar(QWidget *parent, OBSSource source); - - OBSSource GetSource() { return OBSGetStrongRef(weakSource); } - -public slots: - virtual void Update() {} -}; - -class BrowserToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - -public: - BrowserToolbar(QWidget *parent, OBSSource source); - ~BrowserToolbar(); - -public slots: - void on_refresh_clicked(); -}; - -class ComboSelectToolbar : public SourceToolbar { - Q_OBJECT - -protected: - std::unique_ptr ui; - const char *prop_name; - bool is_int = false; - -public: - ComboSelectToolbar(QWidget *parent, OBSSource source); - ~ComboSelectToolbar(); - virtual void Init(); - -public slots: - void on_device_currentIndexChanged(int idx); -}; - -class AudioCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - AudioCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class WindowCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - WindowCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class ApplicationAudioCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - ApplicationAudioCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class DisplayCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - DisplayCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class DeviceCaptureToolbar : public QWidget { - Q_OBJECT - - OBSWeakSource weakSource; - - std::unique_ptr ui; - const char *activateText; - const char *deactivateText; - bool active; - -public: - DeviceCaptureToolbar(QWidget *parent, OBSSource source); - ~DeviceCaptureToolbar(); - -public slots: - void on_activateButton_clicked(); -}; - -class GameCaptureToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - - void UpdateWindowVisibility(); - -public: - GameCaptureToolbar(QWidget *parent, OBSSource source); - ~GameCaptureToolbar(); - -public slots: - void on_mode_currentIndexChanged(int idx); - void on_window_currentIndexChanged(int idx); -}; - -class ImageSourceToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - -public: - ImageSourceToolbar(QWidget *parent, OBSSource source); - ~ImageSourceToolbar(); - -public slots: - void on_browse_clicked(); -}; class ColorSourceToolbar : public SourceToolbar { Q_OBJECT @@ -159,20 +19,3 @@ public: public slots: void on_choose_clicked(); }; - -class TextSourceToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - QFont font; - QColor color; - -public: - TextSourceToolbar(QWidget *parent, OBSSource source); - ~TextSourceToolbar(); - -public slots: - void on_selectFont_clicked(); - void on_selectColor_clicked(); - void on_text_textChanged(); -}; diff --git a/frontend/components/ComboSelectToolbar.cpp b/frontend/components/ComboSelectToolbar.cpp index c45d06976..77a0364d7 100644 --- a/frontend/components/ComboSelectToolbar.cpp +++ b/frontend/components/ComboSelectToolbar.cpp @@ -1,110 +1,10 @@ -#include "window-basic-main.hpp" -#include "moc_context-bar-controls.cpp" -#include "obs-app.hpp" - -#include -#include -#include -#include - -#include "ui_browser-source-toolbar.h" +#include "ComboSelectToolbar.hpp" #include "ui_device-select-toolbar.h" -#include "ui_game-capture-toolbar.h" -#include "ui_image-source-toolbar.h" -#include "ui_color-source-toolbar.h" -#include "ui_text-source-toolbar.h" -#ifdef _WIN32 -#define get_os_module(win, mac, linux) obs_get_module(win) -#define get_os_text(mod, win, mac, linux) obs_module_get_locale_text(mod, win) -#elif __APPLE__ -#define get_os_module(win, mac, linux) obs_get_module(mac) -#define get_os_text(mod, win, mac, linux) obs_module_get_locale_text(mod, mac) -#else -#define get_os_module(win, mac, linux) obs_get_module(linux) -#define get_os_text(mod, win, mac, linux) obs_module_get_locale_text(mod, linux) -#endif +#include +#include -/* ========================================================================= */ - -SourceToolbar::SourceToolbar(QWidget *parent, OBSSource source) - : QWidget(parent), - weakSource(OBSGetWeakRef(source)), - props(obs_source_properties(source), obs_properties_destroy) -{ -} - -void SourceToolbar::SaveOldProperties(obs_source_t *source) -{ - oldData = obs_data_create(); - - OBSDataAutoRelease oldSettings = obs_source_get_settings(source); - obs_data_apply(oldData, oldSettings); - obs_data_set_string(oldData, "undo_suuid", obs_source_get_uuid(source)); -} - -void SourceToolbar::SetUndoProperties(obs_source_t *source, bool repeatable) -{ - if (!oldData) { - blog(LOG_ERROR, "%s: somehow oldData was null.", __FUNCTION__); - return; - } - - OBSBasic *main = reinterpret_cast(App()->GetMainWindow()); - - OBSSource currentSceneSource = main->GetCurrentSceneSource(); - if (!currentSceneSource) - return; - std::string scene_uuid = obs_source_get_uuid(currentSceneSource); - auto undo_redo = [scene_uuid = std::move(scene_uuid), main](const std::string &data) { - OBSDataAutoRelease settings = obs_data_create_from_json(data.c_str()); - OBSSourceAutoRelease source = obs_get_source_by_uuid(obs_data_get_string(settings, "undo_suuid")); - obs_source_reset_settings(source, settings); - - OBSSourceAutoRelease scene_source = obs_get_source_by_uuid(scene_uuid.c_str()); - main->SetCurrentScene(scene_source.Get(), true); - - main->UpdateContextBar(); - }; - - OBSDataAutoRelease new_settings = obs_data_create(); - OBSDataAutoRelease curr_settings = obs_source_get_settings(source); - obs_data_apply(new_settings, curr_settings); - obs_data_set_string(new_settings, "undo_suuid", obs_source_get_uuid(source)); - - std::string undo_data(obs_data_get_json(oldData)); - std::string redo_data(obs_data_get_json(new_settings)); - - if (undo_data.compare(redo_data) != 0) - main->undo_s.add_action(QTStr("Undo.Properties").arg(obs_source_get_name(source)), undo_redo, undo_redo, - undo_data, redo_data, repeatable); - - oldData = nullptr; -} - -/* ========================================================================= */ - -BrowserToolbar::BrowserToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_BrowserSourceToolbar) -{ - ui->setupUi(this); -} - -BrowserToolbar::~BrowserToolbar() {} - -void BrowserToolbar::on_refresh_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - obs_property_t *p = obs_properties_get(props.get(), "refreshnocache"); - obs_property_button_clicked(p, source.Get()); -} - -/* ========================================================================= */ +#include "moc_ComboSelectToolbar.cpp" ComboSelectToolbar::ComboSelectToolbar(QWidget *parent, OBSSource source) : SourceToolbar(parent, source), @@ -115,7 +15,7 @@ ComboSelectToolbar::ComboSelectToolbar(QWidget *parent, OBSSource source) ComboSelectToolbar::~ComboSelectToolbar() {} -static int FillPropertyCombo(QComboBox *c, obs_property_t *p, const std::string &cur_id, bool is_int = false) +int FillPropertyCombo(QComboBox *c, obs_property_t *p, const std::string &cur_id, bool is_int = false) { size_t count = obs_property_list_item_count(p); int cur_idx = -1; @@ -204,504 +104,3 @@ void ComboSelectToolbar::on_device_currentIndexChanged(int idx) UpdateSourceComboToolbarValue(ui->device, source, idx, prop_name, is_int); SetUndoProperties(source); } - -AudioCaptureToolbar::AudioCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) {} - -void AudioCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = get_os_module("win-wasapi", "mac-capture", "linux-pulseaudio"); - if (!mod) - return; - - const char *device_str = get_os_text(mod, "Device", "CoreAudio.Device", "Device"); - ui->deviceLabel->setText(device_str); - - prop_name = "device_id"; - - ComboSelectToolbar::Init(); -} - -WindowCaptureToolbar::WindowCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) {} - -void WindowCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = get_os_module("win-capture", "mac-capture", "linux-capture"); - if (!mod) - return; - - const char *device_str = get_os_text(mod, "WindowCapture.Window", "WindowUtils.Window", "Window"); - ui->deviceLabel->setText(device_str); - -#if !defined(_WIN32) && !defined(__APPLE__) //linux - prop_name = "capture_window"; -#else - prop_name = "window"; -#endif - -#ifdef __APPLE__ - is_int = true; -#endif - - ComboSelectToolbar::Init(); -} - -ApplicationAudioCaptureToolbar::ApplicationAudioCaptureToolbar(QWidget *parent, OBSSource source) - : ComboSelectToolbar(parent, source) -{ -} - -void ApplicationAudioCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = obs_get_module("win-wasapi"); - const char *device_str = obs_module_get_locale_text(mod, "Window"); - ui->deviceLabel->setText(device_str); - - prop_name = "window"; - - ComboSelectToolbar::Init(); -} - -DisplayCaptureToolbar::DisplayCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) {} - -void DisplayCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = get_os_module("win-capture", "mac-capture", "linux-capture"); - if (!mod) - return; - - const char *device_str = get_os_text(mod, "Monitor", "DisplayCapture.Display", "Screen"); - ui->deviceLabel->setText(device_str); - -#ifdef _WIN32 - prop_name = "monitor_id"; -#elif __APPLE__ - prop_name = "display_uuid"; -#else - is_int = true; - prop_name = "screen"; -#endif - - ComboSelectToolbar::Init(); -} - -/* ========================================================================= */ - -DeviceCaptureToolbar::DeviceCaptureToolbar(QWidget *parent, OBSSource source) - : QWidget(parent), - weakSource(OBSGetWeakRef(source)), - ui(new Ui_DeviceSelectToolbar) -{ - ui->setupUi(this); - - delete ui->deviceLabel; - delete ui->device; - ui->deviceLabel = nullptr; - ui->device = nullptr; - - OBSDataAutoRelease settings = obs_source_get_settings(source); - active = obs_data_get_bool(settings, "active"); - - obs_module_t *mod = obs_get_module("win-dshow"); - if (!mod) - return; - - activateText = obs_module_get_locale_text(mod, "Activate"); - deactivateText = obs_module_get_locale_text(mod, "Deactivate"); - - ui->activateButton->setText(active ? deactivateText : activateText); -} - -DeviceCaptureToolbar::~DeviceCaptureToolbar() {} - -void DeviceCaptureToolbar::on_activateButton_clicked() -{ - OBSSource source = OBSGetStrongRef(weakSource); - if (!source) { - return; - } - - OBSDataAutoRelease settings = obs_source_get_settings(source); - bool now_active = obs_data_get_bool(settings, "active"); - - bool desyncedSetting = now_active != active; - - active = !active; - - const char *text = active ? deactivateText : activateText; - ui->activateButton->setText(text); - - if (desyncedSetting) { - return; - } - - calldata_t cd = {}; - calldata_set_bool(&cd, "active", active); - proc_handler_t *ph = obs_source_get_proc_handler(source); - proc_handler_call(ph, "activate", &cd); - calldata_free(&cd); -} - -/* ========================================================================= */ - -GameCaptureToolbar::GameCaptureToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_GameCaptureToolbar) -{ - obs_property_t *p; - int cur_idx; - - ui->setupUi(this); - - obs_module_t *mod = obs_get_module("win-capture"); - if (!mod) - return; - - ui->modeLabel->setText(obs_module_get_locale_text(mod, "Mode")); - ui->windowLabel->setText(obs_module_get_locale_text(mod, "WindowCapture.Window")); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - std::string cur_mode = obs_data_get_string(settings, "capture_mode"); - std::string cur_window = obs_data_get_string(settings, "window"); - - ui->mode->blockSignals(true); - p = obs_properties_get(props.get(), "capture_mode"); - cur_idx = FillPropertyCombo(ui->mode, p, cur_mode); - ui->mode->setCurrentIndex(cur_idx); - ui->mode->blockSignals(false); - - ui->window->blockSignals(true); - p = obs_properties_get(props.get(), "window"); - cur_idx = FillPropertyCombo(ui->window, p, cur_window); - ui->window->setCurrentIndex(cur_idx); - ui->window->blockSignals(false); - - if (cur_idx != -1 && obs_property_list_item_disabled(p, cur_idx)) { - SetComboItemEnabled(ui->window, cur_idx, false); - } - - UpdateWindowVisibility(); -} - -GameCaptureToolbar::~GameCaptureToolbar() {} - -void GameCaptureToolbar::UpdateWindowVisibility() -{ - QString mode = ui->mode->currentData().toString(); - bool is_window = (mode == "window"); - ui->windowLabel->setVisible(is_window); - ui->window->setVisible(is_window); -} - -void GameCaptureToolbar::on_mode_currentIndexChanged(int idx) -{ - OBSSource source = GetSource(); - if (idx == -1 || !source) { - return; - } - - QString id = ui->mode->itemData(idx).toString(); - - SaveOldProperties(source); - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_string(settings, "capture_mode", QT_TO_UTF8(id)); - obs_source_update(source, settings); - SetUndoProperties(source); - - UpdateWindowVisibility(); -} - -void GameCaptureToolbar::on_window_currentIndexChanged(int idx) -{ - OBSSource source = GetSource(); - if (idx == -1 || !source) { - return; - } - - QString id = ui->window->itemData(idx).toString(); - - SaveOldProperties(source); - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_string(settings, "window", QT_TO_UTF8(id)); - obs_source_update(source, settings); - SetUndoProperties(source); -} - -/* ========================================================================= */ - -ImageSourceToolbar::ImageSourceToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_ImageSourceToolbar) -{ - ui->setupUi(this); - - obs_module_t *mod = obs_get_module("image-source"); - ui->pathLabel->setText(obs_module_get_locale_text(mod, "File")); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - std::string file = obs_data_get_string(settings, "file"); - - ui->path->setText(file.c_str()); -} - -ImageSourceToolbar::~ImageSourceToolbar() {} - -void ImageSourceToolbar::on_browse_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - obs_property_t *p = obs_properties_get(props.get(), "file"); - const char *desc = obs_property_description(p); - const char *filter = obs_property_path_filter(p); - const char *default_path = obs_property_path_default_path(p); - - QString startDir = ui->path->text(); - if (startDir.isEmpty()) - startDir = default_path; - - QString path = OpenFile(this, desc, startDir, filter); - if (path.isEmpty()) { - return; - } - - ui->path->setText(path); - - SaveOldProperties(source); - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_string(settings, "file", QT_TO_UTF8(path)); - obs_source_update(source, settings); - SetUndoProperties(source); -} - -/* ========================================================================= */ - -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); -} - -ColorSourceToolbar::ColorSourceToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_ColorSourceToolbar) -{ - ui->setupUi(this); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - unsigned int val = (unsigned int)obs_data_get_int(settings, "color"); - - color = color_from_int(val); - UpdateColor(); -} - -ColorSourceToolbar::~ColorSourceToolbar() {} - -void ColorSourceToolbar::UpdateColor() -{ - QPalette palette = QPalette(color); - ui->color->setFrameStyle(QFrame::Sunken | QFrame::Panel); - ui->color->setText(color.name(QColor::HexRgb)); - ui->color->setPalette(palette); - ui->color->setStyleSheet(QString("background-color :%1; color: %2;") - .arg(palette.color(QPalette::Window).name(QColor::HexRgb)) - .arg(palette.color(QPalette::WindowText).name(QColor::HexRgb))); - ui->color->setAutoFillBackground(true); - ui->color->setAlignment(Qt::AlignCenter); -} - -void ColorSourceToolbar::on_choose_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - obs_property_t *p = obs_properties_get(props.get(), "color"); - const char *desc = obs_property_description(p); - - QColorDialog::ColorDialogOptions options; - - options |= QColorDialog::ShowAlphaChannel; -#ifdef __linux__ - // TODO: Revisit hang on Ubuntu with native dialog - options |= QColorDialog::DontUseNativeDialog; -#endif - - QColor newColor = QColorDialog::getColor(color, this, desc, options); - if (!newColor.isValid()) { - return; - } - - color = newColor; - UpdateColor(); - - SaveOldProperties(source); - - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_int(settings, "color", color_to_int(color)); - obs_source_update(source, settings); - - SetUndoProperties(source); -} - -/* ========================================================================= */ - -extern void MakeQFont(obs_data_t *font_obj, QFont &font, bool limit = false); - -TextSourceToolbar::TextSourceToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_TextSourceToolbar) -{ - ui->setupUi(this); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - - const char *id = obs_source_get_unversioned_id(source); - bool ft2 = strcmp(id, "text_ft2_source") == 0; - bool read_from_file = obs_data_get_bool(settings, ft2 ? "from_file" : "read_from_file"); - - OBSDataAutoRelease font_obj = obs_data_get_obj(settings, "font"); - MakeQFont(font_obj, font); - - // Use "color1" if it's a freetype source and "color" elsewise - unsigned int val = (unsigned int)obs_data_get_int( - settings, (strncmp(obs_source_get_id(source), "text_ft2_source", 15) == 0) ? "color1" : "color"); - - color = color_from_int(val); - - const char *text = obs_data_get_string(settings, "text"); - - bool single_line = !read_from_file && (!text || (strchr(text, '\n') == nullptr)); - ui->emptySpace->setVisible(!single_line); - ui->text->setVisible(single_line); - if (single_line) - ui->text->setText(text); -} - -TextSourceToolbar::~TextSourceToolbar() {} - -void TextSourceToolbar::on_selectFont_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - QFontDialog::FontDialogOptions options; - uint32_t flags; - bool success; - -#ifndef _WIN32 - options = QFontDialog::DontUseNativeDialog; -#endif - - font = QFontDialog::getFont(&success, font, this, QTStr("Basic.PropertiesWindow.SelectFont.WindowTitle"), - options); - if (!success) { - return; - } - - OBSDataAutoRelease font_obj = obs_data_create(); - - obs_data_set_string(font_obj, "face", QT_TO_UTF8(font.family())); - obs_data_set_string(font_obj, "style", QT_TO_UTF8(font.styleName())); - obs_data_set_int(font_obj, "size", font.pointSize()); - flags = font.bold() ? OBS_FONT_BOLD : 0; - flags |= font.italic() ? OBS_FONT_ITALIC : 0; - flags |= font.underline() ? OBS_FONT_UNDERLINE : 0; - flags |= font.strikeOut() ? OBS_FONT_STRIKEOUT : 0; - obs_data_set_int(font_obj, "flags", flags); - - SaveOldProperties(source); - - OBSDataAutoRelease settings = obs_data_create(); - - obs_data_set_obj(settings, "font", font_obj); - - obs_source_update(source, settings); - - SetUndoProperties(source); -} - -void TextSourceToolbar::on_selectColor_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - bool freetype = strncmp(obs_source_get_id(source), "text_ft2_source", 15) == 0; - - obs_property_t *p = obs_properties_get(props.get(), freetype ? "color1" : "color"); - - const char *desc = obs_property_description(p); - - QColorDialog::ColorDialogOptions options; - - options |= QColorDialog::ShowAlphaChannel; -#ifdef __linux__ - // TODO: Revisit hang on Ubuntu with native dialog - options |= QColorDialog::DontUseNativeDialog; -#endif - - QColor newColor = QColorDialog::getColor(color, this, desc, options); - if (!newColor.isValid()) { - return; - } - - color = newColor; - - SaveOldProperties(source); - - OBSDataAutoRelease settings = obs_data_create(); - if (freetype) { - obs_data_set_int(settings, "color1", color_to_int(color)); - obs_data_set_int(settings, "color2", color_to_int(color)); - } else { - obs_data_set_int(settings, "color", color_to_int(color)); - } - obs_source_update(source, settings); - - SetUndoProperties(source); -} - -void TextSourceToolbar::on_text_textChanged() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - std::string newText = QT_TO_UTF8(ui->text->text()); - OBSDataAutoRelease settings = obs_source_get_settings(source); - if (newText == obs_data_get_string(settings, "text")) { - return; - } - SaveOldProperties(source); - - obs_data_set_string(settings, "text", newText.c_str()); - obs_source_update(source, nullptr); - - SetUndoProperties(source, true); -} diff --git a/frontend/components/ComboSelectToolbar.hpp b/frontend/components/ComboSelectToolbar.hpp index acf88a5fb..613709e13 100644 --- a/frontend/components/ComboSelectToolbar.hpp +++ b/frontend/components/ComboSelectToolbar.hpp @@ -1,52 +1,8 @@ #pragma once -#include -#include -#include +#include "SourceToolbar.hpp" -class Ui_BrowserSourceToolbar; class Ui_DeviceSelectToolbar; -class Ui_GameCaptureToolbar; -class Ui_ImageSourceToolbar; -class Ui_ColorSourceToolbar; -class Ui_TextSourceToolbar; - -class SourceToolbar : public QWidget { - Q_OBJECT - - OBSWeakSource weakSource; - -protected: - using properties_delete_t = decltype(&obs_properties_destroy); - using properties_t = std::unique_ptr; - - properties_t props; - OBSDataAutoRelease oldData; - - void SaveOldProperties(obs_source_t *source); - void SetUndoProperties(obs_source_t *source, bool repeatable = false); - -public: - SourceToolbar(QWidget *parent, OBSSource source); - - OBSSource GetSource() { return OBSGetStrongRef(weakSource); } - -public slots: - virtual void Update() {} -}; - -class BrowserToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - -public: - BrowserToolbar(QWidget *parent, OBSSource source); - ~BrowserToolbar(); - -public slots: - void on_refresh_clicked(); -}; class ComboSelectToolbar : public SourceToolbar { Q_OBJECT @@ -64,115 +20,3 @@ public: public slots: void on_device_currentIndexChanged(int idx); }; - -class AudioCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - AudioCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class WindowCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - WindowCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class ApplicationAudioCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - ApplicationAudioCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class DisplayCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - DisplayCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class DeviceCaptureToolbar : public QWidget { - Q_OBJECT - - OBSWeakSource weakSource; - - std::unique_ptr ui; - const char *activateText; - const char *deactivateText; - bool active; - -public: - DeviceCaptureToolbar(QWidget *parent, OBSSource source); - ~DeviceCaptureToolbar(); - -public slots: - void on_activateButton_clicked(); -}; - -class GameCaptureToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - - void UpdateWindowVisibility(); - -public: - GameCaptureToolbar(QWidget *parent, OBSSource source); - ~GameCaptureToolbar(); - -public slots: - void on_mode_currentIndexChanged(int idx); - void on_window_currentIndexChanged(int idx); -}; - -class ImageSourceToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - -public: - ImageSourceToolbar(QWidget *parent, OBSSource source); - ~ImageSourceToolbar(); - -public slots: - void on_browse_clicked(); -}; - -class ColorSourceToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - QColor color; - - void UpdateColor(); - -public: - ColorSourceToolbar(QWidget *parent, OBSSource source); - ~ColorSourceToolbar(); - -public slots: - void on_choose_clicked(); -}; - -class TextSourceToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - QFont font; - QColor color; - -public: - TextSourceToolbar(QWidget *parent, OBSSource source); - ~TextSourceToolbar(); - -public slots: - void on_selectFont_clicked(); - void on_selectColor_clicked(); - void on_text_textChanged(); -}; diff --git a/frontend/components/DeviceCaptureToolbar.cpp b/frontend/components/DeviceCaptureToolbar.cpp index c45d06976..c69179453 100644 --- a/frontend/components/DeviceCaptureToolbar.cpp +++ b/frontend/components/DeviceCaptureToolbar.cpp @@ -1,302 +1,6 @@ -#include "window-basic-main.hpp" -#include "moc_context-bar-controls.cpp" -#include "obs-app.hpp" - -#include -#include -#include -#include - -#include "ui_browser-source-toolbar.h" +#include "DeviceCaptureToolbar.hpp" #include "ui_device-select-toolbar.h" -#include "ui_game-capture-toolbar.h" -#include "ui_image-source-toolbar.h" -#include "ui_color-source-toolbar.h" -#include "ui_text-source-toolbar.h" - -#ifdef _WIN32 -#define get_os_module(win, mac, linux) obs_get_module(win) -#define get_os_text(mod, win, mac, linux) obs_module_get_locale_text(mod, win) -#elif __APPLE__ -#define get_os_module(win, mac, linux) obs_get_module(mac) -#define get_os_text(mod, win, mac, linux) obs_module_get_locale_text(mod, mac) -#else -#define get_os_module(win, mac, linux) obs_get_module(linux) -#define get_os_text(mod, win, mac, linux) obs_module_get_locale_text(mod, linux) -#endif - -/* ========================================================================= */ - -SourceToolbar::SourceToolbar(QWidget *parent, OBSSource source) - : QWidget(parent), - weakSource(OBSGetWeakRef(source)), - props(obs_source_properties(source), obs_properties_destroy) -{ -} - -void SourceToolbar::SaveOldProperties(obs_source_t *source) -{ - oldData = obs_data_create(); - - OBSDataAutoRelease oldSettings = obs_source_get_settings(source); - obs_data_apply(oldData, oldSettings); - obs_data_set_string(oldData, "undo_suuid", obs_source_get_uuid(source)); -} - -void SourceToolbar::SetUndoProperties(obs_source_t *source, bool repeatable) -{ - if (!oldData) { - blog(LOG_ERROR, "%s: somehow oldData was null.", __FUNCTION__); - return; - } - - OBSBasic *main = reinterpret_cast(App()->GetMainWindow()); - - OBSSource currentSceneSource = main->GetCurrentSceneSource(); - if (!currentSceneSource) - return; - std::string scene_uuid = obs_source_get_uuid(currentSceneSource); - auto undo_redo = [scene_uuid = std::move(scene_uuid), main](const std::string &data) { - OBSDataAutoRelease settings = obs_data_create_from_json(data.c_str()); - OBSSourceAutoRelease source = obs_get_source_by_uuid(obs_data_get_string(settings, "undo_suuid")); - obs_source_reset_settings(source, settings); - - OBSSourceAutoRelease scene_source = obs_get_source_by_uuid(scene_uuid.c_str()); - main->SetCurrentScene(scene_source.Get(), true); - - main->UpdateContextBar(); - }; - - OBSDataAutoRelease new_settings = obs_data_create(); - OBSDataAutoRelease curr_settings = obs_source_get_settings(source); - obs_data_apply(new_settings, curr_settings); - obs_data_set_string(new_settings, "undo_suuid", obs_source_get_uuid(source)); - - std::string undo_data(obs_data_get_json(oldData)); - std::string redo_data(obs_data_get_json(new_settings)); - - if (undo_data.compare(redo_data) != 0) - main->undo_s.add_action(QTStr("Undo.Properties").arg(obs_source_get_name(source)), undo_redo, undo_redo, - undo_data, redo_data, repeatable); - - oldData = nullptr; -} - -/* ========================================================================= */ - -BrowserToolbar::BrowserToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_BrowserSourceToolbar) -{ - ui->setupUi(this); -} - -BrowserToolbar::~BrowserToolbar() {} - -void BrowserToolbar::on_refresh_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - obs_property_t *p = obs_properties_get(props.get(), "refreshnocache"); - obs_property_button_clicked(p, source.Get()); -} - -/* ========================================================================= */ - -ComboSelectToolbar::ComboSelectToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_DeviceSelectToolbar) -{ - ui->setupUi(this); -} - -ComboSelectToolbar::~ComboSelectToolbar() {} - -static int FillPropertyCombo(QComboBox *c, obs_property_t *p, const std::string &cur_id, bool is_int = false) -{ - size_t count = obs_property_list_item_count(p); - int cur_idx = -1; - - for (size_t i = 0; i < count; i++) { - const char *name = obs_property_list_item_name(p, i); - std::string id; - - if (is_int) { - id = std::to_string(obs_property_list_item_int(p, i)); - } else { - const char *val = obs_property_list_item_string(p, i); - id = val ? val : ""; - } - - if (cur_id == id) - cur_idx = (int)i; - - c->addItem(name, id.c_str()); - } - - return cur_idx; -} - -void UpdateSourceComboToolbarProperties(QComboBox *combo, OBSSource source, obs_properties_t *props, - const char *prop_name, bool is_int) -{ - std::string cur_id; - - OBSDataAutoRelease settings = obs_source_get_settings(source); - if (is_int) { - cur_id = std::to_string(obs_data_get_int(settings, prop_name)); - } else { - cur_id = obs_data_get_string(settings, prop_name); - } - - combo->blockSignals(true); - - obs_property_t *p = obs_properties_get(props, prop_name); - int cur_idx = FillPropertyCombo(combo, p, cur_id, is_int); - - if (cur_idx == -1 || obs_property_list_item_disabled(p, cur_idx)) { - if (cur_idx == -1) { - combo->insertItem(0, QTStr("Basic.Settings.Audio.UnknownAudioDevice")); - cur_idx = 0; - } - - SetComboItemEnabled(combo, cur_idx, false); - } - - combo->setCurrentIndex(cur_idx); - combo->blockSignals(false); -} - -void ComboSelectToolbar::Init() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - UpdateSourceComboToolbarProperties(ui->device, source, props.get(), prop_name, is_int); -} - -void UpdateSourceComboToolbarValue(QComboBox *combo, OBSSource source, int idx, const char *prop_name, bool is_int) -{ - QString id = combo->itemData(idx).toString(); - - OBSDataAutoRelease settings = obs_data_create(); - if (is_int) { - obs_data_set_int(settings, prop_name, id.toInt()); - } else { - obs_data_set_string(settings, prop_name, QT_TO_UTF8(id)); - } - obs_source_update(source, settings); -} - -void ComboSelectToolbar::on_device_currentIndexChanged(int idx) -{ - OBSSource source = GetSource(); - if (idx == -1 || !source) { - return; - } - - SaveOldProperties(source); - UpdateSourceComboToolbarValue(ui->device, source, idx, prop_name, is_int); - SetUndoProperties(source); -} - -AudioCaptureToolbar::AudioCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) {} - -void AudioCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = get_os_module("win-wasapi", "mac-capture", "linux-pulseaudio"); - if (!mod) - return; - - const char *device_str = get_os_text(mod, "Device", "CoreAudio.Device", "Device"); - ui->deviceLabel->setText(device_str); - - prop_name = "device_id"; - - ComboSelectToolbar::Init(); -} - -WindowCaptureToolbar::WindowCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) {} - -void WindowCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = get_os_module("win-capture", "mac-capture", "linux-capture"); - if (!mod) - return; - - const char *device_str = get_os_text(mod, "WindowCapture.Window", "WindowUtils.Window", "Window"); - ui->deviceLabel->setText(device_str); - -#if !defined(_WIN32) && !defined(__APPLE__) //linux - prop_name = "capture_window"; -#else - prop_name = "window"; -#endif - -#ifdef __APPLE__ - is_int = true; -#endif - - ComboSelectToolbar::Init(); -} - -ApplicationAudioCaptureToolbar::ApplicationAudioCaptureToolbar(QWidget *parent, OBSSource source) - : ComboSelectToolbar(parent, source) -{ -} - -void ApplicationAudioCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = obs_get_module("win-wasapi"); - const char *device_str = obs_module_get_locale_text(mod, "Window"); - ui->deviceLabel->setText(device_str); - - prop_name = "window"; - - ComboSelectToolbar::Init(); -} - -DisplayCaptureToolbar::DisplayCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) {} - -void DisplayCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = get_os_module("win-capture", "mac-capture", "linux-capture"); - if (!mod) - return; - - const char *device_str = get_os_text(mod, "Monitor", "DisplayCapture.Display", "Screen"); - ui->deviceLabel->setText(device_str); - -#ifdef _WIN32 - prop_name = "monitor_id"; -#elif __APPLE__ - prop_name = "display_uuid"; -#else - is_int = true; - prop_name = "screen"; -#endif - - ComboSelectToolbar::Init(); -} - -/* ========================================================================= */ +#include "moc_DeviceCaptureToolbar.cpp" DeviceCaptureToolbar::DeviceCaptureToolbar(QWidget *parent, OBSSource source) : QWidget(parent), @@ -352,356 +56,3 @@ void DeviceCaptureToolbar::on_activateButton_clicked() proc_handler_call(ph, "activate", &cd); calldata_free(&cd); } - -/* ========================================================================= */ - -GameCaptureToolbar::GameCaptureToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_GameCaptureToolbar) -{ - obs_property_t *p; - int cur_idx; - - ui->setupUi(this); - - obs_module_t *mod = obs_get_module("win-capture"); - if (!mod) - return; - - ui->modeLabel->setText(obs_module_get_locale_text(mod, "Mode")); - ui->windowLabel->setText(obs_module_get_locale_text(mod, "WindowCapture.Window")); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - std::string cur_mode = obs_data_get_string(settings, "capture_mode"); - std::string cur_window = obs_data_get_string(settings, "window"); - - ui->mode->blockSignals(true); - p = obs_properties_get(props.get(), "capture_mode"); - cur_idx = FillPropertyCombo(ui->mode, p, cur_mode); - ui->mode->setCurrentIndex(cur_idx); - ui->mode->blockSignals(false); - - ui->window->blockSignals(true); - p = obs_properties_get(props.get(), "window"); - cur_idx = FillPropertyCombo(ui->window, p, cur_window); - ui->window->setCurrentIndex(cur_idx); - ui->window->blockSignals(false); - - if (cur_idx != -1 && obs_property_list_item_disabled(p, cur_idx)) { - SetComboItemEnabled(ui->window, cur_idx, false); - } - - UpdateWindowVisibility(); -} - -GameCaptureToolbar::~GameCaptureToolbar() {} - -void GameCaptureToolbar::UpdateWindowVisibility() -{ - QString mode = ui->mode->currentData().toString(); - bool is_window = (mode == "window"); - ui->windowLabel->setVisible(is_window); - ui->window->setVisible(is_window); -} - -void GameCaptureToolbar::on_mode_currentIndexChanged(int idx) -{ - OBSSource source = GetSource(); - if (idx == -1 || !source) { - return; - } - - QString id = ui->mode->itemData(idx).toString(); - - SaveOldProperties(source); - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_string(settings, "capture_mode", QT_TO_UTF8(id)); - obs_source_update(source, settings); - SetUndoProperties(source); - - UpdateWindowVisibility(); -} - -void GameCaptureToolbar::on_window_currentIndexChanged(int idx) -{ - OBSSource source = GetSource(); - if (idx == -1 || !source) { - return; - } - - QString id = ui->window->itemData(idx).toString(); - - SaveOldProperties(source); - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_string(settings, "window", QT_TO_UTF8(id)); - obs_source_update(source, settings); - SetUndoProperties(source); -} - -/* ========================================================================= */ - -ImageSourceToolbar::ImageSourceToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_ImageSourceToolbar) -{ - ui->setupUi(this); - - obs_module_t *mod = obs_get_module("image-source"); - ui->pathLabel->setText(obs_module_get_locale_text(mod, "File")); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - std::string file = obs_data_get_string(settings, "file"); - - ui->path->setText(file.c_str()); -} - -ImageSourceToolbar::~ImageSourceToolbar() {} - -void ImageSourceToolbar::on_browse_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - obs_property_t *p = obs_properties_get(props.get(), "file"); - const char *desc = obs_property_description(p); - const char *filter = obs_property_path_filter(p); - const char *default_path = obs_property_path_default_path(p); - - QString startDir = ui->path->text(); - if (startDir.isEmpty()) - startDir = default_path; - - QString path = OpenFile(this, desc, startDir, filter); - if (path.isEmpty()) { - return; - } - - ui->path->setText(path); - - SaveOldProperties(source); - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_string(settings, "file", QT_TO_UTF8(path)); - obs_source_update(source, settings); - SetUndoProperties(source); -} - -/* ========================================================================= */ - -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); -} - -ColorSourceToolbar::ColorSourceToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_ColorSourceToolbar) -{ - ui->setupUi(this); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - unsigned int val = (unsigned int)obs_data_get_int(settings, "color"); - - color = color_from_int(val); - UpdateColor(); -} - -ColorSourceToolbar::~ColorSourceToolbar() {} - -void ColorSourceToolbar::UpdateColor() -{ - QPalette palette = QPalette(color); - ui->color->setFrameStyle(QFrame::Sunken | QFrame::Panel); - ui->color->setText(color.name(QColor::HexRgb)); - ui->color->setPalette(palette); - ui->color->setStyleSheet(QString("background-color :%1; color: %2;") - .arg(palette.color(QPalette::Window).name(QColor::HexRgb)) - .arg(palette.color(QPalette::WindowText).name(QColor::HexRgb))); - ui->color->setAutoFillBackground(true); - ui->color->setAlignment(Qt::AlignCenter); -} - -void ColorSourceToolbar::on_choose_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - obs_property_t *p = obs_properties_get(props.get(), "color"); - const char *desc = obs_property_description(p); - - QColorDialog::ColorDialogOptions options; - - options |= QColorDialog::ShowAlphaChannel; -#ifdef __linux__ - // TODO: Revisit hang on Ubuntu with native dialog - options |= QColorDialog::DontUseNativeDialog; -#endif - - QColor newColor = QColorDialog::getColor(color, this, desc, options); - if (!newColor.isValid()) { - return; - } - - color = newColor; - UpdateColor(); - - SaveOldProperties(source); - - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_int(settings, "color", color_to_int(color)); - obs_source_update(source, settings); - - SetUndoProperties(source); -} - -/* ========================================================================= */ - -extern void MakeQFont(obs_data_t *font_obj, QFont &font, bool limit = false); - -TextSourceToolbar::TextSourceToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_TextSourceToolbar) -{ - ui->setupUi(this); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - - const char *id = obs_source_get_unversioned_id(source); - bool ft2 = strcmp(id, "text_ft2_source") == 0; - bool read_from_file = obs_data_get_bool(settings, ft2 ? "from_file" : "read_from_file"); - - OBSDataAutoRelease font_obj = obs_data_get_obj(settings, "font"); - MakeQFont(font_obj, font); - - // Use "color1" if it's a freetype source and "color" elsewise - unsigned int val = (unsigned int)obs_data_get_int( - settings, (strncmp(obs_source_get_id(source), "text_ft2_source", 15) == 0) ? "color1" : "color"); - - color = color_from_int(val); - - const char *text = obs_data_get_string(settings, "text"); - - bool single_line = !read_from_file && (!text || (strchr(text, '\n') == nullptr)); - ui->emptySpace->setVisible(!single_line); - ui->text->setVisible(single_line); - if (single_line) - ui->text->setText(text); -} - -TextSourceToolbar::~TextSourceToolbar() {} - -void TextSourceToolbar::on_selectFont_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - QFontDialog::FontDialogOptions options; - uint32_t flags; - bool success; - -#ifndef _WIN32 - options = QFontDialog::DontUseNativeDialog; -#endif - - font = QFontDialog::getFont(&success, font, this, QTStr("Basic.PropertiesWindow.SelectFont.WindowTitle"), - options); - if (!success) { - return; - } - - OBSDataAutoRelease font_obj = obs_data_create(); - - obs_data_set_string(font_obj, "face", QT_TO_UTF8(font.family())); - obs_data_set_string(font_obj, "style", QT_TO_UTF8(font.styleName())); - obs_data_set_int(font_obj, "size", font.pointSize()); - flags = font.bold() ? OBS_FONT_BOLD : 0; - flags |= font.italic() ? OBS_FONT_ITALIC : 0; - flags |= font.underline() ? OBS_FONT_UNDERLINE : 0; - flags |= font.strikeOut() ? OBS_FONT_STRIKEOUT : 0; - obs_data_set_int(font_obj, "flags", flags); - - SaveOldProperties(source); - - OBSDataAutoRelease settings = obs_data_create(); - - obs_data_set_obj(settings, "font", font_obj); - - obs_source_update(source, settings); - - SetUndoProperties(source); -} - -void TextSourceToolbar::on_selectColor_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - bool freetype = strncmp(obs_source_get_id(source), "text_ft2_source", 15) == 0; - - obs_property_t *p = obs_properties_get(props.get(), freetype ? "color1" : "color"); - - const char *desc = obs_property_description(p); - - QColorDialog::ColorDialogOptions options; - - options |= QColorDialog::ShowAlphaChannel; -#ifdef __linux__ - // TODO: Revisit hang on Ubuntu with native dialog - options |= QColorDialog::DontUseNativeDialog; -#endif - - QColor newColor = QColorDialog::getColor(color, this, desc, options); - if (!newColor.isValid()) { - return; - } - - color = newColor; - - SaveOldProperties(source); - - OBSDataAutoRelease settings = obs_data_create(); - if (freetype) { - obs_data_set_int(settings, "color1", color_to_int(color)); - obs_data_set_int(settings, "color2", color_to_int(color)); - } else { - obs_data_set_int(settings, "color", color_to_int(color)); - } - obs_source_update(source, settings); - - SetUndoProperties(source); -} - -void TextSourceToolbar::on_text_textChanged() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - std::string newText = QT_TO_UTF8(ui->text->text()); - OBSDataAutoRelease settings = obs_source_get_settings(source); - if (newText == obs_data_get_string(settings, "text")) { - return; - } - SaveOldProperties(source); - - obs_data_set_string(settings, "text", newText.c_str()); - obs_source_update(source, nullptr); - - SetUndoProperties(source, true); -} diff --git a/frontend/components/DeviceCaptureToolbar.hpp b/frontend/components/DeviceCaptureToolbar.hpp index acf88a5fb..17f76f4aa 100644 --- a/frontend/components/DeviceCaptureToolbar.hpp +++ b/frontend/components/DeviceCaptureToolbar.hpp @@ -1,101 +1,10 @@ #pragma once -#include #include + #include -class Ui_BrowserSourceToolbar; class Ui_DeviceSelectToolbar; -class Ui_GameCaptureToolbar; -class Ui_ImageSourceToolbar; -class Ui_ColorSourceToolbar; -class Ui_TextSourceToolbar; - -class SourceToolbar : public QWidget { - Q_OBJECT - - OBSWeakSource weakSource; - -protected: - using properties_delete_t = decltype(&obs_properties_destroy); - using properties_t = std::unique_ptr; - - properties_t props; - OBSDataAutoRelease oldData; - - void SaveOldProperties(obs_source_t *source); - void SetUndoProperties(obs_source_t *source, bool repeatable = false); - -public: - SourceToolbar(QWidget *parent, OBSSource source); - - OBSSource GetSource() { return OBSGetStrongRef(weakSource); } - -public slots: - virtual void Update() {} -}; - -class BrowserToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - -public: - BrowserToolbar(QWidget *parent, OBSSource source); - ~BrowserToolbar(); - -public slots: - void on_refresh_clicked(); -}; - -class ComboSelectToolbar : public SourceToolbar { - Q_OBJECT - -protected: - std::unique_ptr ui; - const char *prop_name; - bool is_int = false; - -public: - ComboSelectToolbar(QWidget *parent, OBSSource source); - ~ComboSelectToolbar(); - virtual void Init(); - -public slots: - void on_device_currentIndexChanged(int idx); -}; - -class AudioCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - AudioCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class WindowCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - WindowCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class ApplicationAudioCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - ApplicationAudioCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class DisplayCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - DisplayCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; class DeviceCaptureToolbar : public QWidget { Q_OBJECT @@ -114,65 +23,3 @@ public: public slots: void on_activateButton_clicked(); }; - -class GameCaptureToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - - void UpdateWindowVisibility(); - -public: - GameCaptureToolbar(QWidget *parent, OBSSource source); - ~GameCaptureToolbar(); - -public slots: - void on_mode_currentIndexChanged(int idx); - void on_window_currentIndexChanged(int idx); -}; - -class ImageSourceToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - -public: - ImageSourceToolbar(QWidget *parent, OBSSource source); - ~ImageSourceToolbar(); - -public slots: - void on_browse_clicked(); -}; - -class ColorSourceToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - QColor color; - - void UpdateColor(); - -public: - ColorSourceToolbar(QWidget *parent, OBSSource source); - ~ColorSourceToolbar(); - -public slots: - void on_choose_clicked(); -}; - -class TextSourceToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - QFont font; - QColor color; - -public: - TextSourceToolbar(QWidget *parent, OBSSource source); - ~TextSourceToolbar(); - -public slots: - void on_selectFont_clicked(); - void on_selectColor_clicked(); - void on_text_textChanged(); -}; diff --git a/frontend/components/DisplayCaptureToolbar.cpp b/frontend/components/DisplayCaptureToolbar.cpp index c45d06976..d32bdea84 100644 --- a/frontend/components/DisplayCaptureToolbar.cpp +++ b/frontend/components/DisplayCaptureToolbar.cpp @@ -1,18 +1,6 @@ -#include "window-basic-main.hpp" -#include "moc_context-bar-controls.cpp" -#include "obs-app.hpp" - -#include -#include -#include -#include - -#include "ui_browser-source-toolbar.h" +#include "DisplayCaptureToolbar.hpp" #include "ui_device-select-toolbar.h" -#include "ui_game-capture-toolbar.h" -#include "ui_image-source-toolbar.h" -#include "ui_color-source-toolbar.h" -#include "ui_text-source-toolbar.h" +#include "moc_DisplayCaptureToolbar.cpp" #ifdef _WIN32 #define get_os_module(win, mac, linux) obs_get_module(win) @@ -25,251 +13,6 @@ #define get_os_text(mod, win, mac, linux) obs_module_get_locale_text(mod, linux) #endif -/* ========================================================================= */ - -SourceToolbar::SourceToolbar(QWidget *parent, OBSSource source) - : QWidget(parent), - weakSource(OBSGetWeakRef(source)), - props(obs_source_properties(source), obs_properties_destroy) -{ -} - -void SourceToolbar::SaveOldProperties(obs_source_t *source) -{ - oldData = obs_data_create(); - - OBSDataAutoRelease oldSettings = obs_source_get_settings(source); - obs_data_apply(oldData, oldSettings); - obs_data_set_string(oldData, "undo_suuid", obs_source_get_uuid(source)); -} - -void SourceToolbar::SetUndoProperties(obs_source_t *source, bool repeatable) -{ - if (!oldData) { - blog(LOG_ERROR, "%s: somehow oldData was null.", __FUNCTION__); - return; - } - - OBSBasic *main = reinterpret_cast(App()->GetMainWindow()); - - OBSSource currentSceneSource = main->GetCurrentSceneSource(); - if (!currentSceneSource) - return; - std::string scene_uuid = obs_source_get_uuid(currentSceneSource); - auto undo_redo = [scene_uuid = std::move(scene_uuid), main](const std::string &data) { - OBSDataAutoRelease settings = obs_data_create_from_json(data.c_str()); - OBSSourceAutoRelease source = obs_get_source_by_uuid(obs_data_get_string(settings, "undo_suuid")); - obs_source_reset_settings(source, settings); - - OBSSourceAutoRelease scene_source = obs_get_source_by_uuid(scene_uuid.c_str()); - main->SetCurrentScene(scene_source.Get(), true); - - main->UpdateContextBar(); - }; - - OBSDataAutoRelease new_settings = obs_data_create(); - OBSDataAutoRelease curr_settings = obs_source_get_settings(source); - obs_data_apply(new_settings, curr_settings); - obs_data_set_string(new_settings, "undo_suuid", obs_source_get_uuid(source)); - - std::string undo_data(obs_data_get_json(oldData)); - std::string redo_data(obs_data_get_json(new_settings)); - - if (undo_data.compare(redo_data) != 0) - main->undo_s.add_action(QTStr("Undo.Properties").arg(obs_source_get_name(source)), undo_redo, undo_redo, - undo_data, redo_data, repeatable); - - oldData = nullptr; -} - -/* ========================================================================= */ - -BrowserToolbar::BrowserToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_BrowserSourceToolbar) -{ - ui->setupUi(this); -} - -BrowserToolbar::~BrowserToolbar() {} - -void BrowserToolbar::on_refresh_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - obs_property_t *p = obs_properties_get(props.get(), "refreshnocache"); - obs_property_button_clicked(p, source.Get()); -} - -/* ========================================================================= */ - -ComboSelectToolbar::ComboSelectToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_DeviceSelectToolbar) -{ - ui->setupUi(this); -} - -ComboSelectToolbar::~ComboSelectToolbar() {} - -static int FillPropertyCombo(QComboBox *c, obs_property_t *p, const std::string &cur_id, bool is_int = false) -{ - size_t count = obs_property_list_item_count(p); - int cur_idx = -1; - - for (size_t i = 0; i < count; i++) { - const char *name = obs_property_list_item_name(p, i); - std::string id; - - if (is_int) { - id = std::to_string(obs_property_list_item_int(p, i)); - } else { - const char *val = obs_property_list_item_string(p, i); - id = val ? val : ""; - } - - if (cur_id == id) - cur_idx = (int)i; - - c->addItem(name, id.c_str()); - } - - return cur_idx; -} - -void UpdateSourceComboToolbarProperties(QComboBox *combo, OBSSource source, obs_properties_t *props, - const char *prop_name, bool is_int) -{ - std::string cur_id; - - OBSDataAutoRelease settings = obs_source_get_settings(source); - if (is_int) { - cur_id = std::to_string(obs_data_get_int(settings, prop_name)); - } else { - cur_id = obs_data_get_string(settings, prop_name); - } - - combo->blockSignals(true); - - obs_property_t *p = obs_properties_get(props, prop_name); - int cur_idx = FillPropertyCombo(combo, p, cur_id, is_int); - - if (cur_idx == -1 || obs_property_list_item_disabled(p, cur_idx)) { - if (cur_idx == -1) { - combo->insertItem(0, QTStr("Basic.Settings.Audio.UnknownAudioDevice")); - cur_idx = 0; - } - - SetComboItemEnabled(combo, cur_idx, false); - } - - combo->setCurrentIndex(cur_idx); - combo->blockSignals(false); -} - -void ComboSelectToolbar::Init() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - UpdateSourceComboToolbarProperties(ui->device, source, props.get(), prop_name, is_int); -} - -void UpdateSourceComboToolbarValue(QComboBox *combo, OBSSource source, int idx, const char *prop_name, bool is_int) -{ - QString id = combo->itemData(idx).toString(); - - OBSDataAutoRelease settings = obs_data_create(); - if (is_int) { - obs_data_set_int(settings, prop_name, id.toInt()); - } else { - obs_data_set_string(settings, prop_name, QT_TO_UTF8(id)); - } - obs_source_update(source, settings); -} - -void ComboSelectToolbar::on_device_currentIndexChanged(int idx) -{ - OBSSource source = GetSource(); - if (idx == -1 || !source) { - return; - } - - SaveOldProperties(source); - UpdateSourceComboToolbarValue(ui->device, source, idx, prop_name, is_int); - SetUndoProperties(source); -} - -AudioCaptureToolbar::AudioCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) {} - -void AudioCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = get_os_module("win-wasapi", "mac-capture", "linux-pulseaudio"); - if (!mod) - return; - - const char *device_str = get_os_text(mod, "Device", "CoreAudio.Device", "Device"); - ui->deviceLabel->setText(device_str); - - prop_name = "device_id"; - - ComboSelectToolbar::Init(); -} - -WindowCaptureToolbar::WindowCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) {} - -void WindowCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = get_os_module("win-capture", "mac-capture", "linux-capture"); - if (!mod) - return; - - const char *device_str = get_os_text(mod, "WindowCapture.Window", "WindowUtils.Window", "Window"); - ui->deviceLabel->setText(device_str); - -#if !defined(_WIN32) && !defined(__APPLE__) //linux - prop_name = "capture_window"; -#else - prop_name = "window"; -#endif - -#ifdef __APPLE__ - is_int = true; -#endif - - ComboSelectToolbar::Init(); -} - -ApplicationAudioCaptureToolbar::ApplicationAudioCaptureToolbar(QWidget *parent, OBSSource source) - : ComboSelectToolbar(parent, source) -{ -} - -void ApplicationAudioCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = obs_get_module("win-wasapi"); - const char *device_str = obs_module_get_locale_text(mod, "Window"); - ui->deviceLabel->setText(device_str); - - prop_name = "window"; - - ComboSelectToolbar::Init(); -} - DisplayCaptureToolbar::DisplayCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) {} void DisplayCaptureToolbar::Init() @@ -295,413 +38,3 @@ void DisplayCaptureToolbar::Init() ComboSelectToolbar::Init(); } - -/* ========================================================================= */ - -DeviceCaptureToolbar::DeviceCaptureToolbar(QWidget *parent, OBSSource source) - : QWidget(parent), - weakSource(OBSGetWeakRef(source)), - ui(new Ui_DeviceSelectToolbar) -{ - ui->setupUi(this); - - delete ui->deviceLabel; - delete ui->device; - ui->deviceLabel = nullptr; - ui->device = nullptr; - - OBSDataAutoRelease settings = obs_source_get_settings(source); - active = obs_data_get_bool(settings, "active"); - - obs_module_t *mod = obs_get_module("win-dshow"); - if (!mod) - return; - - activateText = obs_module_get_locale_text(mod, "Activate"); - deactivateText = obs_module_get_locale_text(mod, "Deactivate"); - - ui->activateButton->setText(active ? deactivateText : activateText); -} - -DeviceCaptureToolbar::~DeviceCaptureToolbar() {} - -void DeviceCaptureToolbar::on_activateButton_clicked() -{ - OBSSource source = OBSGetStrongRef(weakSource); - if (!source) { - return; - } - - OBSDataAutoRelease settings = obs_source_get_settings(source); - bool now_active = obs_data_get_bool(settings, "active"); - - bool desyncedSetting = now_active != active; - - active = !active; - - const char *text = active ? deactivateText : activateText; - ui->activateButton->setText(text); - - if (desyncedSetting) { - return; - } - - calldata_t cd = {}; - calldata_set_bool(&cd, "active", active); - proc_handler_t *ph = obs_source_get_proc_handler(source); - proc_handler_call(ph, "activate", &cd); - calldata_free(&cd); -} - -/* ========================================================================= */ - -GameCaptureToolbar::GameCaptureToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_GameCaptureToolbar) -{ - obs_property_t *p; - int cur_idx; - - ui->setupUi(this); - - obs_module_t *mod = obs_get_module("win-capture"); - if (!mod) - return; - - ui->modeLabel->setText(obs_module_get_locale_text(mod, "Mode")); - ui->windowLabel->setText(obs_module_get_locale_text(mod, "WindowCapture.Window")); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - std::string cur_mode = obs_data_get_string(settings, "capture_mode"); - std::string cur_window = obs_data_get_string(settings, "window"); - - ui->mode->blockSignals(true); - p = obs_properties_get(props.get(), "capture_mode"); - cur_idx = FillPropertyCombo(ui->mode, p, cur_mode); - ui->mode->setCurrentIndex(cur_idx); - ui->mode->blockSignals(false); - - ui->window->blockSignals(true); - p = obs_properties_get(props.get(), "window"); - cur_idx = FillPropertyCombo(ui->window, p, cur_window); - ui->window->setCurrentIndex(cur_idx); - ui->window->blockSignals(false); - - if (cur_idx != -1 && obs_property_list_item_disabled(p, cur_idx)) { - SetComboItemEnabled(ui->window, cur_idx, false); - } - - UpdateWindowVisibility(); -} - -GameCaptureToolbar::~GameCaptureToolbar() {} - -void GameCaptureToolbar::UpdateWindowVisibility() -{ - QString mode = ui->mode->currentData().toString(); - bool is_window = (mode == "window"); - ui->windowLabel->setVisible(is_window); - ui->window->setVisible(is_window); -} - -void GameCaptureToolbar::on_mode_currentIndexChanged(int idx) -{ - OBSSource source = GetSource(); - if (idx == -1 || !source) { - return; - } - - QString id = ui->mode->itemData(idx).toString(); - - SaveOldProperties(source); - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_string(settings, "capture_mode", QT_TO_UTF8(id)); - obs_source_update(source, settings); - SetUndoProperties(source); - - UpdateWindowVisibility(); -} - -void GameCaptureToolbar::on_window_currentIndexChanged(int idx) -{ - OBSSource source = GetSource(); - if (idx == -1 || !source) { - return; - } - - QString id = ui->window->itemData(idx).toString(); - - SaveOldProperties(source); - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_string(settings, "window", QT_TO_UTF8(id)); - obs_source_update(source, settings); - SetUndoProperties(source); -} - -/* ========================================================================= */ - -ImageSourceToolbar::ImageSourceToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_ImageSourceToolbar) -{ - ui->setupUi(this); - - obs_module_t *mod = obs_get_module("image-source"); - ui->pathLabel->setText(obs_module_get_locale_text(mod, "File")); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - std::string file = obs_data_get_string(settings, "file"); - - ui->path->setText(file.c_str()); -} - -ImageSourceToolbar::~ImageSourceToolbar() {} - -void ImageSourceToolbar::on_browse_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - obs_property_t *p = obs_properties_get(props.get(), "file"); - const char *desc = obs_property_description(p); - const char *filter = obs_property_path_filter(p); - const char *default_path = obs_property_path_default_path(p); - - QString startDir = ui->path->text(); - if (startDir.isEmpty()) - startDir = default_path; - - QString path = OpenFile(this, desc, startDir, filter); - if (path.isEmpty()) { - return; - } - - ui->path->setText(path); - - SaveOldProperties(source); - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_string(settings, "file", QT_TO_UTF8(path)); - obs_source_update(source, settings); - SetUndoProperties(source); -} - -/* ========================================================================= */ - -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); -} - -ColorSourceToolbar::ColorSourceToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_ColorSourceToolbar) -{ - ui->setupUi(this); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - unsigned int val = (unsigned int)obs_data_get_int(settings, "color"); - - color = color_from_int(val); - UpdateColor(); -} - -ColorSourceToolbar::~ColorSourceToolbar() {} - -void ColorSourceToolbar::UpdateColor() -{ - QPalette palette = QPalette(color); - ui->color->setFrameStyle(QFrame::Sunken | QFrame::Panel); - ui->color->setText(color.name(QColor::HexRgb)); - ui->color->setPalette(palette); - ui->color->setStyleSheet(QString("background-color :%1; color: %2;") - .arg(palette.color(QPalette::Window).name(QColor::HexRgb)) - .arg(palette.color(QPalette::WindowText).name(QColor::HexRgb))); - ui->color->setAutoFillBackground(true); - ui->color->setAlignment(Qt::AlignCenter); -} - -void ColorSourceToolbar::on_choose_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - obs_property_t *p = obs_properties_get(props.get(), "color"); - const char *desc = obs_property_description(p); - - QColorDialog::ColorDialogOptions options; - - options |= QColorDialog::ShowAlphaChannel; -#ifdef __linux__ - // TODO: Revisit hang on Ubuntu with native dialog - options |= QColorDialog::DontUseNativeDialog; -#endif - - QColor newColor = QColorDialog::getColor(color, this, desc, options); - if (!newColor.isValid()) { - return; - } - - color = newColor; - UpdateColor(); - - SaveOldProperties(source); - - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_int(settings, "color", color_to_int(color)); - obs_source_update(source, settings); - - SetUndoProperties(source); -} - -/* ========================================================================= */ - -extern void MakeQFont(obs_data_t *font_obj, QFont &font, bool limit = false); - -TextSourceToolbar::TextSourceToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_TextSourceToolbar) -{ - ui->setupUi(this); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - - const char *id = obs_source_get_unversioned_id(source); - bool ft2 = strcmp(id, "text_ft2_source") == 0; - bool read_from_file = obs_data_get_bool(settings, ft2 ? "from_file" : "read_from_file"); - - OBSDataAutoRelease font_obj = obs_data_get_obj(settings, "font"); - MakeQFont(font_obj, font); - - // Use "color1" if it's a freetype source and "color" elsewise - unsigned int val = (unsigned int)obs_data_get_int( - settings, (strncmp(obs_source_get_id(source), "text_ft2_source", 15) == 0) ? "color1" : "color"); - - color = color_from_int(val); - - const char *text = obs_data_get_string(settings, "text"); - - bool single_line = !read_from_file && (!text || (strchr(text, '\n') == nullptr)); - ui->emptySpace->setVisible(!single_line); - ui->text->setVisible(single_line); - if (single_line) - ui->text->setText(text); -} - -TextSourceToolbar::~TextSourceToolbar() {} - -void TextSourceToolbar::on_selectFont_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - QFontDialog::FontDialogOptions options; - uint32_t flags; - bool success; - -#ifndef _WIN32 - options = QFontDialog::DontUseNativeDialog; -#endif - - font = QFontDialog::getFont(&success, font, this, QTStr("Basic.PropertiesWindow.SelectFont.WindowTitle"), - options); - if (!success) { - return; - } - - OBSDataAutoRelease font_obj = obs_data_create(); - - obs_data_set_string(font_obj, "face", QT_TO_UTF8(font.family())); - obs_data_set_string(font_obj, "style", QT_TO_UTF8(font.styleName())); - obs_data_set_int(font_obj, "size", font.pointSize()); - flags = font.bold() ? OBS_FONT_BOLD : 0; - flags |= font.italic() ? OBS_FONT_ITALIC : 0; - flags |= font.underline() ? OBS_FONT_UNDERLINE : 0; - flags |= font.strikeOut() ? OBS_FONT_STRIKEOUT : 0; - obs_data_set_int(font_obj, "flags", flags); - - SaveOldProperties(source); - - OBSDataAutoRelease settings = obs_data_create(); - - obs_data_set_obj(settings, "font", font_obj); - - obs_source_update(source, settings); - - SetUndoProperties(source); -} - -void TextSourceToolbar::on_selectColor_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - bool freetype = strncmp(obs_source_get_id(source), "text_ft2_source", 15) == 0; - - obs_property_t *p = obs_properties_get(props.get(), freetype ? "color1" : "color"); - - const char *desc = obs_property_description(p); - - QColorDialog::ColorDialogOptions options; - - options |= QColorDialog::ShowAlphaChannel; -#ifdef __linux__ - // TODO: Revisit hang on Ubuntu with native dialog - options |= QColorDialog::DontUseNativeDialog; -#endif - - QColor newColor = QColorDialog::getColor(color, this, desc, options); - if (!newColor.isValid()) { - return; - } - - color = newColor; - - SaveOldProperties(source); - - OBSDataAutoRelease settings = obs_data_create(); - if (freetype) { - obs_data_set_int(settings, "color1", color_to_int(color)); - obs_data_set_int(settings, "color2", color_to_int(color)); - } else { - obs_data_set_int(settings, "color", color_to_int(color)); - } - obs_source_update(source, settings); - - SetUndoProperties(source); -} - -void TextSourceToolbar::on_text_textChanged() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - std::string newText = QT_TO_UTF8(ui->text->text()); - OBSDataAutoRelease settings = obs_source_get_settings(source); - if (newText == obs_data_get_string(settings, "text")) { - return; - } - SaveOldProperties(source); - - obs_data_set_string(settings, "text", newText.c_str()); - obs_source_update(source, nullptr); - - SetUndoProperties(source, true); -} diff --git a/frontend/components/DisplayCaptureToolbar.hpp b/frontend/components/DisplayCaptureToolbar.hpp index acf88a5fb..0f2f3bb13 100644 --- a/frontend/components/DisplayCaptureToolbar.hpp +++ b/frontend/components/DisplayCaptureToolbar.hpp @@ -1,93 +1,6 @@ #pragma once -#include -#include -#include - -class Ui_BrowserSourceToolbar; -class Ui_DeviceSelectToolbar; -class Ui_GameCaptureToolbar; -class Ui_ImageSourceToolbar; -class Ui_ColorSourceToolbar; -class Ui_TextSourceToolbar; - -class SourceToolbar : public QWidget { - Q_OBJECT - - OBSWeakSource weakSource; - -protected: - using properties_delete_t = decltype(&obs_properties_destroy); - using properties_t = std::unique_ptr; - - properties_t props; - OBSDataAutoRelease oldData; - - void SaveOldProperties(obs_source_t *source); - void SetUndoProperties(obs_source_t *source, bool repeatable = false); - -public: - SourceToolbar(QWidget *parent, OBSSource source); - - OBSSource GetSource() { return OBSGetStrongRef(weakSource); } - -public slots: - virtual void Update() {} -}; - -class BrowserToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - -public: - BrowserToolbar(QWidget *parent, OBSSource source); - ~BrowserToolbar(); - -public slots: - void on_refresh_clicked(); -}; - -class ComboSelectToolbar : public SourceToolbar { - Q_OBJECT - -protected: - std::unique_ptr ui; - const char *prop_name; - bool is_int = false; - -public: - ComboSelectToolbar(QWidget *parent, OBSSource source); - ~ComboSelectToolbar(); - virtual void Init(); - -public slots: - void on_device_currentIndexChanged(int idx); -}; - -class AudioCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - AudioCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class WindowCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - WindowCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class ApplicationAudioCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - ApplicationAudioCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; +#include "ComboSelectToolbar.hpp" class DisplayCaptureToolbar : public ComboSelectToolbar { Q_OBJECT @@ -96,83 +9,3 @@ public: DisplayCaptureToolbar(QWidget *parent, OBSSource source); void Init() override; }; - -class DeviceCaptureToolbar : public QWidget { - Q_OBJECT - - OBSWeakSource weakSource; - - std::unique_ptr ui; - const char *activateText; - const char *deactivateText; - bool active; - -public: - DeviceCaptureToolbar(QWidget *parent, OBSSource source); - ~DeviceCaptureToolbar(); - -public slots: - void on_activateButton_clicked(); -}; - -class GameCaptureToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - - void UpdateWindowVisibility(); - -public: - GameCaptureToolbar(QWidget *parent, OBSSource source); - ~GameCaptureToolbar(); - -public slots: - void on_mode_currentIndexChanged(int idx); - void on_window_currentIndexChanged(int idx); -}; - -class ImageSourceToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - -public: - ImageSourceToolbar(QWidget *parent, OBSSource source); - ~ImageSourceToolbar(); - -public slots: - void on_browse_clicked(); -}; - -class ColorSourceToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - QColor color; - - void UpdateColor(); - -public: - ColorSourceToolbar(QWidget *parent, OBSSource source); - ~ColorSourceToolbar(); - -public slots: - void on_choose_clicked(); -}; - -class TextSourceToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - QFont font; - QColor color; - -public: - TextSourceToolbar(QWidget *parent, OBSSource source); - ~TextSourceToolbar(); - -public slots: - void on_selectFont_clicked(); - void on_selectColor_clicked(); - void on_text_textChanged(); -}; diff --git a/frontend/components/GameCaptureToolbar.cpp b/frontend/components/GameCaptureToolbar.cpp index c45d06976..2a9f8afdf 100644 --- a/frontend/components/GameCaptureToolbar.cpp +++ b/frontend/components/GameCaptureToolbar.cpp @@ -1,359 +1,11 @@ -#include "window-basic-main.hpp" -#include "moc_context-bar-controls.cpp" -#include "obs-app.hpp" +#include "GameCaptureToolbar.hpp" +#include "ui_game-capture-toolbar.h" #include -#include -#include -#include -#include "ui_browser-source-toolbar.h" -#include "ui_device-select-toolbar.h" -#include "ui_game-capture-toolbar.h" -#include "ui_image-source-toolbar.h" -#include "ui_color-source-toolbar.h" -#include "ui_text-source-toolbar.h" +#include "moc_GameCaptureToolbar.cpp" -#ifdef _WIN32 -#define get_os_module(win, mac, linux) obs_get_module(win) -#define get_os_text(mod, win, mac, linux) obs_module_get_locale_text(mod, win) -#elif __APPLE__ -#define get_os_module(win, mac, linux) obs_get_module(mac) -#define get_os_text(mod, win, mac, linux) obs_module_get_locale_text(mod, mac) -#else -#define get_os_module(win, mac, linux) obs_get_module(linux) -#define get_os_text(mod, win, mac, linux) obs_module_get_locale_text(mod, linux) -#endif - -/* ========================================================================= */ - -SourceToolbar::SourceToolbar(QWidget *parent, OBSSource source) - : QWidget(parent), - weakSource(OBSGetWeakRef(source)), - props(obs_source_properties(source), obs_properties_destroy) -{ -} - -void SourceToolbar::SaveOldProperties(obs_source_t *source) -{ - oldData = obs_data_create(); - - OBSDataAutoRelease oldSettings = obs_source_get_settings(source); - obs_data_apply(oldData, oldSettings); - obs_data_set_string(oldData, "undo_suuid", obs_source_get_uuid(source)); -} - -void SourceToolbar::SetUndoProperties(obs_source_t *source, bool repeatable) -{ - if (!oldData) { - blog(LOG_ERROR, "%s: somehow oldData was null.", __FUNCTION__); - return; - } - - OBSBasic *main = reinterpret_cast(App()->GetMainWindow()); - - OBSSource currentSceneSource = main->GetCurrentSceneSource(); - if (!currentSceneSource) - return; - std::string scene_uuid = obs_source_get_uuid(currentSceneSource); - auto undo_redo = [scene_uuid = std::move(scene_uuid), main](const std::string &data) { - OBSDataAutoRelease settings = obs_data_create_from_json(data.c_str()); - OBSSourceAutoRelease source = obs_get_source_by_uuid(obs_data_get_string(settings, "undo_suuid")); - obs_source_reset_settings(source, settings); - - OBSSourceAutoRelease scene_source = obs_get_source_by_uuid(scene_uuid.c_str()); - main->SetCurrentScene(scene_source.Get(), true); - - main->UpdateContextBar(); - }; - - OBSDataAutoRelease new_settings = obs_data_create(); - OBSDataAutoRelease curr_settings = obs_source_get_settings(source); - obs_data_apply(new_settings, curr_settings); - obs_data_set_string(new_settings, "undo_suuid", obs_source_get_uuid(source)); - - std::string undo_data(obs_data_get_json(oldData)); - std::string redo_data(obs_data_get_json(new_settings)); - - if (undo_data.compare(redo_data) != 0) - main->undo_s.add_action(QTStr("Undo.Properties").arg(obs_source_get_name(source)), undo_redo, undo_redo, - undo_data, redo_data, repeatable); - - oldData = nullptr; -} - -/* ========================================================================= */ - -BrowserToolbar::BrowserToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_BrowserSourceToolbar) -{ - ui->setupUi(this); -} - -BrowserToolbar::~BrowserToolbar() {} - -void BrowserToolbar::on_refresh_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - obs_property_t *p = obs_properties_get(props.get(), "refreshnocache"); - obs_property_button_clicked(p, source.Get()); -} - -/* ========================================================================= */ - -ComboSelectToolbar::ComboSelectToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_DeviceSelectToolbar) -{ - ui->setupUi(this); -} - -ComboSelectToolbar::~ComboSelectToolbar() {} - -static int FillPropertyCombo(QComboBox *c, obs_property_t *p, const std::string &cur_id, bool is_int = false) -{ - size_t count = obs_property_list_item_count(p); - int cur_idx = -1; - - for (size_t i = 0; i < count; i++) { - const char *name = obs_property_list_item_name(p, i); - std::string id; - - if (is_int) { - id = std::to_string(obs_property_list_item_int(p, i)); - } else { - const char *val = obs_property_list_item_string(p, i); - id = val ? val : ""; - } - - if (cur_id == id) - cur_idx = (int)i; - - c->addItem(name, id.c_str()); - } - - return cur_idx; -} - -void UpdateSourceComboToolbarProperties(QComboBox *combo, OBSSource source, obs_properties_t *props, - const char *prop_name, bool is_int) -{ - std::string cur_id; - - OBSDataAutoRelease settings = obs_source_get_settings(source); - if (is_int) { - cur_id = std::to_string(obs_data_get_int(settings, prop_name)); - } else { - cur_id = obs_data_get_string(settings, prop_name); - } - - combo->blockSignals(true); - - obs_property_t *p = obs_properties_get(props, prop_name); - int cur_idx = FillPropertyCombo(combo, p, cur_id, is_int); - - if (cur_idx == -1 || obs_property_list_item_disabled(p, cur_idx)) { - if (cur_idx == -1) { - combo->insertItem(0, QTStr("Basic.Settings.Audio.UnknownAudioDevice")); - cur_idx = 0; - } - - SetComboItemEnabled(combo, cur_idx, false); - } - - combo->setCurrentIndex(cur_idx); - combo->blockSignals(false); -} - -void ComboSelectToolbar::Init() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - UpdateSourceComboToolbarProperties(ui->device, source, props.get(), prop_name, is_int); -} - -void UpdateSourceComboToolbarValue(QComboBox *combo, OBSSource source, int idx, const char *prop_name, bool is_int) -{ - QString id = combo->itemData(idx).toString(); - - OBSDataAutoRelease settings = obs_data_create(); - if (is_int) { - obs_data_set_int(settings, prop_name, id.toInt()); - } else { - obs_data_set_string(settings, prop_name, QT_TO_UTF8(id)); - } - obs_source_update(source, settings); -} - -void ComboSelectToolbar::on_device_currentIndexChanged(int idx) -{ - OBSSource source = GetSource(); - if (idx == -1 || !source) { - return; - } - - SaveOldProperties(source); - UpdateSourceComboToolbarValue(ui->device, source, idx, prop_name, is_int); - SetUndoProperties(source); -} - -AudioCaptureToolbar::AudioCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) {} - -void AudioCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = get_os_module("win-wasapi", "mac-capture", "linux-pulseaudio"); - if (!mod) - return; - - const char *device_str = get_os_text(mod, "Device", "CoreAudio.Device", "Device"); - ui->deviceLabel->setText(device_str); - - prop_name = "device_id"; - - ComboSelectToolbar::Init(); -} - -WindowCaptureToolbar::WindowCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) {} - -void WindowCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = get_os_module("win-capture", "mac-capture", "linux-capture"); - if (!mod) - return; - - const char *device_str = get_os_text(mod, "WindowCapture.Window", "WindowUtils.Window", "Window"); - ui->deviceLabel->setText(device_str); - -#if !defined(_WIN32) && !defined(__APPLE__) //linux - prop_name = "capture_window"; -#else - prop_name = "window"; -#endif - -#ifdef __APPLE__ - is_int = true; -#endif - - ComboSelectToolbar::Init(); -} - -ApplicationAudioCaptureToolbar::ApplicationAudioCaptureToolbar(QWidget *parent, OBSSource source) - : ComboSelectToolbar(parent, source) -{ -} - -void ApplicationAudioCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = obs_get_module("win-wasapi"); - const char *device_str = obs_module_get_locale_text(mod, "Window"); - ui->deviceLabel->setText(device_str); - - prop_name = "window"; - - ComboSelectToolbar::Init(); -} - -DisplayCaptureToolbar::DisplayCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) {} - -void DisplayCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = get_os_module("win-capture", "mac-capture", "linux-capture"); - if (!mod) - return; - - const char *device_str = get_os_text(mod, "Monitor", "DisplayCapture.Display", "Screen"); - ui->deviceLabel->setText(device_str); - -#ifdef _WIN32 - prop_name = "monitor_id"; -#elif __APPLE__ - prop_name = "display_uuid"; -#else - is_int = true; - prop_name = "screen"; -#endif - - ComboSelectToolbar::Init(); -} - -/* ========================================================================= */ - -DeviceCaptureToolbar::DeviceCaptureToolbar(QWidget *parent, OBSSource source) - : QWidget(parent), - weakSource(OBSGetWeakRef(source)), - ui(new Ui_DeviceSelectToolbar) -{ - ui->setupUi(this); - - delete ui->deviceLabel; - delete ui->device; - ui->deviceLabel = nullptr; - ui->device = nullptr; - - OBSDataAutoRelease settings = obs_source_get_settings(source); - active = obs_data_get_bool(settings, "active"); - - obs_module_t *mod = obs_get_module("win-dshow"); - if (!mod) - return; - - activateText = obs_module_get_locale_text(mod, "Activate"); - deactivateText = obs_module_get_locale_text(mod, "Deactivate"); - - ui->activateButton->setText(active ? deactivateText : activateText); -} - -DeviceCaptureToolbar::~DeviceCaptureToolbar() {} - -void DeviceCaptureToolbar::on_activateButton_clicked() -{ - OBSSource source = OBSGetStrongRef(weakSource); - if (!source) { - return; - } - - OBSDataAutoRelease settings = obs_source_get_settings(source); - bool now_active = obs_data_get_bool(settings, "active"); - - bool desyncedSetting = now_active != active; - - active = !active; - - const char *text = active ? deactivateText : activateText; - ui->activateButton->setText(text); - - if (desyncedSetting) { - return; - } - - calldata_t cd = {}; - calldata_set_bool(&cd, "active", active); - proc_handler_t *ph = obs_source_get_proc_handler(source); - proc_handler_call(ph, "activate", &cd); - calldata_free(&cd); -} - -/* ========================================================================= */ +extern int FillPropertyCombo(QComboBox *c, obs_property_t *p, const std::string &cur_id, bool is_int = false); GameCaptureToolbar::GameCaptureToolbar(QWidget *parent, OBSSource source) : SourceToolbar(parent, source), @@ -437,271 +89,3 @@ void GameCaptureToolbar::on_window_currentIndexChanged(int idx) obs_source_update(source, settings); SetUndoProperties(source); } - -/* ========================================================================= */ - -ImageSourceToolbar::ImageSourceToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_ImageSourceToolbar) -{ - ui->setupUi(this); - - obs_module_t *mod = obs_get_module("image-source"); - ui->pathLabel->setText(obs_module_get_locale_text(mod, "File")); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - std::string file = obs_data_get_string(settings, "file"); - - ui->path->setText(file.c_str()); -} - -ImageSourceToolbar::~ImageSourceToolbar() {} - -void ImageSourceToolbar::on_browse_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - obs_property_t *p = obs_properties_get(props.get(), "file"); - const char *desc = obs_property_description(p); - const char *filter = obs_property_path_filter(p); - const char *default_path = obs_property_path_default_path(p); - - QString startDir = ui->path->text(); - if (startDir.isEmpty()) - startDir = default_path; - - QString path = OpenFile(this, desc, startDir, filter); - if (path.isEmpty()) { - return; - } - - ui->path->setText(path); - - SaveOldProperties(source); - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_string(settings, "file", QT_TO_UTF8(path)); - obs_source_update(source, settings); - SetUndoProperties(source); -} - -/* ========================================================================= */ - -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); -} - -ColorSourceToolbar::ColorSourceToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_ColorSourceToolbar) -{ - ui->setupUi(this); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - unsigned int val = (unsigned int)obs_data_get_int(settings, "color"); - - color = color_from_int(val); - UpdateColor(); -} - -ColorSourceToolbar::~ColorSourceToolbar() {} - -void ColorSourceToolbar::UpdateColor() -{ - QPalette palette = QPalette(color); - ui->color->setFrameStyle(QFrame::Sunken | QFrame::Panel); - ui->color->setText(color.name(QColor::HexRgb)); - ui->color->setPalette(palette); - ui->color->setStyleSheet(QString("background-color :%1; color: %2;") - .arg(palette.color(QPalette::Window).name(QColor::HexRgb)) - .arg(palette.color(QPalette::WindowText).name(QColor::HexRgb))); - ui->color->setAutoFillBackground(true); - ui->color->setAlignment(Qt::AlignCenter); -} - -void ColorSourceToolbar::on_choose_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - obs_property_t *p = obs_properties_get(props.get(), "color"); - const char *desc = obs_property_description(p); - - QColorDialog::ColorDialogOptions options; - - options |= QColorDialog::ShowAlphaChannel; -#ifdef __linux__ - // TODO: Revisit hang on Ubuntu with native dialog - options |= QColorDialog::DontUseNativeDialog; -#endif - - QColor newColor = QColorDialog::getColor(color, this, desc, options); - if (!newColor.isValid()) { - return; - } - - color = newColor; - UpdateColor(); - - SaveOldProperties(source); - - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_int(settings, "color", color_to_int(color)); - obs_source_update(source, settings); - - SetUndoProperties(source); -} - -/* ========================================================================= */ - -extern void MakeQFont(obs_data_t *font_obj, QFont &font, bool limit = false); - -TextSourceToolbar::TextSourceToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_TextSourceToolbar) -{ - ui->setupUi(this); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - - const char *id = obs_source_get_unversioned_id(source); - bool ft2 = strcmp(id, "text_ft2_source") == 0; - bool read_from_file = obs_data_get_bool(settings, ft2 ? "from_file" : "read_from_file"); - - OBSDataAutoRelease font_obj = obs_data_get_obj(settings, "font"); - MakeQFont(font_obj, font); - - // Use "color1" if it's a freetype source and "color" elsewise - unsigned int val = (unsigned int)obs_data_get_int( - settings, (strncmp(obs_source_get_id(source), "text_ft2_source", 15) == 0) ? "color1" : "color"); - - color = color_from_int(val); - - const char *text = obs_data_get_string(settings, "text"); - - bool single_line = !read_from_file && (!text || (strchr(text, '\n') == nullptr)); - ui->emptySpace->setVisible(!single_line); - ui->text->setVisible(single_line); - if (single_line) - ui->text->setText(text); -} - -TextSourceToolbar::~TextSourceToolbar() {} - -void TextSourceToolbar::on_selectFont_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - QFontDialog::FontDialogOptions options; - uint32_t flags; - bool success; - -#ifndef _WIN32 - options = QFontDialog::DontUseNativeDialog; -#endif - - font = QFontDialog::getFont(&success, font, this, QTStr("Basic.PropertiesWindow.SelectFont.WindowTitle"), - options); - if (!success) { - return; - } - - OBSDataAutoRelease font_obj = obs_data_create(); - - obs_data_set_string(font_obj, "face", QT_TO_UTF8(font.family())); - obs_data_set_string(font_obj, "style", QT_TO_UTF8(font.styleName())); - obs_data_set_int(font_obj, "size", font.pointSize()); - flags = font.bold() ? OBS_FONT_BOLD : 0; - flags |= font.italic() ? OBS_FONT_ITALIC : 0; - flags |= font.underline() ? OBS_FONT_UNDERLINE : 0; - flags |= font.strikeOut() ? OBS_FONT_STRIKEOUT : 0; - obs_data_set_int(font_obj, "flags", flags); - - SaveOldProperties(source); - - OBSDataAutoRelease settings = obs_data_create(); - - obs_data_set_obj(settings, "font", font_obj); - - obs_source_update(source, settings); - - SetUndoProperties(source); -} - -void TextSourceToolbar::on_selectColor_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - bool freetype = strncmp(obs_source_get_id(source), "text_ft2_source", 15) == 0; - - obs_property_t *p = obs_properties_get(props.get(), freetype ? "color1" : "color"); - - const char *desc = obs_property_description(p); - - QColorDialog::ColorDialogOptions options; - - options |= QColorDialog::ShowAlphaChannel; -#ifdef __linux__ - // TODO: Revisit hang on Ubuntu with native dialog - options |= QColorDialog::DontUseNativeDialog; -#endif - - QColor newColor = QColorDialog::getColor(color, this, desc, options); - if (!newColor.isValid()) { - return; - } - - color = newColor; - - SaveOldProperties(source); - - OBSDataAutoRelease settings = obs_data_create(); - if (freetype) { - obs_data_set_int(settings, "color1", color_to_int(color)); - obs_data_set_int(settings, "color2", color_to_int(color)); - } else { - obs_data_set_int(settings, "color", color_to_int(color)); - } - obs_source_update(source, settings); - - SetUndoProperties(source); -} - -void TextSourceToolbar::on_text_textChanged() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - std::string newText = QT_TO_UTF8(ui->text->text()); - OBSDataAutoRelease settings = obs_source_get_settings(source); - if (newText == obs_data_get_string(settings, "text")) { - return; - } - SaveOldProperties(source); - - obs_data_set_string(settings, "text", newText.c_str()); - obs_source_update(source, nullptr); - - SetUndoProperties(source, true); -} diff --git a/frontend/components/GameCaptureToolbar.hpp b/frontend/components/GameCaptureToolbar.hpp index acf88a5fb..0dcf769e3 100644 --- a/frontend/components/GameCaptureToolbar.hpp +++ b/frontend/components/GameCaptureToolbar.hpp @@ -1,119 +1,8 @@ #pragma once -#include -#include -#include +#include "SourceToolbar.hpp" -class Ui_BrowserSourceToolbar; -class Ui_DeviceSelectToolbar; class Ui_GameCaptureToolbar; -class Ui_ImageSourceToolbar; -class Ui_ColorSourceToolbar; -class Ui_TextSourceToolbar; - -class SourceToolbar : public QWidget { - Q_OBJECT - - OBSWeakSource weakSource; - -protected: - using properties_delete_t = decltype(&obs_properties_destroy); - using properties_t = std::unique_ptr; - - properties_t props; - OBSDataAutoRelease oldData; - - void SaveOldProperties(obs_source_t *source); - void SetUndoProperties(obs_source_t *source, bool repeatable = false); - -public: - SourceToolbar(QWidget *parent, OBSSource source); - - OBSSource GetSource() { return OBSGetStrongRef(weakSource); } - -public slots: - virtual void Update() {} -}; - -class BrowserToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - -public: - BrowserToolbar(QWidget *parent, OBSSource source); - ~BrowserToolbar(); - -public slots: - void on_refresh_clicked(); -}; - -class ComboSelectToolbar : public SourceToolbar { - Q_OBJECT - -protected: - std::unique_ptr ui; - const char *prop_name; - bool is_int = false; - -public: - ComboSelectToolbar(QWidget *parent, OBSSource source); - ~ComboSelectToolbar(); - virtual void Init(); - -public slots: - void on_device_currentIndexChanged(int idx); -}; - -class AudioCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - AudioCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class WindowCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - WindowCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class ApplicationAudioCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - ApplicationAudioCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class DisplayCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - DisplayCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class DeviceCaptureToolbar : public QWidget { - Q_OBJECT - - OBSWeakSource weakSource; - - std::unique_ptr ui; - const char *activateText; - const char *deactivateText; - bool active; - -public: - DeviceCaptureToolbar(QWidget *parent, OBSSource source); - ~DeviceCaptureToolbar(); - -public slots: - void on_activateButton_clicked(); -}; class GameCaptureToolbar : public SourceToolbar { Q_OBJECT @@ -130,49 +19,3 @@ public slots: void on_mode_currentIndexChanged(int idx); void on_window_currentIndexChanged(int idx); }; - -class ImageSourceToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - -public: - ImageSourceToolbar(QWidget *parent, OBSSource source); - ~ImageSourceToolbar(); - -public slots: - void on_browse_clicked(); -}; - -class ColorSourceToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - QColor color; - - void UpdateColor(); - -public: - ColorSourceToolbar(QWidget *parent, OBSSource source); - ~ColorSourceToolbar(); - -public slots: - void on_choose_clicked(); -}; - -class TextSourceToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - QFont font; - QColor color; - -public: - TextSourceToolbar(QWidget *parent, OBSSource source); - ~TextSourceToolbar(); - -public slots: - void on_selectFont_clicked(); - void on_selectColor_clicked(); - void on_text_textChanged(); -}; diff --git a/frontend/components/ImageSourceToolbar.cpp b/frontend/components/ImageSourceToolbar.cpp index c45d06976..71458cef2 100644 --- a/frontend/components/ImageSourceToolbar.cpp +++ b/frontend/components/ImageSourceToolbar.cpp @@ -1,444 +1,9 @@ -#include "window-basic-main.hpp" -#include "moc_context-bar-controls.cpp" -#include "obs-app.hpp" +#include "ImageSourceToolbar.hpp" +#include "ui_image-source-toolbar.h" #include -#include -#include -#include -#include "ui_browser-source-toolbar.h" -#include "ui_device-select-toolbar.h" -#include "ui_game-capture-toolbar.h" -#include "ui_image-source-toolbar.h" -#include "ui_color-source-toolbar.h" -#include "ui_text-source-toolbar.h" - -#ifdef _WIN32 -#define get_os_module(win, mac, linux) obs_get_module(win) -#define get_os_text(mod, win, mac, linux) obs_module_get_locale_text(mod, win) -#elif __APPLE__ -#define get_os_module(win, mac, linux) obs_get_module(mac) -#define get_os_text(mod, win, mac, linux) obs_module_get_locale_text(mod, mac) -#else -#define get_os_module(win, mac, linux) obs_get_module(linux) -#define get_os_text(mod, win, mac, linux) obs_module_get_locale_text(mod, linux) -#endif - -/* ========================================================================= */ - -SourceToolbar::SourceToolbar(QWidget *parent, OBSSource source) - : QWidget(parent), - weakSource(OBSGetWeakRef(source)), - props(obs_source_properties(source), obs_properties_destroy) -{ -} - -void SourceToolbar::SaveOldProperties(obs_source_t *source) -{ - oldData = obs_data_create(); - - OBSDataAutoRelease oldSettings = obs_source_get_settings(source); - obs_data_apply(oldData, oldSettings); - obs_data_set_string(oldData, "undo_suuid", obs_source_get_uuid(source)); -} - -void SourceToolbar::SetUndoProperties(obs_source_t *source, bool repeatable) -{ - if (!oldData) { - blog(LOG_ERROR, "%s: somehow oldData was null.", __FUNCTION__); - return; - } - - OBSBasic *main = reinterpret_cast(App()->GetMainWindow()); - - OBSSource currentSceneSource = main->GetCurrentSceneSource(); - if (!currentSceneSource) - return; - std::string scene_uuid = obs_source_get_uuid(currentSceneSource); - auto undo_redo = [scene_uuid = std::move(scene_uuid), main](const std::string &data) { - OBSDataAutoRelease settings = obs_data_create_from_json(data.c_str()); - OBSSourceAutoRelease source = obs_get_source_by_uuid(obs_data_get_string(settings, "undo_suuid")); - obs_source_reset_settings(source, settings); - - OBSSourceAutoRelease scene_source = obs_get_source_by_uuid(scene_uuid.c_str()); - main->SetCurrentScene(scene_source.Get(), true); - - main->UpdateContextBar(); - }; - - OBSDataAutoRelease new_settings = obs_data_create(); - OBSDataAutoRelease curr_settings = obs_source_get_settings(source); - obs_data_apply(new_settings, curr_settings); - obs_data_set_string(new_settings, "undo_suuid", obs_source_get_uuid(source)); - - std::string undo_data(obs_data_get_json(oldData)); - std::string redo_data(obs_data_get_json(new_settings)); - - if (undo_data.compare(redo_data) != 0) - main->undo_s.add_action(QTStr("Undo.Properties").arg(obs_source_get_name(source)), undo_redo, undo_redo, - undo_data, redo_data, repeatable); - - oldData = nullptr; -} - -/* ========================================================================= */ - -BrowserToolbar::BrowserToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_BrowserSourceToolbar) -{ - ui->setupUi(this); -} - -BrowserToolbar::~BrowserToolbar() {} - -void BrowserToolbar::on_refresh_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - obs_property_t *p = obs_properties_get(props.get(), "refreshnocache"); - obs_property_button_clicked(p, source.Get()); -} - -/* ========================================================================= */ - -ComboSelectToolbar::ComboSelectToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_DeviceSelectToolbar) -{ - ui->setupUi(this); -} - -ComboSelectToolbar::~ComboSelectToolbar() {} - -static int FillPropertyCombo(QComboBox *c, obs_property_t *p, const std::string &cur_id, bool is_int = false) -{ - size_t count = obs_property_list_item_count(p); - int cur_idx = -1; - - for (size_t i = 0; i < count; i++) { - const char *name = obs_property_list_item_name(p, i); - std::string id; - - if (is_int) { - id = std::to_string(obs_property_list_item_int(p, i)); - } else { - const char *val = obs_property_list_item_string(p, i); - id = val ? val : ""; - } - - if (cur_id == id) - cur_idx = (int)i; - - c->addItem(name, id.c_str()); - } - - return cur_idx; -} - -void UpdateSourceComboToolbarProperties(QComboBox *combo, OBSSource source, obs_properties_t *props, - const char *prop_name, bool is_int) -{ - std::string cur_id; - - OBSDataAutoRelease settings = obs_source_get_settings(source); - if (is_int) { - cur_id = std::to_string(obs_data_get_int(settings, prop_name)); - } else { - cur_id = obs_data_get_string(settings, prop_name); - } - - combo->blockSignals(true); - - obs_property_t *p = obs_properties_get(props, prop_name); - int cur_idx = FillPropertyCombo(combo, p, cur_id, is_int); - - if (cur_idx == -1 || obs_property_list_item_disabled(p, cur_idx)) { - if (cur_idx == -1) { - combo->insertItem(0, QTStr("Basic.Settings.Audio.UnknownAudioDevice")); - cur_idx = 0; - } - - SetComboItemEnabled(combo, cur_idx, false); - } - - combo->setCurrentIndex(cur_idx); - combo->blockSignals(false); -} - -void ComboSelectToolbar::Init() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - UpdateSourceComboToolbarProperties(ui->device, source, props.get(), prop_name, is_int); -} - -void UpdateSourceComboToolbarValue(QComboBox *combo, OBSSource source, int idx, const char *prop_name, bool is_int) -{ - QString id = combo->itemData(idx).toString(); - - OBSDataAutoRelease settings = obs_data_create(); - if (is_int) { - obs_data_set_int(settings, prop_name, id.toInt()); - } else { - obs_data_set_string(settings, prop_name, QT_TO_UTF8(id)); - } - obs_source_update(source, settings); -} - -void ComboSelectToolbar::on_device_currentIndexChanged(int idx) -{ - OBSSource source = GetSource(); - if (idx == -1 || !source) { - return; - } - - SaveOldProperties(source); - UpdateSourceComboToolbarValue(ui->device, source, idx, prop_name, is_int); - SetUndoProperties(source); -} - -AudioCaptureToolbar::AudioCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) {} - -void AudioCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = get_os_module("win-wasapi", "mac-capture", "linux-pulseaudio"); - if (!mod) - return; - - const char *device_str = get_os_text(mod, "Device", "CoreAudio.Device", "Device"); - ui->deviceLabel->setText(device_str); - - prop_name = "device_id"; - - ComboSelectToolbar::Init(); -} - -WindowCaptureToolbar::WindowCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) {} - -void WindowCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = get_os_module("win-capture", "mac-capture", "linux-capture"); - if (!mod) - return; - - const char *device_str = get_os_text(mod, "WindowCapture.Window", "WindowUtils.Window", "Window"); - ui->deviceLabel->setText(device_str); - -#if !defined(_WIN32) && !defined(__APPLE__) //linux - prop_name = "capture_window"; -#else - prop_name = "window"; -#endif - -#ifdef __APPLE__ - is_int = true; -#endif - - ComboSelectToolbar::Init(); -} - -ApplicationAudioCaptureToolbar::ApplicationAudioCaptureToolbar(QWidget *parent, OBSSource source) - : ComboSelectToolbar(parent, source) -{ -} - -void ApplicationAudioCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = obs_get_module("win-wasapi"); - const char *device_str = obs_module_get_locale_text(mod, "Window"); - ui->deviceLabel->setText(device_str); - - prop_name = "window"; - - ComboSelectToolbar::Init(); -} - -DisplayCaptureToolbar::DisplayCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) {} - -void DisplayCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = get_os_module("win-capture", "mac-capture", "linux-capture"); - if (!mod) - return; - - const char *device_str = get_os_text(mod, "Monitor", "DisplayCapture.Display", "Screen"); - ui->deviceLabel->setText(device_str); - -#ifdef _WIN32 - prop_name = "monitor_id"; -#elif __APPLE__ - prop_name = "display_uuid"; -#else - is_int = true; - prop_name = "screen"; -#endif - - ComboSelectToolbar::Init(); -} - -/* ========================================================================= */ - -DeviceCaptureToolbar::DeviceCaptureToolbar(QWidget *parent, OBSSource source) - : QWidget(parent), - weakSource(OBSGetWeakRef(source)), - ui(new Ui_DeviceSelectToolbar) -{ - ui->setupUi(this); - - delete ui->deviceLabel; - delete ui->device; - ui->deviceLabel = nullptr; - ui->device = nullptr; - - OBSDataAutoRelease settings = obs_source_get_settings(source); - active = obs_data_get_bool(settings, "active"); - - obs_module_t *mod = obs_get_module("win-dshow"); - if (!mod) - return; - - activateText = obs_module_get_locale_text(mod, "Activate"); - deactivateText = obs_module_get_locale_text(mod, "Deactivate"); - - ui->activateButton->setText(active ? deactivateText : activateText); -} - -DeviceCaptureToolbar::~DeviceCaptureToolbar() {} - -void DeviceCaptureToolbar::on_activateButton_clicked() -{ - OBSSource source = OBSGetStrongRef(weakSource); - if (!source) { - return; - } - - OBSDataAutoRelease settings = obs_source_get_settings(source); - bool now_active = obs_data_get_bool(settings, "active"); - - bool desyncedSetting = now_active != active; - - active = !active; - - const char *text = active ? deactivateText : activateText; - ui->activateButton->setText(text); - - if (desyncedSetting) { - return; - } - - calldata_t cd = {}; - calldata_set_bool(&cd, "active", active); - proc_handler_t *ph = obs_source_get_proc_handler(source); - proc_handler_call(ph, "activate", &cd); - calldata_free(&cd); -} - -/* ========================================================================= */ - -GameCaptureToolbar::GameCaptureToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_GameCaptureToolbar) -{ - obs_property_t *p; - int cur_idx; - - ui->setupUi(this); - - obs_module_t *mod = obs_get_module("win-capture"); - if (!mod) - return; - - ui->modeLabel->setText(obs_module_get_locale_text(mod, "Mode")); - ui->windowLabel->setText(obs_module_get_locale_text(mod, "WindowCapture.Window")); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - std::string cur_mode = obs_data_get_string(settings, "capture_mode"); - std::string cur_window = obs_data_get_string(settings, "window"); - - ui->mode->blockSignals(true); - p = obs_properties_get(props.get(), "capture_mode"); - cur_idx = FillPropertyCombo(ui->mode, p, cur_mode); - ui->mode->setCurrentIndex(cur_idx); - ui->mode->blockSignals(false); - - ui->window->blockSignals(true); - p = obs_properties_get(props.get(), "window"); - cur_idx = FillPropertyCombo(ui->window, p, cur_window); - ui->window->setCurrentIndex(cur_idx); - ui->window->blockSignals(false); - - if (cur_idx != -1 && obs_property_list_item_disabled(p, cur_idx)) { - SetComboItemEnabled(ui->window, cur_idx, false); - } - - UpdateWindowVisibility(); -} - -GameCaptureToolbar::~GameCaptureToolbar() {} - -void GameCaptureToolbar::UpdateWindowVisibility() -{ - QString mode = ui->mode->currentData().toString(); - bool is_window = (mode == "window"); - ui->windowLabel->setVisible(is_window); - ui->window->setVisible(is_window); -} - -void GameCaptureToolbar::on_mode_currentIndexChanged(int idx) -{ - OBSSource source = GetSource(); - if (idx == -1 || !source) { - return; - } - - QString id = ui->mode->itemData(idx).toString(); - - SaveOldProperties(source); - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_string(settings, "capture_mode", QT_TO_UTF8(id)); - obs_source_update(source, settings); - SetUndoProperties(source); - - UpdateWindowVisibility(); -} - -void GameCaptureToolbar::on_window_currentIndexChanged(int idx) -{ - OBSSource source = GetSource(); - if (idx == -1 || !source) { - return; - } - - QString id = ui->window->itemData(idx).toString(); - - SaveOldProperties(source); - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_string(settings, "window", QT_TO_UTF8(id)); - obs_source_update(source, settings); - SetUndoProperties(source); -} - -/* ========================================================================= */ +#include "moc_ImageSourceToolbar.cpp" ImageSourceToolbar::ImageSourceToolbar(QWidget *parent, OBSSource source) : SourceToolbar(parent, source), @@ -486,222 +51,3 @@ void ImageSourceToolbar::on_browse_clicked() obs_source_update(source, settings); SetUndoProperties(source); } - -/* ========================================================================= */ - -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); -} - -ColorSourceToolbar::ColorSourceToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_ColorSourceToolbar) -{ - ui->setupUi(this); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - unsigned int val = (unsigned int)obs_data_get_int(settings, "color"); - - color = color_from_int(val); - UpdateColor(); -} - -ColorSourceToolbar::~ColorSourceToolbar() {} - -void ColorSourceToolbar::UpdateColor() -{ - QPalette palette = QPalette(color); - ui->color->setFrameStyle(QFrame::Sunken | QFrame::Panel); - ui->color->setText(color.name(QColor::HexRgb)); - ui->color->setPalette(palette); - ui->color->setStyleSheet(QString("background-color :%1; color: %2;") - .arg(palette.color(QPalette::Window).name(QColor::HexRgb)) - .arg(palette.color(QPalette::WindowText).name(QColor::HexRgb))); - ui->color->setAutoFillBackground(true); - ui->color->setAlignment(Qt::AlignCenter); -} - -void ColorSourceToolbar::on_choose_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - obs_property_t *p = obs_properties_get(props.get(), "color"); - const char *desc = obs_property_description(p); - - QColorDialog::ColorDialogOptions options; - - options |= QColorDialog::ShowAlphaChannel; -#ifdef __linux__ - // TODO: Revisit hang on Ubuntu with native dialog - options |= QColorDialog::DontUseNativeDialog; -#endif - - QColor newColor = QColorDialog::getColor(color, this, desc, options); - if (!newColor.isValid()) { - return; - } - - color = newColor; - UpdateColor(); - - SaveOldProperties(source); - - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_int(settings, "color", color_to_int(color)); - obs_source_update(source, settings); - - SetUndoProperties(source); -} - -/* ========================================================================= */ - -extern void MakeQFont(obs_data_t *font_obj, QFont &font, bool limit = false); - -TextSourceToolbar::TextSourceToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_TextSourceToolbar) -{ - ui->setupUi(this); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - - const char *id = obs_source_get_unversioned_id(source); - bool ft2 = strcmp(id, "text_ft2_source") == 0; - bool read_from_file = obs_data_get_bool(settings, ft2 ? "from_file" : "read_from_file"); - - OBSDataAutoRelease font_obj = obs_data_get_obj(settings, "font"); - MakeQFont(font_obj, font); - - // Use "color1" if it's a freetype source and "color" elsewise - unsigned int val = (unsigned int)obs_data_get_int( - settings, (strncmp(obs_source_get_id(source), "text_ft2_source", 15) == 0) ? "color1" : "color"); - - color = color_from_int(val); - - const char *text = obs_data_get_string(settings, "text"); - - bool single_line = !read_from_file && (!text || (strchr(text, '\n') == nullptr)); - ui->emptySpace->setVisible(!single_line); - ui->text->setVisible(single_line); - if (single_line) - ui->text->setText(text); -} - -TextSourceToolbar::~TextSourceToolbar() {} - -void TextSourceToolbar::on_selectFont_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - QFontDialog::FontDialogOptions options; - uint32_t flags; - bool success; - -#ifndef _WIN32 - options = QFontDialog::DontUseNativeDialog; -#endif - - font = QFontDialog::getFont(&success, font, this, QTStr("Basic.PropertiesWindow.SelectFont.WindowTitle"), - options); - if (!success) { - return; - } - - OBSDataAutoRelease font_obj = obs_data_create(); - - obs_data_set_string(font_obj, "face", QT_TO_UTF8(font.family())); - obs_data_set_string(font_obj, "style", QT_TO_UTF8(font.styleName())); - obs_data_set_int(font_obj, "size", font.pointSize()); - flags = font.bold() ? OBS_FONT_BOLD : 0; - flags |= font.italic() ? OBS_FONT_ITALIC : 0; - flags |= font.underline() ? OBS_FONT_UNDERLINE : 0; - flags |= font.strikeOut() ? OBS_FONT_STRIKEOUT : 0; - obs_data_set_int(font_obj, "flags", flags); - - SaveOldProperties(source); - - OBSDataAutoRelease settings = obs_data_create(); - - obs_data_set_obj(settings, "font", font_obj); - - obs_source_update(source, settings); - - SetUndoProperties(source); -} - -void TextSourceToolbar::on_selectColor_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - bool freetype = strncmp(obs_source_get_id(source), "text_ft2_source", 15) == 0; - - obs_property_t *p = obs_properties_get(props.get(), freetype ? "color1" : "color"); - - const char *desc = obs_property_description(p); - - QColorDialog::ColorDialogOptions options; - - options |= QColorDialog::ShowAlphaChannel; -#ifdef __linux__ - // TODO: Revisit hang on Ubuntu with native dialog - options |= QColorDialog::DontUseNativeDialog; -#endif - - QColor newColor = QColorDialog::getColor(color, this, desc, options); - if (!newColor.isValid()) { - return; - } - - color = newColor; - - SaveOldProperties(source); - - OBSDataAutoRelease settings = obs_data_create(); - if (freetype) { - obs_data_set_int(settings, "color1", color_to_int(color)); - obs_data_set_int(settings, "color2", color_to_int(color)); - } else { - obs_data_set_int(settings, "color", color_to_int(color)); - } - obs_source_update(source, settings); - - SetUndoProperties(source); -} - -void TextSourceToolbar::on_text_textChanged() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - std::string newText = QT_TO_UTF8(ui->text->text()); - OBSDataAutoRelease settings = obs_source_get_settings(source); - if (newText == obs_data_get_string(settings, "text")) { - return; - } - SaveOldProperties(source); - - obs_data_set_string(settings, "text", newText.c_str()); - obs_source_update(source, nullptr); - - SetUndoProperties(source, true); -} diff --git a/frontend/components/ImageSourceToolbar.hpp b/frontend/components/ImageSourceToolbar.hpp index acf88a5fb..700b90b38 100644 --- a/frontend/components/ImageSourceToolbar.hpp +++ b/frontend/components/ImageSourceToolbar.hpp @@ -1,135 +1,8 @@ #pragma once -#include -#include -#include +#include "SourceToolbar.hpp" -class Ui_BrowserSourceToolbar; -class Ui_DeviceSelectToolbar; -class Ui_GameCaptureToolbar; class Ui_ImageSourceToolbar; -class Ui_ColorSourceToolbar; -class Ui_TextSourceToolbar; - -class SourceToolbar : public QWidget { - Q_OBJECT - - OBSWeakSource weakSource; - -protected: - using properties_delete_t = decltype(&obs_properties_destroy); - using properties_t = std::unique_ptr; - - properties_t props; - OBSDataAutoRelease oldData; - - void SaveOldProperties(obs_source_t *source); - void SetUndoProperties(obs_source_t *source, bool repeatable = false); - -public: - SourceToolbar(QWidget *parent, OBSSource source); - - OBSSource GetSource() { return OBSGetStrongRef(weakSource); } - -public slots: - virtual void Update() {} -}; - -class BrowserToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - -public: - BrowserToolbar(QWidget *parent, OBSSource source); - ~BrowserToolbar(); - -public slots: - void on_refresh_clicked(); -}; - -class ComboSelectToolbar : public SourceToolbar { - Q_OBJECT - -protected: - std::unique_ptr ui; - const char *prop_name; - bool is_int = false; - -public: - ComboSelectToolbar(QWidget *parent, OBSSource source); - ~ComboSelectToolbar(); - virtual void Init(); - -public slots: - void on_device_currentIndexChanged(int idx); -}; - -class AudioCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - AudioCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class WindowCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - WindowCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class ApplicationAudioCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - ApplicationAudioCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class DisplayCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - DisplayCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class DeviceCaptureToolbar : public QWidget { - Q_OBJECT - - OBSWeakSource weakSource; - - std::unique_ptr ui; - const char *activateText; - const char *deactivateText; - bool active; - -public: - DeviceCaptureToolbar(QWidget *parent, OBSSource source); - ~DeviceCaptureToolbar(); - -public slots: - void on_activateButton_clicked(); -}; - -class GameCaptureToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - - void UpdateWindowVisibility(); - -public: - GameCaptureToolbar(QWidget *parent, OBSSource source); - ~GameCaptureToolbar(); - -public slots: - void on_mode_currentIndexChanged(int idx); - void on_window_currentIndexChanged(int idx); -}; class ImageSourceToolbar : public SourceToolbar { Q_OBJECT @@ -143,36 +16,3 @@ public: public slots: void on_browse_clicked(); }; - -class ColorSourceToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - QColor color; - - void UpdateColor(); - -public: - ColorSourceToolbar(QWidget *parent, OBSSource source); - ~ColorSourceToolbar(); - -public slots: - void on_choose_clicked(); -}; - -class TextSourceToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - QFont font; - QColor color; - -public: - TextSourceToolbar(QWidget *parent, OBSSource source); - ~TextSourceToolbar(); - -public slots: - void on_selectFont_clicked(); - void on_selectColor_clicked(); - void on_text_textChanged(); -}; diff --git a/frontend/components/OBSPreviewScalingComboBox.cpp b/frontend/components/OBSPreviewScalingComboBox.cpp index 7564e1bdb..c1a08fcb6 100644 --- a/frontend/components/OBSPreviewScalingComboBox.cpp +++ b/frontend/components/OBSPreviewScalingComboBox.cpp @@ -15,23 +15,12 @@ along with this program. If not, see . ******************************************************************************/ -#include "preview-controls.hpp" -#include +#include "OBSPreviewScalingComboBox.hpp" -/* Preview Scale Label */ -void OBSPreviewScalingLabel::PreviewScaleChanged(float scale) -{ - previewScale = scale; - UpdateScaleLabel(); -} +#include -void OBSPreviewScalingLabel::UpdateScaleLabel() -{ - float previewScalePercent = floor(100.0f * previewScale); - setText(QString::number(previewScalePercent) + "%"); -} +#include "moc_OBSPreviewScalingComboBox.cpp" -/* Preview Scaling ComboBox */ void OBSPreviewScalingComboBox::PreviewFixedScalingChanged(bool fixed) { if (fixedScaling == fixed) diff --git a/frontend/components/OBSPreviewScalingComboBox.hpp b/frontend/components/OBSPreviewScalingComboBox.hpp index 4078dbea9..73c424369 100644 --- a/frontend/components/OBSPreviewScalingComboBox.hpp +++ b/frontend/components/OBSPreviewScalingComboBox.hpp @@ -17,23 +17,8 @@ #pragma once -#include #include -class OBSPreviewScalingLabel : public QLabel { - Q_OBJECT - -public: - OBSPreviewScalingLabel(QWidget *parent = nullptr) : QLabel(parent) {} - -public slots: - void PreviewScaleChanged(float scale); - -private: - float previewScale = 0.0f; - void UpdateScaleLabel(); -}; - class OBSPreviewScalingComboBox : public QComboBox { Q_OBJECT diff --git a/frontend/components/OBSPreviewScalingLabel.cpp b/frontend/components/OBSPreviewScalingLabel.cpp index 7564e1bdb..580b05836 100644 --- a/frontend/components/OBSPreviewScalingLabel.cpp +++ b/frontend/components/OBSPreviewScalingLabel.cpp @@ -15,10 +15,9 @@ along with this program. If not, see . ******************************************************************************/ -#include "preview-controls.hpp" -#include +#include "OBSPreviewScalingLabel.hpp" +#include "moc_OBSPreviewScalingLabel.cpp" -/* Preview Scale Label */ void OBSPreviewScalingLabel::PreviewScaleChanged(float scale) { previewScale = scale; @@ -30,104 +29,3 @@ void OBSPreviewScalingLabel::UpdateScaleLabel() float previewScalePercent = floor(100.0f * previewScale); setText(QString::number(previewScalePercent) + "%"); } - -/* Preview Scaling ComboBox */ -void OBSPreviewScalingComboBox::PreviewFixedScalingChanged(bool fixed) -{ - if (fixedScaling == fixed) - return; - - fixedScaling = fixed; - UpdateSelection(); -} - -void OBSPreviewScalingComboBox::CanvasResized(uint32_t width, uint32_t height) -{ - SetCanvasSize(width, height); - UpdateCanvasText(); -} - -void OBSPreviewScalingComboBox::OutputResized(uint32_t width, uint32_t height) -{ - SetOutputSize(width, height); - - bool canvasMatchesOutput = output_width == canvas_width && output_height == canvas_height; - - SetScaleOutputEnabled(!canvasMatchesOutput); - UpdateOutputText(); -} - -void OBSPreviewScalingComboBox::PreviewScaleChanged(float scale) -{ - previewScale = scale; - - if (fixedScaling) { - UpdateSelection(); - UpdateAllText(); - } else { - UpdateScaledText(); - } -} - -void OBSPreviewScalingComboBox::SetScaleOutputEnabled(bool show) -{ - if (scaleOutputEnabled == show) - return; - - scaleOutputEnabled = show; - - if (scaleOutputEnabled) { - addItem(QTStr("Basic.MainMenu.Edit.Scale.Output")); - } else { - removeItem(2); - } -} - -void OBSPreviewScalingComboBox::UpdateAllText() -{ - UpdateCanvasText(); - UpdateOutputText(); - UpdateScaledText(); -} - -void OBSPreviewScalingComboBox::UpdateCanvasText() -{ - QString text = QTStr("Basic.MainMenu.Edit.Scale.Canvas"); - text = text.arg(QString::number(canvas_width), QString::number(canvas_height)); - setItemText(1, text); -} - -void OBSPreviewScalingComboBox::UpdateOutputText() -{ - if (scaleOutputEnabled) { - QString text = QTStr("Basic.MainMenu.Edit.Scale.Output"); - text = text.arg(QString::number(output_width), QString::number(output_height)); - setItemText(2, text); - } -} - -void OBSPreviewScalingComboBox::UpdateScaledText() -{ - QString text = QTStr("Basic.MainMenu.Edit.Scale.Manual"); - text = text.arg(QString::number(floor(canvas_width * previewScale)), - QString::number(floor(canvas_height * previewScale))); - setPlaceholderText(text); -} - -void OBSPreviewScalingComboBox::UpdateSelection() -{ - QSignalBlocker sb(this); - float outputScale = float(output_width) / float(canvas_width); - - if (!fixedScaling) { - setCurrentIndex(0); - } else { - if (previewScale == 1.0f) { - setCurrentIndex(1); - } else if (scaleOutputEnabled && (previewScale == outputScale)) { - setCurrentIndex(2); - } else { - setCurrentIndex(-1); - } - } -} diff --git a/frontend/components/OBSPreviewScalingLabel.hpp b/frontend/components/OBSPreviewScalingLabel.hpp index 4078dbea9..82dbf39b8 100644 --- a/frontend/components/OBSPreviewScalingLabel.hpp +++ b/frontend/components/OBSPreviewScalingLabel.hpp @@ -18,7 +18,6 @@ #pragma once #include -#include class OBSPreviewScalingLabel : public QLabel { Q_OBJECT @@ -33,47 +32,3 @@ private: float previewScale = 0.0f; void UpdateScaleLabel(); }; - -class OBSPreviewScalingComboBox : public QComboBox { - Q_OBJECT - -public: - OBSPreviewScalingComboBox(QWidget *parent = nullptr) : QComboBox(parent) {} - - inline void SetCanvasSize(uint32_t width, uint32_t height) - { - canvas_width = width; - canvas_height = height; - }; - inline void SetOutputSize(uint32_t width, uint32_t height) - { - output_width = width; - output_height = height; - }; - void UpdateAllText(); - -public slots: - void PreviewScaleChanged(float scale); - void PreviewFixedScalingChanged(bool fixed); - void CanvasResized(uint32_t width, uint32_t height); - void OutputResized(uint32_t width, uint32_t height); - -private: - uint32_t canvas_width = 0; - uint32_t canvas_height = 0; - - uint32_t output_width = 0; - uint32_t output_height = 0; - - float previewScale = 0.0f; - - bool fixedScaling = false; - - bool scaleOutputEnabled = false; - void SetScaleOutputEnabled(bool show); - - void UpdateCanvasText(); - void UpdateOutputText(); - void UpdateScaledText(); - void UpdateSelection(); -}; diff --git a/frontend/components/SourceToolbar.cpp b/frontend/components/SourceToolbar.cpp index c45d06976..da8675aa6 100644 --- a/frontend/components/SourceToolbar.cpp +++ b/frontend/components/SourceToolbar.cpp @@ -1,31 +1,8 @@ -#include "window-basic-main.hpp" -#include "moc_context-bar-controls.cpp" -#include "obs-app.hpp" +#include "SourceToolbar.hpp" -#include -#include -#include -#include +#include -#include "ui_browser-source-toolbar.h" -#include "ui_device-select-toolbar.h" -#include "ui_game-capture-toolbar.h" -#include "ui_image-source-toolbar.h" -#include "ui_color-source-toolbar.h" -#include "ui_text-source-toolbar.h" - -#ifdef _WIN32 -#define get_os_module(win, mac, linux) obs_get_module(win) -#define get_os_text(mod, win, mac, linux) obs_module_get_locale_text(mod, win) -#elif __APPLE__ -#define get_os_module(win, mac, linux) obs_get_module(mac) -#define get_os_text(mod, win, mac, linux) obs_module_get_locale_text(mod, mac) -#else -#define get_os_module(win, mac, linux) obs_get_module(linux) -#define get_os_text(mod, win, mac, linux) obs_module_get_locale_text(mod, linux) -#endif - -/* ========================================================================= */ +#include "moc_SourceToolbar.cpp" SourceToolbar::SourceToolbar(QWidget *parent, OBSSource source) : QWidget(parent), @@ -81,627 +58,3 @@ void SourceToolbar::SetUndoProperties(obs_source_t *source, bool repeatable) oldData = nullptr; } - -/* ========================================================================= */ - -BrowserToolbar::BrowserToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_BrowserSourceToolbar) -{ - ui->setupUi(this); -} - -BrowserToolbar::~BrowserToolbar() {} - -void BrowserToolbar::on_refresh_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - obs_property_t *p = obs_properties_get(props.get(), "refreshnocache"); - obs_property_button_clicked(p, source.Get()); -} - -/* ========================================================================= */ - -ComboSelectToolbar::ComboSelectToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_DeviceSelectToolbar) -{ - ui->setupUi(this); -} - -ComboSelectToolbar::~ComboSelectToolbar() {} - -static int FillPropertyCombo(QComboBox *c, obs_property_t *p, const std::string &cur_id, bool is_int = false) -{ - size_t count = obs_property_list_item_count(p); - int cur_idx = -1; - - for (size_t i = 0; i < count; i++) { - const char *name = obs_property_list_item_name(p, i); - std::string id; - - if (is_int) { - id = std::to_string(obs_property_list_item_int(p, i)); - } else { - const char *val = obs_property_list_item_string(p, i); - id = val ? val : ""; - } - - if (cur_id == id) - cur_idx = (int)i; - - c->addItem(name, id.c_str()); - } - - return cur_idx; -} - -void UpdateSourceComboToolbarProperties(QComboBox *combo, OBSSource source, obs_properties_t *props, - const char *prop_name, bool is_int) -{ - std::string cur_id; - - OBSDataAutoRelease settings = obs_source_get_settings(source); - if (is_int) { - cur_id = std::to_string(obs_data_get_int(settings, prop_name)); - } else { - cur_id = obs_data_get_string(settings, prop_name); - } - - combo->blockSignals(true); - - obs_property_t *p = obs_properties_get(props, prop_name); - int cur_idx = FillPropertyCombo(combo, p, cur_id, is_int); - - if (cur_idx == -1 || obs_property_list_item_disabled(p, cur_idx)) { - if (cur_idx == -1) { - combo->insertItem(0, QTStr("Basic.Settings.Audio.UnknownAudioDevice")); - cur_idx = 0; - } - - SetComboItemEnabled(combo, cur_idx, false); - } - - combo->setCurrentIndex(cur_idx); - combo->blockSignals(false); -} - -void ComboSelectToolbar::Init() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - UpdateSourceComboToolbarProperties(ui->device, source, props.get(), prop_name, is_int); -} - -void UpdateSourceComboToolbarValue(QComboBox *combo, OBSSource source, int idx, const char *prop_name, bool is_int) -{ - QString id = combo->itemData(idx).toString(); - - OBSDataAutoRelease settings = obs_data_create(); - if (is_int) { - obs_data_set_int(settings, prop_name, id.toInt()); - } else { - obs_data_set_string(settings, prop_name, QT_TO_UTF8(id)); - } - obs_source_update(source, settings); -} - -void ComboSelectToolbar::on_device_currentIndexChanged(int idx) -{ - OBSSource source = GetSource(); - if (idx == -1 || !source) { - return; - } - - SaveOldProperties(source); - UpdateSourceComboToolbarValue(ui->device, source, idx, prop_name, is_int); - SetUndoProperties(source); -} - -AudioCaptureToolbar::AudioCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) {} - -void AudioCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = get_os_module("win-wasapi", "mac-capture", "linux-pulseaudio"); - if (!mod) - return; - - const char *device_str = get_os_text(mod, "Device", "CoreAudio.Device", "Device"); - ui->deviceLabel->setText(device_str); - - prop_name = "device_id"; - - ComboSelectToolbar::Init(); -} - -WindowCaptureToolbar::WindowCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) {} - -void WindowCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = get_os_module("win-capture", "mac-capture", "linux-capture"); - if (!mod) - return; - - const char *device_str = get_os_text(mod, "WindowCapture.Window", "WindowUtils.Window", "Window"); - ui->deviceLabel->setText(device_str); - -#if !defined(_WIN32) && !defined(__APPLE__) //linux - prop_name = "capture_window"; -#else - prop_name = "window"; -#endif - -#ifdef __APPLE__ - is_int = true; -#endif - - ComboSelectToolbar::Init(); -} - -ApplicationAudioCaptureToolbar::ApplicationAudioCaptureToolbar(QWidget *parent, OBSSource source) - : ComboSelectToolbar(parent, source) -{ -} - -void ApplicationAudioCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = obs_get_module("win-wasapi"); - const char *device_str = obs_module_get_locale_text(mod, "Window"); - ui->deviceLabel->setText(device_str); - - prop_name = "window"; - - ComboSelectToolbar::Init(); -} - -DisplayCaptureToolbar::DisplayCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) {} - -void DisplayCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = get_os_module("win-capture", "mac-capture", "linux-capture"); - if (!mod) - return; - - const char *device_str = get_os_text(mod, "Monitor", "DisplayCapture.Display", "Screen"); - ui->deviceLabel->setText(device_str); - -#ifdef _WIN32 - prop_name = "monitor_id"; -#elif __APPLE__ - prop_name = "display_uuid"; -#else - is_int = true; - prop_name = "screen"; -#endif - - ComboSelectToolbar::Init(); -} - -/* ========================================================================= */ - -DeviceCaptureToolbar::DeviceCaptureToolbar(QWidget *parent, OBSSource source) - : QWidget(parent), - weakSource(OBSGetWeakRef(source)), - ui(new Ui_DeviceSelectToolbar) -{ - ui->setupUi(this); - - delete ui->deviceLabel; - delete ui->device; - ui->deviceLabel = nullptr; - ui->device = nullptr; - - OBSDataAutoRelease settings = obs_source_get_settings(source); - active = obs_data_get_bool(settings, "active"); - - obs_module_t *mod = obs_get_module("win-dshow"); - if (!mod) - return; - - activateText = obs_module_get_locale_text(mod, "Activate"); - deactivateText = obs_module_get_locale_text(mod, "Deactivate"); - - ui->activateButton->setText(active ? deactivateText : activateText); -} - -DeviceCaptureToolbar::~DeviceCaptureToolbar() {} - -void DeviceCaptureToolbar::on_activateButton_clicked() -{ - OBSSource source = OBSGetStrongRef(weakSource); - if (!source) { - return; - } - - OBSDataAutoRelease settings = obs_source_get_settings(source); - bool now_active = obs_data_get_bool(settings, "active"); - - bool desyncedSetting = now_active != active; - - active = !active; - - const char *text = active ? deactivateText : activateText; - ui->activateButton->setText(text); - - if (desyncedSetting) { - return; - } - - calldata_t cd = {}; - calldata_set_bool(&cd, "active", active); - proc_handler_t *ph = obs_source_get_proc_handler(source); - proc_handler_call(ph, "activate", &cd); - calldata_free(&cd); -} - -/* ========================================================================= */ - -GameCaptureToolbar::GameCaptureToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_GameCaptureToolbar) -{ - obs_property_t *p; - int cur_idx; - - ui->setupUi(this); - - obs_module_t *mod = obs_get_module("win-capture"); - if (!mod) - return; - - ui->modeLabel->setText(obs_module_get_locale_text(mod, "Mode")); - ui->windowLabel->setText(obs_module_get_locale_text(mod, "WindowCapture.Window")); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - std::string cur_mode = obs_data_get_string(settings, "capture_mode"); - std::string cur_window = obs_data_get_string(settings, "window"); - - ui->mode->blockSignals(true); - p = obs_properties_get(props.get(), "capture_mode"); - cur_idx = FillPropertyCombo(ui->mode, p, cur_mode); - ui->mode->setCurrentIndex(cur_idx); - ui->mode->blockSignals(false); - - ui->window->blockSignals(true); - p = obs_properties_get(props.get(), "window"); - cur_idx = FillPropertyCombo(ui->window, p, cur_window); - ui->window->setCurrentIndex(cur_idx); - ui->window->blockSignals(false); - - if (cur_idx != -1 && obs_property_list_item_disabled(p, cur_idx)) { - SetComboItemEnabled(ui->window, cur_idx, false); - } - - UpdateWindowVisibility(); -} - -GameCaptureToolbar::~GameCaptureToolbar() {} - -void GameCaptureToolbar::UpdateWindowVisibility() -{ - QString mode = ui->mode->currentData().toString(); - bool is_window = (mode == "window"); - ui->windowLabel->setVisible(is_window); - ui->window->setVisible(is_window); -} - -void GameCaptureToolbar::on_mode_currentIndexChanged(int idx) -{ - OBSSource source = GetSource(); - if (idx == -1 || !source) { - return; - } - - QString id = ui->mode->itemData(idx).toString(); - - SaveOldProperties(source); - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_string(settings, "capture_mode", QT_TO_UTF8(id)); - obs_source_update(source, settings); - SetUndoProperties(source); - - UpdateWindowVisibility(); -} - -void GameCaptureToolbar::on_window_currentIndexChanged(int idx) -{ - OBSSource source = GetSource(); - if (idx == -1 || !source) { - return; - } - - QString id = ui->window->itemData(idx).toString(); - - SaveOldProperties(source); - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_string(settings, "window", QT_TO_UTF8(id)); - obs_source_update(source, settings); - SetUndoProperties(source); -} - -/* ========================================================================= */ - -ImageSourceToolbar::ImageSourceToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_ImageSourceToolbar) -{ - ui->setupUi(this); - - obs_module_t *mod = obs_get_module("image-source"); - ui->pathLabel->setText(obs_module_get_locale_text(mod, "File")); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - std::string file = obs_data_get_string(settings, "file"); - - ui->path->setText(file.c_str()); -} - -ImageSourceToolbar::~ImageSourceToolbar() {} - -void ImageSourceToolbar::on_browse_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - obs_property_t *p = obs_properties_get(props.get(), "file"); - const char *desc = obs_property_description(p); - const char *filter = obs_property_path_filter(p); - const char *default_path = obs_property_path_default_path(p); - - QString startDir = ui->path->text(); - if (startDir.isEmpty()) - startDir = default_path; - - QString path = OpenFile(this, desc, startDir, filter); - if (path.isEmpty()) { - return; - } - - ui->path->setText(path); - - SaveOldProperties(source); - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_string(settings, "file", QT_TO_UTF8(path)); - obs_source_update(source, settings); - SetUndoProperties(source); -} - -/* ========================================================================= */ - -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); -} - -ColorSourceToolbar::ColorSourceToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_ColorSourceToolbar) -{ - ui->setupUi(this); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - unsigned int val = (unsigned int)obs_data_get_int(settings, "color"); - - color = color_from_int(val); - UpdateColor(); -} - -ColorSourceToolbar::~ColorSourceToolbar() {} - -void ColorSourceToolbar::UpdateColor() -{ - QPalette palette = QPalette(color); - ui->color->setFrameStyle(QFrame::Sunken | QFrame::Panel); - ui->color->setText(color.name(QColor::HexRgb)); - ui->color->setPalette(palette); - ui->color->setStyleSheet(QString("background-color :%1; color: %2;") - .arg(palette.color(QPalette::Window).name(QColor::HexRgb)) - .arg(palette.color(QPalette::WindowText).name(QColor::HexRgb))); - ui->color->setAutoFillBackground(true); - ui->color->setAlignment(Qt::AlignCenter); -} - -void ColorSourceToolbar::on_choose_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - obs_property_t *p = obs_properties_get(props.get(), "color"); - const char *desc = obs_property_description(p); - - QColorDialog::ColorDialogOptions options; - - options |= QColorDialog::ShowAlphaChannel; -#ifdef __linux__ - // TODO: Revisit hang on Ubuntu with native dialog - options |= QColorDialog::DontUseNativeDialog; -#endif - - QColor newColor = QColorDialog::getColor(color, this, desc, options); - if (!newColor.isValid()) { - return; - } - - color = newColor; - UpdateColor(); - - SaveOldProperties(source); - - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_int(settings, "color", color_to_int(color)); - obs_source_update(source, settings); - - SetUndoProperties(source); -} - -/* ========================================================================= */ - -extern void MakeQFont(obs_data_t *font_obj, QFont &font, bool limit = false); - -TextSourceToolbar::TextSourceToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_TextSourceToolbar) -{ - ui->setupUi(this); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - - const char *id = obs_source_get_unversioned_id(source); - bool ft2 = strcmp(id, "text_ft2_source") == 0; - bool read_from_file = obs_data_get_bool(settings, ft2 ? "from_file" : "read_from_file"); - - OBSDataAutoRelease font_obj = obs_data_get_obj(settings, "font"); - MakeQFont(font_obj, font); - - // Use "color1" if it's a freetype source and "color" elsewise - unsigned int val = (unsigned int)obs_data_get_int( - settings, (strncmp(obs_source_get_id(source), "text_ft2_source", 15) == 0) ? "color1" : "color"); - - color = color_from_int(val); - - const char *text = obs_data_get_string(settings, "text"); - - bool single_line = !read_from_file && (!text || (strchr(text, '\n') == nullptr)); - ui->emptySpace->setVisible(!single_line); - ui->text->setVisible(single_line); - if (single_line) - ui->text->setText(text); -} - -TextSourceToolbar::~TextSourceToolbar() {} - -void TextSourceToolbar::on_selectFont_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - QFontDialog::FontDialogOptions options; - uint32_t flags; - bool success; - -#ifndef _WIN32 - options = QFontDialog::DontUseNativeDialog; -#endif - - font = QFontDialog::getFont(&success, font, this, QTStr("Basic.PropertiesWindow.SelectFont.WindowTitle"), - options); - if (!success) { - return; - } - - OBSDataAutoRelease font_obj = obs_data_create(); - - obs_data_set_string(font_obj, "face", QT_TO_UTF8(font.family())); - obs_data_set_string(font_obj, "style", QT_TO_UTF8(font.styleName())); - obs_data_set_int(font_obj, "size", font.pointSize()); - flags = font.bold() ? OBS_FONT_BOLD : 0; - flags |= font.italic() ? OBS_FONT_ITALIC : 0; - flags |= font.underline() ? OBS_FONT_UNDERLINE : 0; - flags |= font.strikeOut() ? OBS_FONT_STRIKEOUT : 0; - obs_data_set_int(font_obj, "flags", flags); - - SaveOldProperties(source); - - OBSDataAutoRelease settings = obs_data_create(); - - obs_data_set_obj(settings, "font", font_obj); - - obs_source_update(source, settings); - - SetUndoProperties(source); -} - -void TextSourceToolbar::on_selectColor_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - bool freetype = strncmp(obs_source_get_id(source), "text_ft2_source", 15) == 0; - - obs_property_t *p = obs_properties_get(props.get(), freetype ? "color1" : "color"); - - const char *desc = obs_property_description(p); - - QColorDialog::ColorDialogOptions options; - - options |= QColorDialog::ShowAlphaChannel; -#ifdef __linux__ - // TODO: Revisit hang on Ubuntu with native dialog - options |= QColorDialog::DontUseNativeDialog; -#endif - - QColor newColor = QColorDialog::getColor(color, this, desc, options); - if (!newColor.isValid()) { - return; - } - - color = newColor; - - SaveOldProperties(source); - - OBSDataAutoRelease settings = obs_data_create(); - if (freetype) { - obs_data_set_int(settings, "color1", color_to_int(color)); - obs_data_set_int(settings, "color2", color_to_int(color)); - } else { - obs_data_set_int(settings, "color", color_to_int(color)); - } - obs_source_update(source, settings); - - SetUndoProperties(source); -} - -void TextSourceToolbar::on_text_textChanged() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - std::string newText = QT_TO_UTF8(ui->text->text()); - OBSDataAutoRelease settings = obs_source_get_settings(source); - if (newText == obs_data_get_string(settings, "text")) { - return; - } - SaveOldProperties(source); - - obs_data_set_string(settings, "text", newText.c_str()); - obs_source_update(source, nullptr); - - SetUndoProperties(source, true); -} diff --git a/frontend/components/SourceToolbar.hpp b/frontend/components/SourceToolbar.hpp index acf88a5fb..8e3f9b5f7 100644 --- a/frontend/components/SourceToolbar.hpp +++ b/frontend/components/SourceToolbar.hpp @@ -1,15 +1,8 @@ #pragma once -#include #include -#include -class Ui_BrowserSourceToolbar; -class Ui_DeviceSelectToolbar; -class Ui_GameCaptureToolbar; -class Ui_ImageSourceToolbar; -class Ui_ColorSourceToolbar; -class Ui_TextSourceToolbar; +#include class SourceToolbar : public QWidget { Q_OBJECT @@ -34,145 +27,3 @@ public: public slots: virtual void Update() {} }; - -class BrowserToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - -public: - BrowserToolbar(QWidget *parent, OBSSource source); - ~BrowserToolbar(); - -public slots: - void on_refresh_clicked(); -}; - -class ComboSelectToolbar : public SourceToolbar { - Q_OBJECT - -protected: - std::unique_ptr ui; - const char *prop_name; - bool is_int = false; - -public: - ComboSelectToolbar(QWidget *parent, OBSSource source); - ~ComboSelectToolbar(); - virtual void Init(); - -public slots: - void on_device_currentIndexChanged(int idx); -}; - -class AudioCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - AudioCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class WindowCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - WindowCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class ApplicationAudioCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - ApplicationAudioCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class DisplayCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - DisplayCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class DeviceCaptureToolbar : public QWidget { - Q_OBJECT - - OBSWeakSource weakSource; - - std::unique_ptr ui; - const char *activateText; - const char *deactivateText; - bool active; - -public: - DeviceCaptureToolbar(QWidget *parent, OBSSource source); - ~DeviceCaptureToolbar(); - -public slots: - void on_activateButton_clicked(); -}; - -class GameCaptureToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - - void UpdateWindowVisibility(); - -public: - GameCaptureToolbar(QWidget *parent, OBSSource source); - ~GameCaptureToolbar(); - -public slots: - void on_mode_currentIndexChanged(int idx); - void on_window_currentIndexChanged(int idx); -}; - -class ImageSourceToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - -public: - ImageSourceToolbar(QWidget *parent, OBSSource source); - ~ImageSourceToolbar(); - -public slots: - void on_browse_clicked(); -}; - -class ColorSourceToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - QColor color; - - void UpdateColor(); - -public: - ColorSourceToolbar(QWidget *parent, OBSSource source); - ~ColorSourceToolbar(); - -public slots: - void on_choose_clicked(); -}; - -class TextSourceToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - QFont font; - QColor color; - -public: - TextSourceToolbar(QWidget *parent, OBSSource source); - ~TextSourceToolbar(); - -public slots: - void on_selectFont_clicked(); - void on_selectColor_clicked(); - void on_text_textChanged(); -}; diff --git a/frontend/components/SourceTree.cpp b/frontend/components/SourceTree.cpp index a0242e3cd..0325b59d8 100644 --- a/frontend/components/SourceTree.cpp +++ b/frontend/components/SourceTree.cpp @@ -1,26 +1,11 @@ -#include "window-basic-main.hpp" -#include "obs-app.hpp" -#include "source-tree.hpp" -#include "platform.hpp" -#include "source-label.hpp" +#include "SourceTree.hpp" +#include "SourceTreeDelegate.hpp" -#include -#include -#include +#include -#include +#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include +#include "moc_SourceTree.cpp" static inline OBSScene GetCurrentScene() { @@ -28,610 +13,6 @@ static inline OBSScene GetCurrentScene() return main->GetCurrentScene(); } -/* ========================================================================= */ - -SourceTreeItem::SourceTreeItem(SourceTree *tree_, OBSSceneItem sceneitem_) : tree(tree_), sceneitem(sceneitem_) -{ - setAttribute(Qt::WA_TranslucentBackground); - setMouseTracking(true); - - obs_source_t *source = obs_sceneitem_get_source(sceneitem); - const char *name = obs_source_get_name(source); - - OBSDataAutoRelease privData = obs_sceneitem_get_private_settings(sceneitem); - int preset = obs_data_get_int(privData, "color-preset"); - - if (preset == 1) { - const char *color = obs_data_get_string(privData, "color"); - std::string col = "background: "; - col += color; - setStyleSheet(col.c_str()); - } else if (preset > 1) { - setStyleSheet(""); - setProperty("bgColor", preset - 1); - } else { - setStyleSheet("background: none"); - } - - OBSBasic *main = reinterpret_cast(App()->GetMainWindow()); - const char *id = obs_source_get_id(source); - - bool sourceVisible = obs_sceneitem_visible(sceneitem); - - if (tree->iconsVisible) { - QIcon icon; - - if (strcmp(id, "scene") == 0) - icon = main->GetSceneIcon(); - else if (strcmp(id, "group") == 0) - icon = main->GetGroupIcon(); - else - icon = main->GetSourceIcon(id); - - QPixmap pixmap = icon.pixmap(QSize(16, 16)); - - iconLabel = new QLabel(); - iconLabel->setPixmap(pixmap); - iconLabel->setEnabled(sourceVisible); - iconLabel->setStyleSheet("background: none"); - iconLabel->setProperty("class", "source-icon"); - } - - vis = new QCheckBox(); - vis->setProperty("class", "checkbox-icon indicator-visibility"); - vis->setChecked(sourceVisible); - vis->setAccessibleName(QTStr("Basic.Main.Sources.Visibility")); - vis->setAccessibleDescription(QTStr("Basic.Main.Sources.VisibilityDescription").arg(name)); - - lock = new QCheckBox(); - lock->setProperty("class", "checkbox-icon indicator-lock"); - lock->setChecked(obs_sceneitem_locked(sceneitem)); - lock->setAccessibleName(QTStr("Basic.Main.Sources.Lock")); - lock->setAccessibleDescription(QTStr("Basic.Main.Sources.LockDescription").arg(name)); - - label = new OBSSourceLabel(source); - label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); - label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); - label->setAttribute(Qt::WA_TranslucentBackground); - label->setEnabled(sourceVisible); - -#ifdef __APPLE__ - vis->setAttribute(Qt::WA_LayoutUsesWidgetRect); - lock->setAttribute(Qt::WA_LayoutUsesWidgetRect); -#endif - - boxLayout = new QHBoxLayout(); - - boxLayout->setContentsMargins(0, 0, 0, 0); - boxLayout->setSpacing(0); - if (iconLabel) { - boxLayout->addWidget(iconLabel); - boxLayout->addSpacing(2); - } - boxLayout->addWidget(label); - boxLayout->addWidget(vis); - boxLayout->addWidget(lock); -#ifdef __APPLE__ - /* Hack: Fixes a bug where scrollbars would be above the lock icon */ - boxLayout->addSpacing(16); -#endif - - Update(false); - - setLayout(boxLayout); - - /* --------------------------------------------------------- */ - - auto setItemVisible = [this](bool val) { - obs_scene_t *scene = obs_sceneitem_get_scene(sceneitem); - obs_source_t *scenesource = obs_scene_get_source(scene); - int64_t id = obs_sceneitem_get_id(sceneitem); - const char *name = obs_source_get_name(scenesource); - const char *uuid = obs_source_get_uuid(scenesource); - obs_source_t *source = obs_sceneitem_get_source(sceneitem); - - auto undo_redo = [](const std::string &uuid, int64_t id, bool val) { - OBSSourceAutoRelease s = obs_get_source_by_uuid(uuid.c_str()); - obs_scene_t *sc = obs_group_or_scene_from_source(s); - obs_sceneitem_t *si = obs_scene_find_sceneitem_by_id(sc, id); - if (si) - obs_sceneitem_set_visible(si, val); - }; - - QString str = QTStr(val ? "Undo.ShowSceneItem" : "Undo.HideSceneItem"); - - OBSBasic *main = OBSBasic::Get(); - main->undo_s.add_action(str.arg(obs_source_get_name(source), name), - std::bind(undo_redo, std::placeholders::_1, id, !val), - std::bind(undo_redo, std::placeholders::_1, id, val), uuid, uuid); - - QSignalBlocker sourcesSignalBlocker(this); - obs_sceneitem_set_visible(sceneitem, val); - }; - - auto setItemLocked = [this](bool checked) { - QSignalBlocker sourcesSignalBlocker(this); - obs_sceneitem_set_locked(sceneitem, checked); - }; - - connect(vis, &QAbstractButton::clicked, setItemVisible); - connect(lock, &QAbstractButton::clicked, setItemLocked); -} - -void SourceTreeItem::paintEvent(QPaintEvent *event) -{ - QStyleOption opt; - opt.initFrom(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); - - QWidget::paintEvent(event); -} - -void SourceTreeItem::DisconnectSignals() -{ - sigs.clear(); -} - -void SourceTreeItem::Clear() -{ - DisconnectSignals(); - sceneitem = nullptr; -} - -void SourceTreeItem::ReconnectSignals() -{ - if (!sceneitem) - return; - - DisconnectSignals(); - - /* --------------------------------------------------------- */ - - auto removeItem = [](void *data, calldata_t *cd) { - SourceTreeItem *this_ = reinterpret_cast(data); - obs_sceneitem_t *curItem = (obs_sceneitem_t *)calldata_ptr(cd, "item"); - obs_scene_t *curScene = (obs_scene_t *)calldata_ptr(cd, "scene"); - - if (curItem == this_->sceneitem) { - QMetaObject::invokeMethod(this_->tree, "Remove", Q_ARG(OBSSceneItem, curItem), - Q_ARG(OBSScene, curScene)); - curItem = nullptr; - } - if (!curItem) - QMetaObject::invokeMethod(this_, "Clear"); - }; - - auto itemVisible = [](void *data, calldata_t *cd) { - SourceTreeItem *this_ = reinterpret_cast(data); - obs_sceneitem_t *curItem = (obs_sceneitem_t *)calldata_ptr(cd, "item"); - bool visible = calldata_bool(cd, "visible"); - - if (curItem == this_->sceneitem) - QMetaObject::invokeMethod(this_, "VisibilityChanged", Q_ARG(bool, visible)); - }; - - auto itemLocked = [](void *data, calldata_t *cd) { - SourceTreeItem *this_ = reinterpret_cast(data); - obs_sceneitem_t *curItem = (obs_sceneitem_t *)calldata_ptr(cd, "item"); - bool locked = calldata_bool(cd, "locked"); - - if (curItem == this_->sceneitem) - QMetaObject::invokeMethod(this_, "LockedChanged", Q_ARG(bool, locked)); - }; - - auto itemSelect = [](void *data, calldata_t *cd) { - SourceTreeItem *this_ = reinterpret_cast(data); - obs_sceneitem_t *curItem = (obs_sceneitem_t *)calldata_ptr(cd, "item"); - - if (curItem == this_->sceneitem) - QMetaObject::invokeMethod(this_, "Select"); - }; - - auto itemDeselect = [](void *data, calldata_t *cd) { - SourceTreeItem *this_ = reinterpret_cast(data); - obs_sceneitem_t *curItem = (obs_sceneitem_t *)calldata_ptr(cd, "item"); - - if (curItem == this_->sceneitem) - QMetaObject::invokeMethod(this_, "Deselect"); - }; - - auto reorderGroup = [](void *data, calldata_t *) { - SourceTreeItem *this_ = reinterpret_cast(data); - QMetaObject::invokeMethod(this_->tree, "ReorderItems"); - }; - - obs_scene_t *scene = obs_sceneitem_get_scene(sceneitem); - obs_source_t *sceneSource = obs_scene_get_source(scene); - signal_handler_t *signal = obs_source_get_signal_handler(sceneSource); - - sigs.emplace_back(signal, "remove", removeItem, this); - sigs.emplace_back(signal, "item_remove", removeItem, this); - sigs.emplace_back(signal, "item_visible", itemVisible, this); - sigs.emplace_back(signal, "item_locked", itemLocked, this); - sigs.emplace_back(signal, "item_select", itemSelect, this); - sigs.emplace_back(signal, "item_deselect", itemDeselect, this); - - if (obs_sceneitem_is_group(sceneitem)) { - obs_source_t *source = obs_sceneitem_get_source(sceneitem); - signal = obs_source_get_signal_handler(source); - - sigs.emplace_back(signal, "reorder", reorderGroup, this); - } - - /* --------------------------------------------------------- */ - - auto removeSource = [](void *data, calldata_t *) { - SourceTreeItem *this_ = reinterpret_cast(data); - this_->DisconnectSignals(); - this_->sceneitem = nullptr; - QMetaObject::invokeMethod(this_->tree, "RefreshItems"); - }; - - obs_source_t *source = obs_sceneitem_get_source(sceneitem); - signal = obs_source_get_signal_handler(source); - sigs.emplace_back(signal, "remove", removeSource, this); -} - -void SourceTreeItem::mouseDoubleClickEvent(QMouseEvent *event) -{ - QWidget::mouseDoubleClickEvent(event); - - if (expand) { - expand->setChecked(!expand->isChecked()); - } else { - obs_source_t *source = obs_sceneitem_get_source(sceneitem); - OBSBasic *main = reinterpret_cast(App()->GetMainWindow()); - if (obs_source_configurable(source)) { - main->CreatePropertiesWindow(source); - } - } -} - -void SourceTreeItem::enterEvent(QEnterEvent *event) -{ - QWidget::enterEvent(event); - - OBSBasicPreview *preview = OBSBasicPreview::Get(); - - std::lock_guard lock(preview->selectMutex); - preview->hoveredPreviewItems.clear(); - preview->hoveredPreviewItems.push_back(sceneitem); -} - -void SourceTreeItem::leaveEvent(QEvent *event) -{ - QWidget::leaveEvent(event); - - OBSBasicPreview *preview = OBSBasicPreview::Get(); - - std::lock_guard lock(preview->selectMutex); - preview->hoveredPreviewItems.clear(); -} - -bool SourceTreeItem::IsEditing() -{ - return editor != nullptr; -} - -void SourceTreeItem::EnterEditMode() -{ - setFocusPolicy(Qt::StrongFocus); - int index = boxLayout->indexOf(label); - boxLayout->removeWidget(label); - editor = new QLineEdit(label->text()); - editor->setStyleSheet("background: none"); - editor->selectAll(); - editor->installEventFilter(this); - boxLayout->insertWidget(index, editor); - setFocusProxy(editor); -} - -void SourceTreeItem::ExitEditMode(bool save) -{ - ExitEditModeInternal(save); - - if (tree->undoSceneData) { - OBSBasic *main = OBSBasic::Get(); - main->undo_s.pop_disabled(); - - OBSData redoSceneData = main->BackupScene(GetCurrentScene()); - - QString text = QTStr("Undo.GroupItems").arg(newName.c_str()); - main->CreateSceneUndoRedoAction(text, tree->undoSceneData, redoSceneData); - - tree->undoSceneData = nullptr; - } -} - -void SourceTreeItem::ExitEditModeInternal(bool save) -{ - if (!editor) { - return; - } - - OBSBasic *main = reinterpret_cast(App()->GetMainWindow()); - OBSScene scene = main->GetCurrentScene(); - - newName = QT_TO_UTF8(editor->text()); - - setFocusProxy(nullptr); - int index = boxLayout->indexOf(editor); - boxLayout->removeWidget(editor); - delete editor; - editor = nullptr; - setFocusPolicy(Qt::NoFocus); - boxLayout->insertWidget(index, label); - setFocus(); - - /* ----------------------------------------- */ - /* check for empty string */ - - if (!save) - return; - - if (newName.empty()) { - OBSMessageBox::information(main, QTStr("NoNameEntered.Title"), QTStr("NoNameEntered.Text")); - return; - } - - /* ----------------------------------------- */ - /* Check for same name */ - - obs_source_t *source = obs_sceneitem_get_source(sceneitem); - if (newName == obs_source_get_name(source)) - return; - - /* ----------------------------------------- */ - /* check for existing source */ - - OBSSourceAutoRelease existingSource = obs_get_source_by_name(newName.c_str()); - bool exists = !!existingSource; - - if (exists) { - OBSMessageBox::information(main, QTStr("NameExists.Title"), QTStr("NameExists.Text")); - return; - } - - /* ----------------------------------------- */ - /* rename */ - - QSignalBlocker sourcesSignalBlocker(this); - std::string prevName(obs_source_get_name(source)); - std::string scene_uuid = obs_source_get_uuid(main->GetCurrentSceneSource()); - auto undo = [scene_uuid, prevName, main](const std::string &data) { - OBSSourceAutoRelease source = obs_get_source_by_uuid(data.c_str()); - obs_source_set_name(source, prevName.c_str()); - - OBSSourceAutoRelease scene_source = obs_get_source_by_uuid(scene_uuid.c_str()); - main->SetCurrentScene(scene_source.Get(), true); - }; - - std::string editedName = newName; - - auto redo = [scene_uuid, main, editedName](const std::string &data) { - OBSSourceAutoRelease source = obs_get_source_by_uuid(data.c_str()); - obs_source_set_name(source, editedName.c_str()); - - OBSSourceAutoRelease scene_source = obs_get_source_by_uuid(scene_uuid.c_str()); - main->SetCurrentScene(scene_source.Get(), true); - }; - - const char *uuid = obs_source_get_uuid(source); - main->undo_s.add_action(QTStr("Undo.Rename").arg(newName.c_str()), undo, redo, uuid, uuid); - - obs_source_set_name(source, newName.c_str()); -} - -bool SourceTreeItem::eventFilter(QObject *object, QEvent *event) -{ - if (editor != object) - return false; - - if (LineEditCanceled(event)) { - QMetaObject::invokeMethod(this, "ExitEditMode", Qt::QueuedConnection, Q_ARG(bool, false)); - return true; - } - if (LineEditChanged(event)) { - QMetaObject::invokeMethod(this, "ExitEditMode", Qt::QueuedConnection, Q_ARG(bool, true)); - return true; - } - - return false; -} - -void SourceTreeItem::VisibilityChanged(bool visible) -{ - if (iconLabel) { - iconLabel->setEnabled(visible); - } - label->setEnabled(visible); - vis->setChecked(visible); -} - -void SourceTreeItem::LockedChanged(bool locked) -{ - lock->setChecked(locked); - OBSBasic::Get()->UpdateEditMenu(); -} - -void SourceTreeItem::Update(bool force) -{ - OBSScene scene = GetCurrentScene(); - obs_scene_t *itemScene = obs_sceneitem_get_scene(sceneitem); - - Type newType; - - /* ------------------------------------------------- */ - /* if it's a group item, insert group checkbox */ - - if (obs_sceneitem_is_group(sceneitem)) { - newType = Type::Group; - - /* ------------------------------------------------- */ - /* if it's a group sub-item */ - - } else if (itemScene != scene) { - newType = Type::SubItem; - - /* ------------------------------------------------- */ - /* if it's a regular item */ - - } else { - newType = Type::Item; - } - - /* ------------------------------------------------- */ - - if (!force && newType == type) { - return; - } - - /* ------------------------------------------------- */ - - ReconnectSignals(); - - if (spacer) { - boxLayout->removeItem(spacer); - delete spacer; - spacer = nullptr; - } - - if (type == Type::Group) { - boxLayout->removeWidget(expand); - expand->deleteLater(); - expand = nullptr; - } - - type = newType; - - if (type == Type::SubItem) { - spacer = new QSpacerItem(16, 1); - boxLayout->insertItem(0, spacer); - - } else if (type == Type::Group) { - expand = new QCheckBox(); - expand->setProperty("class", "checkbox-icon indicator-expand"); -#ifdef __APPLE__ - expand->setAttribute(Qt::WA_LayoutUsesWidgetRect); -#endif - boxLayout->insertWidget(0, expand); - - OBSDataAutoRelease data = obs_sceneitem_get_private_settings(sceneitem); - expand->blockSignals(true); - expand->setChecked(obs_data_get_bool(data, "collapsed")); - expand->blockSignals(false); - - connect(expand, &QPushButton::toggled, this, &SourceTreeItem::ExpandClicked); - - } else { - spacer = new QSpacerItem(3, 1); - boxLayout->insertItem(0, spacer); - } -} - -void SourceTreeItem::ExpandClicked(bool checked) -{ - OBSDataAutoRelease data = obs_sceneitem_get_private_settings(sceneitem); - - obs_data_set_bool(data, "collapsed", checked); - - if (!checked) - tree->GetStm()->ExpandGroup(sceneitem); - else - tree->GetStm()->CollapseGroup(sceneitem); -} - -void SourceTreeItem::Select() -{ - tree->SelectItem(sceneitem, true); - OBSBasic::Get()->UpdateContextBarDeferred(); - OBSBasic::Get()->UpdateEditMenu(); -} - -void SourceTreeItem::Deselect() -{ - tree->SelectItem(sceneitem, false); - OBSBasic::Get()->UpdateContextBarDeferred(); - OBSBasic::Get()->UpdateEditMenu(); -} - -/* ========================================================================= */ - -void SourceTreeModel::OBSFrontendEvent(enum obs_frontend_event event, void *ptr) -{ - SourceTreeModel *stm = reinterpret_cast(ptr); - - switch (event) { - case OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED: - stm->SceneChanged(); - break; - case OBS_FRONTEND_EVENT_EXIT: - stm->Clear(); - obs_frontend_remove_event_callback(OBSFrontendEvent, stm); - break; - case OBS_FRONTEND_EVENT_SCENE_COLLECTION_CLEANUP: - stm->Clear(); - break; - default: - break; - } -} - -void SourceTreeModel::Clear() -{ - beginResetModel(); - items.clear(); - endResetModel(); - - hasGroups = false; -} - -static bool enumItem(obs_scene_t *, obs_sceneitem_t *item, void *ptr) -{ - QVector &items = *reinterpret_cast *>(ptr); - - obs_source_t *src = obs_sceneitem_get_source(item); - if (obs_source_removed(src)) { - return true; - } - - if (obs_sceneitem_is_group(item)) { - OBSDataAutoRelease data = obs_sceneitem_get_private_settings(item); - - bool collapse = obs_data_get_bool(data, "collapsed"); - if (!collapse) { - obs_scene_t *scene = obs_sceneitem_group_get_scene(item); - - obs_scene_enum_items(scene, enumItem, &items); - } - } - - items.insert(0, item); - return true; -} - -void SourceTreeModel::SceneChanged() -{ - OBSScene scene = GetCurrentScene(); - - beginResetModel(); - items.clear(); - obs_scene_enum_items(scene, enumItem, &items); - endResetModel(); - - UpdateGroupState(false); - st->ResetWidgets(); - - for (int i = 0; i < items.count(); i++) { - bool select = obs_sceneitem_selected(items[i]); - QModelIndex index = createIndex(i, 0); - - st->selectionModel()->select(index, - select ? QItemSelectionModel::Select : QItemSelectionModel::Deselect); - } -} - /* moves a scene item index (blame linux distros for using older Qt builds) */ static inline void MoveItem(QVector &items, int oldIdx, int newIdx) { @@ -640,347 +21,6 @@ static inline void MoveItem(QVector &items, int oldIdx, int newIdx items.insert(newIdx, item); } -/* reorders list optimally with model reorder funcs */ -void SourceTreeModel::ReorderItems() -{ - OBSScene scene = GetCurrentScene(); - - QVector newitems; - obs_scene_enum_items(scene, enumItem, &newitems); - - /* if item list has changed size, do full reset */ - if (newitems.count() != items.count()) { - SceneChanged(); - return; - } - - for (;;) { - int idx1Old = 0; - int idx1New = 0; - int count; - int i; - - /* find first starting changed item index */ - for (i = 0; i < newitems.count(); i++) { - obs_sceneitem_t *oldItem = items[i]; - obs_sceneitem_t *newItem = newitems[i]; - if (oldItem != newItem) { - idx1Old = i; - break; - } - } - - /* if everything is the same, break */ - if (i == newitems.count()) { - break; - } - - /* find new starting index */ - for (i = idx1Old + 1; i < newitems.count(); i++) { - obs_sceneitem_t *oldItem = items[idx1Old]; - obs_sceneitem_t *newItem = newitems[i]; - - if (oldItem == newItem) { - idx1New = i; - break; - } - } - - /* if item could not be found, do full reset */ - if (i == newitems.count()) { - SceneChanged(); - return; - } - - /* get move count */ - for (count = 1; (idx1New + count) < newitems.count(); count++) { - int oldIdx = idx1Old + count; - int newIdx = idx1New + count; - - obs_sceneitem_t *oldItem = items[oldIdx]; - obs_sceneitem_t *newItem = newitems[newIdx]; - - if (oldItem != newItem) { - break; - } - } - - /* move items */ - beginMoveRows(QModelIndex(), idx1Old, idx1Old + count - 1, QModelIndex(), idx1New + count); - for (i = 0; i < count; i++) { - int to = idx1New + count; - if (to > idx1Old) - to--; - MoveItem(items, idx1Old, to); - } - endMoveRows(); - } -} - -void SourceTreeModel::Add(obs_sceneitem_t *item) -{ - if (obs_sceneitem_is_group(item)) { - SceneChanged(); - } else { - beginInsertRows(QModelIndex(), 0, 0); - items.insert(0, item); - endInsertRows(); - - st->UpdateWidget(createIndex(0, 0, nullptr), item); - } -} - -void SourceTreeModel::Remove(obs_sceneitem_t *item) -{ - int idx = -1; - for (int i = 0; i < items.count(); i++) { - if (items[i] == item) { - idx = i; - break; - } - } - - if (idx == -1) - return; - - int startIdx = idx; - int endIdx = idx; - - bool is_group = obs_sceneitem_is_group(item); - if (is_group) { - obs_scene_t *scene = obs_sceneitem_group_get_scene(item); - - for (int i = endIdx + 1; i < items.count(); i++) { - obs_sceneitem_t *subitem = items[i]; - obs_scene_t *subscene = obs_sceneitem_get_scene(subitem); - - if (subscene == scene) - endIdx = i; - else - break; - } - } - - beginRemoveRows(QModelIndex(), startIdx, endIdx); - items.remove(idx, endIdx - startIdx + 1); - endRemoveRows(); - - if (is_group) - UpdateGroupState(true); - - OBSBasic::Get()->UpdateContextBarDeferred(); -} - -OBSSceneItem SourceTreeModel::Get(int idx) -{ - if (idx == -1 || idx >= items.count()) - return OBSSceneItem(); - return items[idx]; -} - -SourceTreeModel::SourceTreeModel(SourceTree *st_) : QAbstractListModel(st_), st(st_) -{ - obs_frontend_add_event_callback(OBSFrontendEvent, this); -} - -int SourceTreeModel::rowCount(const QModelIndex &parent) const -{ - return parent.isValid() ? 0 : items.count(); -} - -QVariant SourceTreeModel::data(const QModelIndex &index, int role) const -{ - if (role == Qt::AccessibleTextRole) { - OBSSceneItem item = items[index.row()]; - obs_source_t *source = obs_sceneitem_get_source(item); - return QVariant(QT_UTF8(obs_source_get_name(source))); - } - - return QVariant(); -} - -Qt::ItemFlags SourceTreeModel::flags(const QModelIndex &index) const -{ - if (!index.isValid()) - return QAbstractListModel::flags(index) | Qt::ItemIsDropEnabled; - - obs_sceneitem_t *item = items[index.row()]; - bool is_group = obs_sceneitem_is_group(item); - - return QAbstractListModel::flags(index) | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | - (is_group ? Qt::ItemIsDropEnabled : Qt::NoItemFlags); -} - -Qt::DropActions SourceTreeModel::supportedDropActions() const -{ - return QAbstractItemModel::supportedDropActions() | Qt::MoveAction; -} - -QString SourceTreeModel::GetNewGroupName() -{ - OBSScene scene = GetCurrentScene(); - QString name = QTStr("Group"); - - int i = 2; - for (;;) { - OBSSourceAutoRelease group = obs_get_source_by_name(QT_TO_UTF8(name)); - if (!group) - break; - name = QTStr("Basic.Main.Group").arg(QString::number(i++)); - } - - return name; -} - -void SourceTreeModel::AddGroup() -{ - QString name = GetNewGroupName(); - obs_sceneitem_t *group = obs_scene_add_group(GetCurrentScene(), QT_TO_UTF8(name)); - if (!group) - return; - - beginInsertRows(QModelIndex(), 0, 0); - items.insert(0, group); - endInsertRows(); - - st->UpdateWidget(createIndex(0, 0, nullptr), group); - UpdateGroupState(true); - - QMetaObject::invokeMethod(st, "Edit", Qt::QueuedConnection, Q_ARG(int, 0)); -} - -void SourceTreeModel::GroupSelectedItems(QModelIndexList &indices) -{ - if (indices.count() == 0) - return; - - OBSBasic *main = OBSBasic::Get(); - OBSScene scene = GetCurrentScene(); - QString name = GetNewGroupName(); - - QVector item_order; - - for (int i = indices.count() - 1; i >= 0; i--) { - obs_sceneitem_t *item = items[indices[i].row()]; - item_order << item; - } - - st->undoSceneData = main->BackupScene(scene); - - obs_sceneitem_t *item = obs_scene_insert_group(scene, QT_TO_UTF8(name), item_order.data(), item_order.size()); - if (!item) { - st->undoSceneData = nullptr; - return; - } - - main->undo_s.push_disabled(); - - for (obs_sceneitem_t *item : item_order) - obs_sceneitem_select(item, false); - - hasGroups = true; - st->UpdateWidgets(true); - - obs_sceneitem_select(item, true); - - /* ----------------------------------------------------------------- */ - /* obs_scene_insert_group triggers a full refresh of scene items via */ - /* the item_add signal. No need to insert a row, just edit the one */ - /* that's created automatically. */ - - int newIdx = indices[0].row(); - QMetaObject::invokeMethod(st, "NewGroupEdit", Qt::QueuedConnection, Q_ARG(int, newIdx)); -} - -void SourceTreeModel::UngroupSelectedGroups(QModelIndexList &indices) -{ - OBSBasic *main = OBSBasic::Get(); - if (indices.count() == 0) - return; - - OBSScene scene = main->GetCurrentScene(); - OBSData undoData = main->BackupScene(scene); - - for (int i = indices.count() - 1; i >= 0; i--) { - obs_sceneitem_t *item = items[indices[i].row()]; - obs_sceneitem_group_ungroup(item); - } - - SceneChanged(); - - OBSData redoData = main->BackupScene(scene); - main->CreateSceneUndoRedoAction(QTStr("Basic.Main.Ungroup"), undoData, redoData); -} - -void SourceTreeModel::ExpandGroup(obs_sceneitem_t *item) -{ - int itemIdx = items.indexOf(item); - if (itemIdx == -1) - return; - - itemIdx++; - - obs_scene_t *scene = obs_sceneitem_group_get_scene(item); - - QVector subItems; - obs_scene_enum_items(scene, enumItem, &subItems); - - if (!subItems.size()) - return; - - beginInsertRows(QModelIndex(), itemIdx, itemIdx + subItems.size() - 1); - for (int i = 0; i < subItems.size(); i++) - items.insert(i + itemIdx, subItems[i]); - endInsertRows(); - - st->UpdateWidgets(); -} - -void SourceTreeModel::CollapseGroup(obs_sceneitem_t *item) -{ - int startIdx = -1; - int endIdx = -1; - - obs_scene_t *scene = obs_sceneitem_group_get_scene(item); - - for (int i = 0; i < items.size(); i++) { - obs_scene_t *itemScene = obs_sceneitem_get_scene(items[i]); - - if (itemScene == scene) { - if (startIdx == -1) - startIdx = i; - endIdx = i; - } - } - - if (startIdx == -1) - return; - - beginRemoveRows(QModelIndex(), startIdx, endIdx); - items.remove(startIdx, endIdx - startIdx + 1); - endRemoveRows(); -} - -void SourceTreeModel::UpdateGroupState(bool update) -{ - bool nowHasGroups = false; - for (auto &item : items) { - if (obs_sceneitem_is_group(item)) { - nowHasGroups = true; - break; - } - } - - if (nowHasGroups != hasGroups) { - hasGroups = nowHasGroups; - if (update) { - st->UpdateWidgets(true); - } - } -} - -/* ========================================================================= */ - SourceTree::SourceTree(QWidget *parent_) : QListView(parent_) { SourceTreeModel *stm_ = new SourceTreeModel(this); @@ -1067,8 +107,6 @@ void SourceTree::SelectItem(obs_sceneitem_t *sceneitem, bool select) selectionModel()->select(index, select ? QItemSelectionModel::Select : QItemSelectionModel::Deselect); } -Q_DECLARE_METATYPE(OBSSceneItem); - void SourceTree::mouseDoubleClickEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) @@ -1598,16 +636,3 @@ void SourceTree::paintEvent(QPaintEvent *event) QListView::paintEvent(event); } } - -SourceTreeDelegate::SourceTreeDelegate(QObject *parent) : QStyledItemDelegate(parent) {} - -QSize SourceTreeDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const -{ - SourceTree *tree = qobject_cast(parent()); - QWidget *item = tree->indexWidget(index); - - if (!item) - return (QSize(0, 0)); - - return (QSize(option.widget->minimumWidth(), item->height())); -} diff --git a/frontend/components/SourceTree.hpp b/frontend/components/SourceTree.hpp index 8f8922d52..60cacaa3b 100644 --- a/frontend/components/SourceTree.hpp +++ b/frontend/components/SourceTree.hpp @@ -1,130 +1,11 @@ #pragma once -#include -#include -#include +#include "SourceTreeItem.hpp" +#include "SourceTreeModel.hpp" + #include -#include #include #include -#include -#include -#include -#include - -class QLabel; -class OBSSourceLabel; -class QCheckBox; -class QLineEdit; -class SourceTree; -class QSpacerItem; -class QHBoxLayout; -class VisibilityItemWidget; - -class SourceTreeItem : public QFrame { - Q_OBJECT - - friend class SourceTree; - friend class SourceTreeModel; - - void mouseDoubleClickEvent(QMouseEvent *event) override; - void enterEvent(QEnterEvent *event) override; - void leaveEvent(QEvent *event) override; - - virtual bool eventFilter(QObject *object, QEvent *event) override; - - void Update(bool force); - - enum class Type { - Unknown, - Item, - Group, - SubItem, - }; - - void DisconnectSignals(); - void ReconnectSignals(); - - Type type = Type::Unknown; - -public: - explicit SourceTreeItem(SourceTree *tree, OBSSceneItem sceneitem); - bool IsEditing(); - -private: - QSpacerItem *spacer = nullptr; - QCheckBox *expand = nullptr; - QLabel *iconLabel = nullptr; - QCheckBox *vis = nullptr; - QCheckBox *lock = nullptr; - QHBoxLayout *boxLayout = nullptr; - OBSSourceLabel *label = nullptr; - - QLineEdit *editor = nullptr; - - std::string newName; - - SourceTree *tree; - OBSSceneItem sceneitem; - std::vector sigs; - - virtual void paintEvent(QPaintEvent *event) override; - - void ExitEditModeInternal(bool save); - -private slots: - void Clear(); - - void EnterEditMode(); - void ExitEditMode(bool save); - - void VisibilityChanged(bool visible); - void LockedChanged(bool locked); - - void ExpandClicked(bool checked); - - void Select(); - void Deselect(); -}; - -class SourceTreeModel : public QAbstractListModel { - Q_OBJECT - - friend class SourceTree; - friend class SourceTreeItem; - - SourceTree *st; - QVector items; - bool hasGroups = false; - - static void OBSFrontendEvent(enum obs_frontend_event event, void *ptr); - void Clear(); - void SceneChanged(); - void ReorderItems(); - - void Add(obs_sceneitem_t *item); - void Remove(obs_sceneitem_t *item); - OBSSceneItem Get(int idx); - QString GetNewGroupName(); - void AddGroup(); - - void GroupSelectedItems(QModelIndexList &indices); - void UngroupSelectedGroups(QModelIndexList &indices); - - void ExpandGroup(obs_sceneitem_t *item); - void CollapseGroup(obs_sceneitem_t *item); - - void UpdateGroupState(bool update); - -public: - explicit SourceTreeModel(SourceTree *st); - - virtual int rowCount(const QModelIndex &parent) const override; - virtual QVariant data(const QModelIndex &index, int role) const override; - - virtual Qt::ItemFlags flags(const QModelIndex &index) const override; - virtual Qt::DropActions supportedDropActions() const override; -}; class SourceTree : public QListView { Q_OBJECT @@ -192,11 +73,3 @@ protected: virtual void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) override; }; - -class SourceTreeDelegate : public QStyledItemDelegate { - Q_OBJECT - -public: - SourceTreeDelegate(QObject *parent); - virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; -}; diff --git a/frontend/components/SourceTreeDelegate.cpp b/frontend/components/SourceTreeDelegate.cpp index a0242e3cd..b849e99ec 100644 --- a/frontend/components/SourceTreeDelegate.cpp +++ b/frontend/components/SourceTreeDelegate.cpp @@ -1,1603 +1,6 @@ -#include "window-basic-main.hpp" -#include "obs-app.hpp" -#include "source-tree.hpp" -#include "platform.hpp" -#include "source-label.hpp" - -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -static inline OBSScene GetCurrentScene() -{ - OBSBasic *main = reinterpret_cast(App()->GetMainWindow()); - return main->GetCurrentScene(); -} - -/* ========================================================================= */ - -SourceTreeItem::SourceTreeItem(SourceTree *tree_, OBSSceneItem sceneitem_) : tree(tree_), sceneitem(sceneitem_) -{ - setAttribute(Qt::WA_TranslucentBackground); - setMouseTracking(true); - - obs_source_t *source = obs_sceneitem_get_source(sceneitem); - const char *name = obs_source_get_name(source); - - OBSDataAutoRelease privData = obs_sceneitem_get_private_settings(sceneitem); - int preset = obs_data_get_int(privData, "color-preset"); - - if (preset == 1) { - const char *color = obs_data_get_string(privData, "color"); - std::string col = "background: "; - col += color; - setStyleSheet(col.c_str()); - } else if (preset > 1) { - setStyleSheet(""); - setProperty("bgColor", preset - 1); - } else { - setStyleSheet("background: none"); - } - - OBSBasic *main = reinterpret_cast(App()->GetMainWindow()); - const char *id = obs_source_get_id(source); - - bool sourceVisible = obs_sceneitem_visible(sceneitem); - - if (tree->iconsVisible) { - QIcon icon; - - if (strcmp(id, "scene") == 0) - icon = main->GetSceneIcon(); - else if (strcmp(id, "group") == 0) - icon = main->GetGroupIcon(); - else - icon = main->GetSourceIcon(id); - - QPixmap pixmap = icon.pixmap(QSize(16, 16)); - - iconLabel = new QLabel(); - iconLabel->setPixmap(pixmap); - iconLabel->setEnabled(sourceVisible); - iconLabel->setStyleSheet("background: none"); - iconLabel->setProperty("class", "source-icon"); - } - - vis = new QCheckBox(); - vis->setProperty("class", "checkbox-icon indicator-visibility"); - vis->setChecked(sourceVisible); - vis->setAccessibleName(QTStr("Basic.Main.Sources.Visibility")); - vis->setAccessibleDescription(QTStr("Basic.Main.Sources.VisibilityDescription").arg(name)); - - lock = new QCheckBox(); - lock->setProperty("class", "checkbox-icon indicator-lock"); - lock->setChecked(obs_sceneitem_locked(sceneitem)); - lock->setAccessibleName(QTStr("Basic.Main.Sources.Lock")); - lock->setAccessibleDescription(QTStr("Basic.Main.Sources.LockDescription").arg(name)); - - label = new OBSSourceLabel(source); - label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); - label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); - label->setAttribute(Qt::WA_TranslucentBackground); - label->setEnabled(sourceVisible); - -#ifdef __APPLE__ - vis->setAttribute(Qt::WA_LayoutUsesWidgetRect); - lock->setAttribute(Qt::WA_LayoutUsesWidgetRect); -#endif - - boxLayout = new QHBoxLayout(); - - boxLayout->setContentsMargins(0, 0, 0, 0); - boxLayout->setSpacing(0); - if (iconLabel) { - boxLayout->addWidget(iconLabel); - boxLayout->addSpacing(2); - } - boxLayout->addWidget(label); - boxLayout->addWidget(vis); - boxLayout->addWidget(lock); -#ifdef __APPLE__ - /* Hack: Fixes a bug where scrollbars would be above the lock icon */ - boxLayout->addSpacing(16); -#endif - - Update(false); - - setLayout(boxLayout); - - /* --------------------------------------------------------- */ - - auto setItemVisible = [this](bool val) { - obs_scene_t *scene = obs_sceneitem_get_scene(sceneitem); - obs_source_t *scenesource = obs_scene_get_source(scene); - int64_t id = obs_sceneitem_get_id(sceneitem); - const char *name = obs_source_get_name(scenesource); - const char *uuid = obs_source_get_uuid(scenesource); - obs_source_t *source = obs_sceneitem_get_source(sceneitem); - - auto undo_redo = [](const std::string &uuid, int64_t id, bool val) { - OBSSourceAutoRelease s = obs_get_source_by_uuid(uuid.c_str()); - obs_scene_t *sc = obs_group_or_scene_from_source(s); - obs_sceneitem_t *si = obs_scene_find_sceneitem_by_id(sc, id); - if (si) - obs_sceneitem_set_visible(si, val); - }; - - QString str = QTStr(val ? "Undo.ShowSceneItem" : "Undo.HideSceneItem"); - - OBSBasic *main = OBSBasic::Get(); - main->undo_s.add_action(str.arg(obs_source_get_name(source), name), - std::bind(undo_redo, std::placeholders::_1, id, !val), - std::bind(undo_redo, std::placeholders::_1, id, val), uuid, uuid); - - QSignalBlocker sourcesSignalBlocker(this); - obs_sceneitem_set_visible(sceneitem, val); - }; - - auto setItemLocked = [this](bool checked) { - QSignalBlocker sourcesSignalBlocker(this); - obs_sceneitem_set_locked(sceneitem, checked); - }; - - connect(vis, &QAbstractButton::clicked, setItemVisible); - connect(lock, &QAbstractButton::clicked, setItemLocked); -} - -void SourceTreeItem::paintEvent(QPaintEvent *event) -{ - QStyleOption opt; - opt.initFrom(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); - - QWidget::paintEvent(event); -} - -void SourceTreeItem::DisconnectSignals() -{ - sigs.clear(); -} - -void SourceTreeItem::Clear() -{ - DisconnectSignals(); - sceneitem = nullptr; -} - -void SourceTreeItem::ReconnectSignals() -{ - if (!sceneitem) - return; - - DisconnectSignals(); - - /* --------------------------------------------------------- */ - - auto removeItem = [](void *data, calldata_t *cd) { - SourceTreeItem *this_ = reinterpret_cast(data); - obs_sceneitem_t *curItem = (obs_sceneitem_t *)calldata_ptr(cd, "item"); - obs_scene_t *curScene = (obs_scene_t *)calldata_ptr(cd, "scene"); - - if (curItem == this_->sceneitem) { - QMetaObject::invokeMethod(this_->tree, "Remove", Q_ARG(OBSSceneItem, curItem), - Q_ARG(OBSScene, curScene)); - curItem = nullptr; - } - if (!curItem) - QMetaObject::invokeMethod(this_, "Clear"); - }; - - auto itemVisible = [](void *data, calldata_t *cd) { - SourceTreeItem *this_ = reinterpret_cast(data); - obs_sceneitem_t *curItem = (obs_sceneitem_t *)calldata_ptr(cd, "item"); - bool visible = calldata_bool(cd, "visible"); - - if (curItem == this_->sceneitem) - QMetaObject::invokeMethod(this_, "VisibilityChanged", Q_ARG(bool, visible)); - }; - - auto itemLocked = [](void *data, calldata_t *cd) { - SourceTreeItem *this_ = reinterpret_cast(data); - obs_sceneitem_t *curItem = (obs_sceneitem_t *)calldata_ptr(cd, "item"); - bool locked = calldata_bool(cd, "locked"); - - if (curItem == this_->sceneitem) - QMetaObject::invokeMethod(this_, "LockedChanged", Q_ARG(bool, locked)); - }; - - auto itemSelect = [](void *data, calldata_t *cd) { - SourceTreeItem *this_ = reinterpret_cast(data); - obs_sceneitem_t *curItem = (obs_sceneitem_t *)calldata_ptr(cd, "item"); - - if (curItem == this_->sceneitem) - QMetaObject::invokeMethod(this_, "Select"); - }; - - auto itemDeselect = [](void *data, calldata_t *cd) { - SourceTreeItem *this_ = reinterpret_cast(data); - obs_sceneitem_t *curItem = (obs_sceneitem_t *)calldata_ptr(cd, "item"); - - if (curItem == this_->sceneitem) - QMetaObject::invokeMethod(this_, "Deselect"); - }; - - auto reorderGroup = [](void *data, calldata_t *) { - SourceTreeItem *this_ = reinterpret_cast(data); - QMetaObject::invokeMethod(this_->tree, "ReorderItems"); - }; - - obs_scene_t *scene = obs_sceneitem_get_scene(sceneitem); - obs_source_t *sceneSource = obs_scene_get_source(scene); - signal_handler_t *signal = obs_source_get_signal_handler(sceneSource); - - sigs.emplace_back(signal, "remove", removeItem, this); - sigs.emplace_back(signal, "item_remove", removeItem, this); - sigs.emplace_back(signal, "item_visible", itemVisible, this); - sigs.emplace_back(signal, "item_locked", itemLocked, this); - sigs.emplace_back(signal, "item_select", itemSelect, this); - sigs.emplace_back(signal, "item_deselect", itemDeselect, this); - - if (obs_sceneitem_is_group(sceneitem)) { - obs_source_t *source = obs_sceneitem_get_source(sceneitem); - signal = obs_source_get_signal_handler(source); - - sigs.emplace_back(signal, "reorder", reorderGroup, this); - } - - /* --------------------------------------------------------- */ - - auto removeSource = [](void *data, calldata_t *) { - SourceTreeItem *this_ = reinterpret_cast(data); - this_->DisconnectSignals(); - this_->sceneitem = nullptr; - QMetaObject::invokeMethod(this_->tree, "RefreshItems"); - }; - - obs_source_t *source = obs_sceneitem_get_source(sceneitem); - signal = obs_source_get_signal_handler(source); - sigs.emplace_back(signal, "remove", removeSource, this); -} - -void SourceTreeItem::mouseDoubleClickEvent(QMouseEvent *event) -{ - QWidget::mouseDoubleClickEvent(event); - - if (expand) { - expand->setChecked(!expand->isChecked()); - } else { - obs_source_t *source = obs_sceneitem_get_source(sceneitem); - OBSBasic *main = reinterpret_cast(App()->GetMainWindow()); - if (obs_source_configurable(source)) { - main->CreatePropertiesWindow(source); - } - } -} - -void SourceTreeItem::enterEvent(QEnterEvent *event) -{ - QWidget::enterEvent(event); - - OBSBasicPreview *preview = OBSBasicPreview::Get(); - - std::lock_guard lock(preview->selectMutex); - preview->hoveredPreviewItems.clear(); - preview->hoveredPreviewItems.push_back(sceneitem); -} - -void SourceTreeItem::leaveEvent(QEvent *event) -{ - QWidget::leaveEvent(event); - - OBSBasicPreview *preview = OBSBasicPreview::Get(); - - std::lock_guard lock(preview->selectMutex); - preview->hoveredPreviewItems.clear(); -} - -bool SourceTreeItem::IsEditing() -{ - return editor != nullptr; -} - -void SourceTreeItem::EnterEditMode() -{ - setFocusPolicy(Qt::StrongFocus); - int index = boxLayout->indexOf(label); - boxLayout->removeWidget(label); - editor = new QLineEdit(label->text()); - editor->setStyleSheet("background: none"); - editor->selectAll(); - editor->installEventFilter(this); - boxLayout->insertWidget(index, editor); - setFocusProxy(editor); -} - -void SourceTreeItem::ExitEditMode(bool save) -{ - ExitEditModeInternal(save); - - if (tree->undoSceneData) { - OBSBasic *main = OBSBasic::Get(); - main->undo_s.pop_disabled(); - - OBSData redoSceneData = main->BackupScene(GetCurrentScene()); - - QString text = QTStr("Undo.GroupItems").arg(newName.c_str()); - main->CreateSceneUndoRedoAction(text, tree->undoSceneData, redoSceneData); - - tree->undoSceneData = nullptr; - } -} - -void SourceTreeItem::ExitEditModeInternal(bool save) -{ - if (!editor) { - return; - } - - OBSBasic *main = reinterpret_cast(App()->GetMainWindow()); - OBSScene scene = main->GetCurrentScene(); - - newName = QT_TO_UTF8(editor->text()); - - setFocusProxy(nullptr); - int index = boxLayout->indexOf(editor); - boxLayout->removeWidget(editor); - delete editor; - editor = nullptr; - setFocusPolicy(Qt::NoFocus); - boxLayout->insertWidget(index, label); - setFocus(); - - /* ----------------------------------------- */ - /* check for empty string */ - - if (!save) - return; - - if (newName.empty()) { - OBSMessageBox::information(main, QTStr("NoNameEntered.Title"), QTStr("NoNameEntered.Text")); - return; - } - - /* ----------------------------------------- */ - /* Check for same name */ - - obs_source_t *source = obs_sceneitem_get_source(sceneitem); - if (newName == obs_source_get_name(source)) - return; - - /* ----------------------------------------- */ - /* check for existing source */ - - OBSSourceAutoRelease existingSource = obs_get_source_by_name(newName.c_str()); - bool exists = !!existingSource; - - if (exists) { - OBSMessageBox::information(main, QTStr("NameExists.Title"), QTStr("NameExists.Text")); - return; - } - - /* ----------------------------------------- */ - /* rename */ - - QSignalBlocker sourcesSignalBlocker(this); - std::string prevName(obs_source_get_name(source)); - std::string scene_uuid = obs_source_get_uuid(main->GetCurrentSceneSource()); - auto undo = [scene_uuid, prevName, main](const std::string &data) { - OBSSourceAutoRelease source = obs_get_source_by_uuid(data.c_str()); - obs_source_set_name(source, prevName.c_str()); - - OBSSourceAutoRelease scene_source = obs_get_source_by_uuid(scene_uuid.c_str()); - main->SetCurrentScene(scene_source.Get(), true); - }; - - std::string editedName = newName; - - auto redo = [scene_uuid, main, editedName](const std::string &data) { - OBSSourceAutoRelease source = obs_get_source_by_uuid(data.c_str()); - obs_source_set_name(source, editedName.c_str()); - - OBSSourceAutoRelease scene_source = obs_get_source_by_uuid(scene_uuid.c_str()); - main->SetCurrentScene(scene_source.Get(), true); - }; - - const char *uuid = obs_source_get_uuid(source); - main->undo_s.add_action(QTStr("Undo.Rename").arg(newName.c_str()), undo, redo, uuid, uuid); - - obs_source_set_name(source, newName.c_str()); -} - -bool SourceTreeItem::eventFilter(QObject *object, QEvent *event) -{ - if (editor != object) - return false; - - if (LineEditCanceled(event)) { - QMetaObject::invokeMethod(this, "ExitEditMode", Qt::QueuedConnection, Q_ARG(bool, false)); - return true; - } - if (LineEditChanged(event)) { - QMetaObject::invokeMethod(this, "ExitEditMode", Qt::QueuedConnection, Q_ARG(bool, true)); - return true; - } - - return false; -} - -void SourceTreeItem::VisibilityChanged(bool visible) -{ - if (iconLabel) { - iconLabel->setEnabled(visible); - } - label->setEnabled(visible); - vis->setChecked(visible); -} - -void SourceTreeItem::LockedChanged(bool locked) -{ - lock->setChecked(locked); - OBSBasic::Get()->UpdateEditMenu(); -} - -void SourceTreeItem::Update(bool force) -{ - OBSScene scene = GetCurrentScene(); - obs_scene_t *itemScene = obs_sceneitem_get_scene(sceneitem); - - Type newType; - - /* ------------------------------------------------- */ - /* if it's a group item, insert group checkbox */ - - if (obs_sceneitem_is_group(sceneitem)) { - newType = Type::Group; - - /* ------------------------------------------------- */ - /* if it's a group sub-item */ - - } else if (itemScene != scene) { - newType = Type::SubItem; - - /* ------------------------------------------------- */ - /* if it's a regular item */ - - } else { - newType = Type::Item; - } - - /* ------------------------------------------------- */ - - if (!force && newType == type) { - return; - } - - /* ------------------------------------------------- */ - - ReconnectSignals(); - - if (spacer) { - boxLayout->removeItem(spacer); - delete spacer; - spacer = nullptr; - } - - if (type == Type::Group) { - boxLayout->removeWidget(expand); - expand->deleteLater(); - expand = nullptr; - } - - type = newType; - - if (type == Type::SubItem) { - spacer = new QSpacerItem(16, 1); - boxLayout->insertItem(0, spacer); - - } else if (type == Type::Group) { - expand = new QCheckBox(); - expand->setProperty("class", "checkbox-icon indicator-expand"); -#ifdef __APPLE__ - expand->setAttribute(Qt::WA_LayoutUsesWidgetRect); -#endif - boxLayout->insertWidget(0, expand); - - OBSDataAutoRelease data = obs_sceneitem_get_private_settings(sceneitem); - expand->blockSignals(true); - expand->setChecked(obs_data_get_bool(data, "collapsed")); - expand->blockSignals(false); - - connect(expand, &QPushButton::toggled, this, &SourceTreeItem::ExpandClicked); - - } else { - spacer = new QSpacerItem(3, 1); - boxLayout->insertItem(0, spacer); - } -} - -void SourceTreeItem::ExpandClicked(bool checked) -{ - OBSDataAutoRelease data = obs_sceneitem_get_private_settings(sceneitem); - - obs_data_set_bool(data, "collapsed", checked); - - if (!checked) - tree->GetStm()->ExpandGroup(sceneitem); - else - tree->GetStm()->CollapseGroup(sceneitem); -} - -void SourceTreeItem::Select() -{ - tree->SelectItem(sceneitem, true); - OBSBasic::Get()->UpdateContextBarDeferred(); - OBSBasic::Get()->UpdateEditMenu(); -} - -void SourceTreeItem::Deselect() -{ - tree->SelectItem(sceneitem, false); - OBSBasic::Get()->UpdateContextBarDeferred(); - OBSBasic::Get()->UpdateEditMenu(); -} - -/* ========================================================================= */ - -void SourceTreeModel::OBSFrontendEvent(enum obs_frontend_event event, void *ptr) -{ - SourceTreeModel *stm = reinterpret_cast(ptr); - - switch (event) { - case OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED: - stm->SceneChanged(); - break; - case OBS_FRONTEND_EVENT_EXIT: - stm->Clear(); - obs_frontend_remove_event_callback(OBSFrontendEvent, stm); - break; - case OBS_FRONTEND_EVENT_SCENE_COLLECTION_CLEANUP: - stm->Clear(); - break; - default: - break; - } -} - -void SourceTreeModel::Clear() -{ - beginResetModel(); - items.clear(); - endResetModel(); - - hasGroups = false; -} - -static bool enumItem(obs_scene_t *, obs_sceneitem_t *item, void *ptr) -{ - QVector &items = *reinterpret_cast *>(ptr); - - obs_source_t *src = obs_sceneitem_get_source(item); - if (obs_source_removed(src)) { - return true; - } - - if (obs_sceneitem_is_group(item)) { - OBSDataAutoRelease data = obs_sceneitem_get_private_settings(item); - - bool collapse = obs_data_get_bool(data, "collapsed"); - if (!collapse) { - obs_scene_t *scene = obs_sceneitem_group_get_scene(item); - - obs_scene_enum_items(scene, enumItem, &items); - } - } - - items.insert(0, item); - return true; -} - -void SourceTreeModel::SceneChanged() -{ - OBSScene scene = GetCurrentScene(); - - beginResetModel(); - items.clear(); - obs_scene_enum_items(scene, enumItem, &items); - endResetModel(); - - UpdateGroupState(false); - st->ResetWidgets(); - - for (int i = 0; i < items.count(); i++) { - bool select = obs_sceneitem_selected(items[i]); - QModelIndex index = createIndex(i, 0); - - st->selectionModel()->select(index, - select ? QItemSelectionModel::Select : QItemSelectionModel::Deselect); - } -} - -/* moves a scene item index (blame linux distros for using older Qt builds) */ -static inline void MoveItem(QVector &items, int oldIdx, int newIdx) -{ - OBSSceneItem item = items[oldIdx]; - items.remove(oldIdx); - items.insert(newIdx, item); -} - -/* reorders list optimally with model reorder funcs */ -void SourceTreeModel::ReorderItems() -{ - OBSScene scene = GetCurrentScene(); - - QVector newitems; - obs_scene_enum_items(scene, enumItem, &newitems); - - /* if item list has changed size, do full reset */ - if (newitems.count() != items.count()) { - SceneChanged(); - return; - } - - for (;;) { - int idx1Old = 0; - int idx1New = 0; - int count; - int i; - - /* find first starting changed item index */ - for (i = 0; i < newitems.count(); i++) { - obs_sceneitem_t *oldItem = items[i]; - obs_sceneitem_t *newItem = newitems[i]; - if (oldItem != newItem) { - idx1Old = i; - break; - } - } - - /* if everything is the same, break */ - if (i == newitems.count()) { - break; - } - - /* find new starting index */ - for (i = idx1Old + 1; i < newitems.count(); i++) { - obs_sceneitem_t *oldItem = items[idx1Old]; - obs_sceneitem_t *newItem = newitems[i]; - - if (oldItem == newItem) { - idx1New = i; - break; - } - } - - /* if item could not be found, do full reset */ - if (i == newitems.count()) { - SceneChanged(); - return; - } - - /* get move count */ - for (count = 1; (idx1New + count) < newitems.count(); count++) { - int oldIdx = idx1Old + count; - int newIdx = idx1New + count; - - obs_sceneitem_t *oldItem = items[oldIdx]; - obs_sceneitem_t *newItem = newitems[newIdx]; - - if (oldItem != newItem) { - break; - } - } - - /* move items */ - beginMoveRows(QModelIndex(), idx1Old, idx1Old + count - 1, QModelIndex(), idx1New + count); - for (i = 0; i < count; i++) { - int to = idx1New + count; - if (to > idx1Old) - to--; - MoveItem(items, idx1Old, to); - } - endMoveRows(); - } -} - -void SourceTreeModel::Add(obs_sceneitem_t *item) -{ - if (obs_sceneitem_is_group(item)) { - SceneChanged(); - } else { - beginInsertRows(QModelIndex(), 0, 0); - items.insert(0, item); - endInsertRows(); - - st->UpdateWidget(createIndex(0, 0, nullptr), item); - } -} - -void SourceTreeModel::Remove(obs_sceneitem_t *item) -{ - int idx = -1; - for (int i = 0; i < items.count(); i++) { - if (items[i] == item) { - idx = i; - break; - } - } - - if (idx == -1) - return; - - int startIdx = idx; - int endIdx = idx; - - bool is_group = obs_sceneitem_is_group(item); - if (is_group) { - obs_scene_t *scene = obs_sceneitem_group_get_scene(item); - - for (int i = endIdx + 1; i < items.count(); i++) { - obs_sceneitem_t *subitem = items[i]; - obs_scene_t *subscene = obs_sceneitem_get_scene(subitem); - - if (subscene == scene) - endIdx = i; - else - break; - } - } - - beginRemoveRows(QModelIndex(), startIdx, endIdx); - items.remove(idx, endIdx - startIdx + 1); - endRemoveRows(); - - if (is_group) - UpdateGroupState(true); - - OBSBasic::Get()->UpdateContextBarDeferred(); -} - -OBSSceneItem SourceTreeModel::Get(int idx) -{ - if (idx == -1 || idx >= items.count()) - return OBSSceneItem(); - return items[idx]; -} - -SourceTreeModel::SourceTreeModel(SourceTree *st_) : QAbstractListModel(st_), st(st_) -{ - obs_frontend_add_event_callback(OBSFrontendEvent, this); -} - -int SourceTreeModel::rowCount(const QModelIndex &parent) const -{ - return parent.isValid() ? 0 : items.count(); -} - -QVariant SourceTreeModel::data(const QModelIndex &index, int role) const -{ - if (role == Qt::AccessibleTextRole) { - OBSSceneItem item = items[index.row()]; - obs_source_t *source = obs_sceneitem_get_source(item); - return QVariant(QT_UTF8(obs_source_get_name(source))); - } - - return QVariant(); -} - -Qt::ItemFlags SourceTreeModel::flags(const QModelIndex &index) const -{ - if (!index.isValid()) - return QAbstractListModel::flags(index) | Qt::ItemIsDropEnabled; - - obs_sceneitem_t *item = items[index.row()]; - bool is_group = obs_sceneitem_is_group(item); - - return QAbstractListModel::flags(index) | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | - (is_group ? Qt::ItemIsDropEnabled : Qt::NoItemFlags); -} - -Qt::DropActions SourceTreeModel::supportedDropActions() const -{ - return QAbstractItemModel::supportedDropActions() | Qt::MoveAction; -} - -QString SourceTreeModel::GetNewGroupName() -{ - OBSScene scene = GetCurrentScene(); - QString name = QTStr("Group"); - - int i = 2; - for (;;) { - OBSSourceAutoRelease group = obs_get_source_by_name(QT_TO_UTF8(name)); - if (!group) - break; - name = QTStr("Basic.Main.Group").arg(QString::number(i++)); - } - - return name; -} - -void SourceTreeModel::AddGroup() -{ - QString name = GetNewGroupName(); - obs_sceneitem_t *group = obs_scene_add_group(GetCurrentScene(), QT_TO_UTF8(name)); - if (!group) - return; - - beginInsertRows(QModelIndex(), 0, 0); - items.insert(0, group); - endInsertRows(); - - st->UpdateWidget(createIndex(0, 0, nullptr), group); - UpdateGroupState(true); - - QMetaObject::invokeMethod(st, "Edit", Qt::QueuedConnection, Q_ARG(int, 0)); -} - -void SourceTreeModel::GroupSelectedItems(QModelIndexList &indices) -{ - if (indices.count() == 0) - return; - - OBSBasic *main = OBSBasic::Get(); - OBSScene scene = GetCurrentScene(); - QString name = GetNewGroupName(); - - QVector item_order; - - for (int i = indices.count() - 1; i >= 0; i--) { - obs_sceneitem_t *item = items[indices[i].row()]; - item_order << item; - } - - st->undoSceneData = main->BackupScene(scene); - - obs_sceneitem_t *item = obs_scene_insert_group(scene, QT_TO_UTF8(name), item_order.data(), item_order.size()); - if (!item) { - st->undoSceneData = nullptr; - return; - } - - main->undo_s.push_disabled(); - - for (obs_sceneitem_t *item : item_order) - obs_sceneitem_select(item, false); - - hasGroups = true; - st->UpdateWidgets(true); - - obs_sceneitem_select(item, true); - - /* ----------------------------------------------------------------- */ - /* obs_scene_insert_group triggers a full refresh of scene items via */ - /* the item_add signal. No need to insert a row, just edit the one */ - /* that's created automatically. */ - - int newIdx = indices[0].row(); - QMetaObject::invokeMethod(st, "NewGroupEdit", Qt::QueuedConnection, Q_ARG(int, newIdx)); -} - -void SourceTreeModel::UngroupSelectedGroups(QModelIndexList &indices) -{ - OBSBasic *main = OBSBasic::Get(); - if (indices.count() == 0) - return; - - OBSScene scene = main->GetCurrentScene(); - OBSData undoData = main->BackupScene(scene); - - for (int i = indices.count() - 1; i >= 0; i--) { - obs_sceneitem_t *item = items[indices[i].row()]; - obs_sceneitem_group_ungroup(item); - } - - SceneChanged(); - - OBSData redoData = main->BackupScene(scene); - main->CreateSceneUndoRedoAction(QTStr("Basic.Main.Ungroup"), undoData, redoData); -} - -void SourceTreeModel::ExpandGroup(obs_sceneitem_t *item) -{ - int itemIdx = items.indexOf(item); - if (itemIdx == -1) - return; - - itemIdx++; - - obs_scene_t *scene = obs_sceneitem_group_get_scene(item); - - QVector subItems; - obs_scene_enum_items(scene, enumItem, &subItems); - - if (!subItems.size()) - return; - - beginInsertRows(QModelIndex(), itemIdx, itemIdx + subItems.size() - 1); - for (int i = 0; i < subItems.size(); i++) - items.insert(i + itemIdx, subItems[i]); - endInsertRows(); - - st->UpdateWidgets(); -} - -void SourceTreeModel::CollapseGroup(obs_sceneitem_t *item) -{ - int startIdx = -1; - int endIdx = -1; - - obs_scene_t *scene = obs_sceneitem_group_get_scene(item); - - for (int i = 0; i < items.size(); i++) { - obs_scene_t *itemScene = obs_sceneitem_get_scene(items[i]); - - if (itemScene == scene) { - if (startIdx == -1) - startIdx = i; - endIdx = i; - } - } - - if (startIdx == -1) - return; - - beginRemoveRows(QModelIndex(), startIdx, endIdx); - items.remove(startIdx, endIdx - startIdx + 1); - endRemoveRows(); -} - -void SourceTreeModel::UpdateGroupState(bool update) -{ - bool nowHasGroups = false; - for (auto &item : items) { - if (obs_sceneitem_is_group(item)) { - nowHasGroups = true; - break; - } - } - - if (nowHasGroups != hasGroups) { - hasGroups = nowHasGroups; - if (update) { - st->UpdateWidgets(true); - } - } -} - -/* ========================================================================= */ - -SourceTree::SourceTree(QWidget *parent_) : QListView(parent_) -{ - SourceTreeModel *stm_ = new SourceTreeModel(this); - setModel(stm_); - setStyleSheet(QString("*[bgColor=\"1\"]{background-color:rgba(255,68,68,33%);}" - "*[bgColor=\"2\"]{background-color:rgba(255,255,68,33%);}" - "*[bgColor=\"3\"]{background-color:rgba(68,255,68,33%);}" - "*[bgColor=\"4\"]{background-color:rgba(68,255,255,33%);}" - "*[bgColor=\"5\"]{background-color:rgba(68,68,255,33%);}" - "*[bgColor=\"6\"]{background-color:rgba(255,68,255,33%);}" - "*[bgColor=\"7\"]{background-color:rgba(68,68,68,33%);}" - "*[bgColor=\"8\"]{background-color:rgba(255,255,255,33%);}")); - - UpdateNoSourcesMessage(); - connect(App(), &OBSApp::StyleChanged, this, &SourceTree::UpdateNoSourcesMessage); - connect(App(), &OBSApp::StyleChanged, this, &SourceTree::UpdateIcons); - - setItemDelegate(new SourceTreeDelegate(this)); -} - -void SourceTree::UpdateIcons() -{ - SourceTreeModel *stm = GetStm(); - stm->SceneChanged(); -} - -void SourceTree::SetIconsVisible(bool visible) -{ - SourceTreeModel *stm = GetStm(); - - iconsVisible = visible; - stm->SceneChanged(); -} - -void SourceTree::ResetWidgets() -{ - OBSScene scene = GetCurrentScene(); - - SourceTreeModel *stm = GetStm(); - stm->UpdateGroupState(false); - - for (int i = 0; i < stm->items.count(); i++) { - QModelIndex index = stm->createIndex(i, 0, nullptr); - setIndexWidget(index, new SourceTreeItem(this, stm->items[i])); - } -} - -void SourceTree::UpdateWidget(const QModelIndex &idx, obs_sceneitem_t *item) -{ - setIndexWidget(idx, new SourceTreeItem(this, item)); -} - -void SourceTree::UpdateWidgets(bool force) -{ - SourceTreeModel *stm = GetStm(); - - for (int i = 0; i < stm->items.size(); i++) { - obs_sceneitem_t *item = stm->items[i]; - SourceTreeItem *widget = GetItemWidget(i); - - if (!widget) { - UpdateWidget(stm->createIndex(i, 0), item); - } else { - widget->Update(force); - } - } -} - -void SourceTree::SelectItem(obs_sceneitem_t *sceneitem, bool select) -{ - SourceTreeModel *stm = GetStm(); - int i = 0; - - for (; i < stm->items.count(); i++) { - if (stm->items[i] == sceneitem) - break; - } - - if (i == stm->items.count()) - return; - - QModelIndex index = stm->createIndex(i, 0); - if (index.isValid() && select != selectionModel()->isSelected(index)) - selectionModel()->select(index, select ? QItemSelectionModel::Select : QItemSelectionModel::Deselect); -} - -Q_DECLARE_METATYPE(OBSSceneItem); - -void SourceTree::mouseDoubleClickEvent(QMouseEvent *event) -{ - if (event->button() == Qt::LeftButton) - QListView::mouseDoubleClickEvent(event); -} - -void SourceTree::dropEvent(QDropEvent *event) -{ - if (event->source() != this) { - QListView::dropEvent(event); - return; - } - - OBSBasic *main = OBSBasic::Get(); - - OBSScene scene = GetCurrentScene(); - obs_source_t *scenesource = obs_scene_get_source(scene); - SourceTreeModel *stm = GetStm(); - auto &items = stm->items; - QModelIndexList indices = selectedIndexes(); - - DropIndicatorPosition indicator = dropIndicatorPosition(); - int row = indexAt(event->position().toPoint()).row(); - bool emptyDrop = row == -1; - - if (emptyDrop) { - if (!items.size()) { - QListView::dropEvent(event); - return; - } - - row = items.size() - 1; - indicator = QAbstractItemView::BelowItem; - } - - /* --------------------------------------- */ - /* store destination group if moving to a */ - /* group */ - - obs_sceneitem_t *dropItem = items[row]; /* item being dropped on */ - bool itemIsGroup = obs_sceneitem_is_group(dropItem); - - obs_sceneitem_t *dropGroup = itemIsGroup ? dropItem : obs_sceneitem_get_group(scene, dropItem); - - /* not a group if moving above the group */ - if (indicator == QAbstractItemView::AboveItem && itemIsGroup) - dropGroup = nullptr; - if (emptyDrop) - dropGroup = nullptr; - - /* --------------------------------------- */ - /* remember to remove list items if */ - /* dropping on collapsed group */ - - bool dropOnCollapsed = false; - if (dropGroup) { - obs_data_t *data = obs_sceneitem_get_private_settings(dropGroup); - dropOnCollapsed = obs_data_get_bool(data, "collapsed"); - obs_data_release(data); - } - - if (indicator == QAbstractItemView::BelowItem || indicator == QAbstractItemView::OnItem || - indicator == QAbstractItemView::OnViewport) - row++; - - if (row < 0 || row > stm->items.count()) { - QListView::dropEvent(event); - return; - } - - /* --------------------------------------- */ - /* determine if any base group is selected */ - - bool hasGroups = false; - for (int i = 0; i < indices.size(); i++) { - obs_sceneitem_t *item = items[indices[i].row()]; - if (obs_sceneitem_is_group(item)) { - hasGroups = true; - break; - } - } - - /* --------------------------------------- */ - /* if dropping a group, detect if it's */ - /* below another group */ - - obs_sceneitem_t *itemBelow; - if (row == stm->items.count()) - itemBelow = nullptr; - else - itemBelow = stm->items[row]; - - if (hasGroups) { - if (!itemBelow || obs_sceneitem_get_group(scene, itemBelow) != dropGroup) { - dropGroup = nullptr; - dropOnCollapsed = false; - } - } - - /* --------------------------------------- */ - /* if dropping groups on other groups, */ - /* disregard as invalid drag/drop */ - - if (dropGroup && hasGroups) { - QListView::dropEvent(event); - return; - } - - /* --------------------------------------- */ - /* save undo data */ - std::vector sources; - for (int i = 0; i < indices.size(); i++) { - obs_sceneitem_t *item = items[indices[i].row()]; - if (obs_sceneitem_get_scene(item) != scene) - sources.push_back(obs_scene_get_source(obs_sceneitem_get_scene(item))); - } - if (dropGroup) - sources.push_back(obs_sceneitem_get_source(dropGroup)); - OBSData undo_data = main->BackupScene(scene, &sources); - - /* --------------------------------------- */ - /* if selection includes base group items, */ - /* include all group sub-items and treat */ - /* them all as one */ - - if (hasGroups) { - /* remove sub-items if selected */ - for (int i = indices.size() - 1; i >= 0; i--) { - obs_sceneitem_t *item = items[indices[i].row()]; - obs_scene_t *itemScene = obs_sceneitem_get_scene(item); - - if (itemScene != scene) { - indices.removeAt(i); - } - } - - /* add all sub-items of selected groups */ - for (int i = indices.size() - 1; i >= 0; i--) { - obs_sceneitem_t *item = items[indices[i].row()]; - - if (obs_sceneitem_is_group(item)) { - for (int j = items.size() - 1; j >= 0; j--) { - obs_sceneitem_t *subitem = items[j]; - obs_sceneitem_t *subitemGroup = obs_sceneitem_get_group(scene, subitem); - - if (subitemGroup == item) { - QModelIndex idx = stm->createIndex(j, 0); - indices.insert(i + 1, idx); - } - } - } - } - } - - /* --------------------------------------- */ - /* build persistent indices */ - - QList persistentIndices; - persistentIndices.reserve(indices.count()); - for (QModelIndex &index : indices) - persistentIndices.append(index); - std::sort(persistentIndices.begin(), persistentIndices.end()); - - /* --------------------------------------- */ - /* move all items to destination index */ - - int r = row; - for (auto &persistentIdx : persistentIndices) { - int from = persistentIdx.row(); - int to = r; - int itemTo = to; - - if (itemTo > from) - itemTo--; - - if (itemTo != from) { - stm->beginMoveRows(QModelIndex(), from, from, QModelIndex(), to); - MoveItem(items, from, itemTo); - stm->endMoveRows(); - } - - r = persistentIdx.row() + 1; - } - - std::sort(persistentIndices.begin(), persistentIndices.end()); - int firstIdx = persistentIndices.front().row(); - int lastIdx = persistentIndices.back().row(); - - /* --------------------------------------- */ - /* reorder scene items in back-end */ - - QVector orderList; - obs_sceneitem_t *lastGroup = nullptr; - int insertCollapsedIdx = 0; - - auto insertCollapsed = [&](obs_sceneitem_t *item) { - struct obs_sceneitem_order_info info; - info.group = lastGroup; - info.item = item; - - orderList.insert(insertCollapsedIdx++, info); - }; - - using insertCollapsed_t = decltype(insertCollapsed); - - auto preInsertCollapsed = [](obs_scene_t *, obs_sceneitem_t *item, void *param) { - (*reinterpret_cast(param))(item); - return true; - }; - - auto insertLastGroup = [&]() { - OBSDataAutoRelease data = obs_sceneitem_get_private_settings(lastGroup); - bool collapsed = obs_data_get_bool(data, "collapsed"); - - if (collapsed) { - insertCollapsedIdx = 0; - obs_sceneitem_group_enum_items(lastGroup, preInsertCollapsed, &insertCollapsed); - } - - struct obs_sceneitem_order_info info; - info.group = nullptr; - info.item = lastGroup; - orderList.insert(0, info); - }; - - auto updateScene = [&]() { - struct obs_sceneitem_order_info info; - - for (int i = 0; i < items.size(); i++) { - obs_sceneitem_t *item = items[i]; - obs_sceneitem_t *group; - - if (obs_sceneitem_is_group(item)) { - if (lastGroup) { - insertLastGroup(); - } - lastGroup = item; - continue; - } - - if (!hasGroups && i >= firstIdx && i <= lastIdx) - group = dropGroup; - else - group = obs_sceneitem_get_group(scene, item); - - if (lastGroup && lastGroup != group) { - insertLastGroup(); - } - - lastGroup = group; - - info.group = group; - info.item = item; - orderList.insert(0, info); - } - - if (lastGroup) { - insertLastGroup(); - } - - obs_scene_reorder_items2(scene, orderList.data(), orderList.size()); - }; - - using updateScene_t = decltype(updateScene); - - auto preUpdateScene = [](void *data, obs_scene_t *) { - (*reinterpret_cast(data))(); - }; - - ignoreReorder = true; - obs_scene_atomic_update(scene, preUpdateScene, &updateScene); - ignoreReorder = false; - - /* --------------------------------------- */ - /* save redo data */ - - OBSData redo_data = main->BackupScene(scene, &sources); - - /* --------------------------------------- */ - /* add undo/redo action */ - - const char *scene_name = obs_source_get_name(scenesource); - QString action_name = QTStr("Undo.ReorderSources").arg(scene_name); - main->CreateSceneUndoRedoAction(action_name, undo_data, redo_data); - - /* --------------------------------------- */ - /* remove items if dropped in to collapsed */ - /* group */ - - if (dropOnCollapsed) { - stm->beginRemoveRows(QModelIndex(), firstIdx, lastIdx); - items.remove(firstIdx, lastIdx - firstIdx + 1); - stm->endRemoveRows(); - } - - /* --------------------------------------- */ - /* update widgets and accept event */ - - UpdateWidgets(true); - - event->accept(); - event->setDropAction(Qt::CopyAction); - - QListView::dropEvent(event); -} - -void SourceTree::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) -{ - { - QSignalBlocker sourcesSignalBlocker(this); - SourceTreeModel *stm = GetStm(); - - QModelIndexList selectedIdxs = selected.indexes(); - QModelIndexList deselectedIdxs = deselected.indexes(); - - for (int i = 0; i < selectedIdxs.count(); i++) { - int idx = selectedIdxs[i].row(); - obs_sceneitem_select(stm->items[idx], true); - } - - for (int i = 0; i < deselectedIdxs.count(); i++) { - int idx = deselectedIdxs[i].row(); - obs_sceneitem_select(stm->items[idx], false); - } - } - QListView::selectionChanged(selected, deselected); -} - -void SourceTree::NewGroupEdit(int row) -{ - if (!Edit(row)) { - OBSBasic *main = OBSBasic::Get(); - main->undo_s.pop_disabled(); - - blog(LOG_WARNING, "Uh, somehow the edit didn't process, this " - "code should never be reached.\nAnd by " - "\"never be reached\", I mean that " - "theoretically, it should be\nimpossible " - "for this code to be reached. But if this " - "code is reached,\nfeel free to laugh at " - "Lain, because apparently it is, in fact, " - "actually\npossible for this code to be " - "reached. But I mean, again, theoretically\n" - "it should be impossible. So if you see " - "this in your log, just know that\nit's " - "really dumb, and depressing. But at least " - "the undo/redo action is\nstill covered, so " - "in theory things *should* be fine. But " - "it's entirely\npossible that they might " - "not be exactly. But again, yea. This " - "really\nshould not be possible."); - - OBSData redoSceneData = main->BackupScene(GetCurrentScene()); - - QString text = QTStr("Undo.GroupItems").arg("Unknown"); - main->CreateSceneUndoRedoAction(text, undoSceneData, redoSceneData); - - undoSceneData = nullptr; - } -} - -bool SourceTree::Edit(int row) -{ - SourceTreeModel *stm = GetStm(); - if (row < 0 || row >= stm->items.count()) - return false; - - QModelIndex index = stm->createIndex(row, 0); - QWidget *widget = indexWidget(index); - SourceTreeItem *itemWidget = reinterpret_cast(widget); - if (itemWidget->IsEditing()) { -#ifdef __APPLE__ - itemWidget->ExitEditMode(true); -#endif - return false; - } - - itemWidget->EnterEditMode(); - edit(index); - return true; -} - -bool SourceTree::MultipleBaseSelected() const -{ - SourceTreeModel *stm = GetStm(); - QModelIndexList selectedIndices = selectedIndexes(); - - OBSScene scene = GetCurrentScene(); - - if (selectedIndices.size() < 1) { - return false; - } - - for (auto &idx : selectedIndices) { - obs_sceneitem_t *item = stm->items[idx.row()]; - if (obs_sceneitem_is_group(item)) { - return false; - } - - obs_scene *itemScene = obs_sceneitem_get_scene(item); - if (itemScene != scene) { - return false; - } - } - - return true; -} - -bool SourceTree::GroupsSelected() const -{ - SourceTreeModel *stm = GetStm(); - QModelIndexList selectedIndices = selectedIndexes(); - - OBSScene scene = GetCurrentScene(); - - if (selectedIndices.size() < 1) { - return false; - } - - for (auto &idx : selectedIndices) { - obs_sceneitem_t *item = stm->items[idx.row()]; - if (!obs_sceneitem_is_group(item)) { - return false; - } - } - - return true; -} - -bool SourceTree::GroupedItemsSelected() const -{ - SourceTreeModel *stm = GetStm(); - QModelIndexList selectedIndices = selectedIndexes(); - OBSScene scene = GetCurrentScene(); - - if (!selectedIndices.size()) { - return false; - } - - for (auto &idx : selectedIndices) { - obs_sceneitem_t *item = stm->items[idx.row()]; - obs_scene *itemScene = obs_sceneitem_get_scene(item); - - if (itemScene != scene) { - return true; - } - } - - return false; -} - -void SourceTree::Remove(OBSSceneItem item, OBSScene scene) -{ - OBSBasic *main = reinterpret_cast(App()->GetMainWindow()); - GetStm()->Remove(item); - main->SaveProject(); - - if (!main->SavingDisabled()) { - obs_source_t *sceneSource = obs_scene_get_source(scene); - obs_source_t *itemSource = obs_sceneitem_get_source(item); - blog(LOG_INFO, "User Removed source '%s' (%s) from scene '%s'", obs_source_get_name(itemSource), - obs_source_get_id(itemSource), obs_source_get_name(sceneSource)); - } -} - -void SourceTree::GroupSelectedItems() -{ - QModelIndexList indices = selectedIndexes(); - std::sort(indices.begin(), indices.end()); - GetStm()->GroupSelectedItems(indices); -} - -void SourceTree::UngroupSelectedGroups() -{ - QModelIndexList indices = selectedIndexes(); - GetStm()->UngroupSelectedGroups(indices); -} - -void SourceTree::AddGroup() -{ - GetStm()->AddGroup(); -} - -void SourceTree::UpdateNoSourcesMessage() -{ - QString file = !App()->IsThemeDark() ? ":res/images/no_sources.svg" : "theme:Dark/no_sources.svg"; - iconNoSources.load(file); - - QTextOption opt(Qt::AlignHCenter); - opt.setWrapMode(QTextOption::WordWrap); - textNoSources.setTextOption(opt); - textNoSources.setText(QTStr("NoSources.Label").replace("\n", "
")); - - textPrepared = false; -} - -void SourceTree::paintEvent(QPaintEvent *event) -{ - SourceTreeModel *stm = GetStm(); - if (stm && !stm->items.count()) { - QPainter p(viewport()); - - if (!textPrepared) { - textNoSources.prepare(QTransform(), p.font()); - textPrepared = true; - } - - QRectF iconRect = iconNoSources.viewBoxF(); - iconRect.setSize(QSizeF(32.0, 32.0)); - - QSizeF iconSize = iconRect.size(); - QSizeF textSize = textNoSources.size(); - QSizeF thisSize = size(); - const qreal spacing = 16.0; - - qreal totalHeight = iconSize.height() + spacing + textSize.height(); - - qreal x = thisSize.width() / 2.0 - iconSize.width() / 2.0; - qreal y = thisSize.height() / 2.0 - totalHeight / 2.0; - iconRect.moveTo(std::round(x), std::round(y)); - iconNoSources.render(&p, iconRect); - - x = thisSize.width() / 2.0 - textSize.width() / 2.0; - y += spacing + iconSize.height(); - p.drawStaticText(x, y, textNoSources); - } else { - QListView::paintEvent(event); - } -} +#include "SourceTree.hpp" +#include "SourceTreeDelegate.hpp" +#include "moc_SourceTreeDelegate.cpp" SourceTreeDelegate::SourceTreeDelegate(QObject *parent) : QStyledItemDelegate(parent) {} diff --git a/frontend/components/SourceTreeDelegate.hpp b/frontend/components/SourceTreeDelegate.hpp index 8f8922d52..c5489395f 100644 --- a/frontend/components/SourceTreeDelegate.hpp +++ b/frontend/components/SourceTreeDelegate.hpp @@ -1,197 +1,10 @@ #pragma once -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include #include -#include -#include - -class QLabel; -class OBSSourceLabel; -class QCheckBox; -class QLineEdit; -class SourceTree; -class QSpacerItem; -class QHBoxLayout; -class VisibilityItemWidget; - -class SourceTreeItem : public QFrame { - Q_OBJECT - - friend class SourceTree; - friend class SourceTreeModel; - - void mouseDoubleClickEvent(QMouseEvent *event) override; - void enterEvent(QEnterEvent *event) override; - void leaveEvent(QEvent *event) override; - - virtual bool eventFilter(QObject *object, QEvent *event) override; - - void Update(bool force); - - enum class Type { - Unknown, - Item, - Group, - SubItem, - }; - - void DisconnectSignals(); - void ReconnectSignals(); - - Type type = Type::Unknown; - -public: - explicit SourceTreeItem(SourceTree *tree, OBSSceneItem sceneitem); - bool IsEditing(); - -private: - QSpacerItem *spacer = nullptr; - QCheckBox *expand = nullptr; - QLabel *iconLabel = nullptr; - QCheckBox *vis = nullptr; - QCheckBox *lock = nullptr; - QHBoxLayout *boxLayout = nullptr; - OBSSourceLabel *label = nullptr; - - QLineEdit *editor = nullptr; - - std::string newName; - - SourceTree *tree; - OBSSceneItem sceneitem; - std::vector sigs; - - virtual void paintEvent(QPaintEvent *event) override; - - void ExitEditModeInternal(bool save); - -private slots: - void Clear(); - - void EnterEditMode(); - void ExitEditMode(bool save); - - void VisibilityChanged(bool visible); - void LockedChanged(bool locked); - - void ExpandClicked(bool checked); - - void Select(); - void Deselect(); -}; - -class SourceTreeModel : public QAbstractListModel { - Q_OBJECT - - friend class SourceTree; - friend class SourceTreeItem; - - SourceTree *st; - QVector items; - bool hasGroups = false; - - static void OBSFrontendEvent(enum obs_frontend_event event, void *ptr); - void Clear(); - void SceneChanged(); - void ReorderItems(); - - void Add(obs_sceneitem_t *item); - void Remove(obs_sceneitem_t *item); - OBSSceneItem Get(int idx); - QString GetNewGroupName(); - void AddGroup(); - - void GroupSelectedItems(QModelIndexList &indices); - void UngroupSelectedGroups(QModelIndexList &indices); - - void ExpandGroup(obs_sceneitem_t *item); - void CollapseGroup(obs_sceneitem_t *item); - - void UpdateGroupState(bool update); - -public: - explicit SourceTreeModel(SourceTree *st); - - virtual int rowCount(const QModelIndex &parent) const override; - virtual QVariant data(const QModelIndex &index, int role) const override; - - virtual Qt::ItemFlags flags(const QModelIndex &index) const override; - virtual Qt::DropActions supportedDropActions() const override; -}; - -class SourceTree : public QListView { - Q_OBJECT - - bool ignoreReorder = false; - - friend class SourceTreeModel; - friend class SourceTreeItem; - - bool textPrepared = false; - QStaticText textNoSources; - QSvgRenderer iconNoSources; - - OBSData undoSceneData; - - bool iconsVisible = true; - - void UpdateNoSourcesMessage(); - - void ResetWidgets(); - void UpdateWidget(const QModelIndex &idx, obs_sceneitem_t *item); - void UpdateWidgets(bool force = false); - - inline SourceTreeModel *GetStm() const { return reinterpret_cast(model()); } - -public: - inline SourceTreeItem *GetItemWidget(int idx) - { - QWidget *widget = indexWidget(GetStm()->createIndex(idx, 0)); - return reinterpret_cast(widget); - } - - explicit SourceTree(QWidget *parent = nullptr); - - inline bool IgnoreReorder() const { return ignoreReorder; } - inline void Clear() { GetStm()->Clear(); } - - inline void Add(obs_sceneitem_t *item) { GetStm()->Add(item); } - inline OBSSceneItem Get(int idx) { return GetStm()->Get(idx); } - inline QString GetNewGroupName() { return GetStm()->GetNewGroupName(); } - - void SelectItem(obs_sceneitem_t *sceneitem, bool select); - - bool MultipleBaseSelected() const; - bool GroupsSelected() const; - bool GroupedItemsSelected() const; - - void UpdateIcons(); - void SetIconsVisible(bool visible); - -public slots: - inline void ReorderItems() { GetStm()->ReorderItems(); } - inline void RefreshItems() { GetStm()->SceneChanged(); } - void Remove(OBSSceneItem item, OBSScene scene); - void GroupSelectedItems(); - void UngroupSelectedGroups(); - void AddGroup(); - bool Edit(int idx); - void NewGroupEdit(int idx); - -protected: - virtual void mouseDoubleClickEvent(QMouseEvent *event) override; - virtual void dropEvent(QDropEvent *event) override; - virtual void paintEvent(QPaintEvent *event) override; - - virtual void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) override; -}; +#include class SourceTreeDelegate : public QStyledItemDelegate { Q_OBJECT diff --git a/frontend/components/SourceTreeItem.cpp b/frontend/components/SourceTreeItem.cpp index a0242e3cd..7b6b7a7f4 100644 --- a/frontend/components/SourceTreeItem.cpp +++ b/frontend/components/SourceTreeItem.cpp @@ -1,26 +1,15 @@ -#include "window-basic-main.hpp" -#include "obs-app.hpp" -#include "source-tree.hpp" -#include "platform.hpp" -#include "source-label.hpp" +#include "SourceTreeItem.hpp" + +#include +#include #include -#include -#include -#include - -#include +#include #include -#include -#include -#include -#include -#include -#include +#include -#include -#include +#include "moc_SourceTreeItem.cpp" static inline OBSScene GetCurrentScene() { @@ -28,8 +17,6 @@ static inline OBSScene GetCurrentScene() return main->GetCurrentScene(); } -/* ========================================================================= */ - SourceTreeItem::SourceTreeItem(SourceTree *tree_, OBSSceneItem sceneitem_) : tree(tree_), sceneitem(sceneitem_) { setAttribute(Qt::WA_TranslucentBackground); @@ -555,1059 +542,3 @@ void SourceTreeItem::Deselect() OBSBasic::Get()->UpdateContextBarDeferred(); OBSBasic::Get()->UpdateEditMenu(); } - -/* ========================================================================= */ - -void SourceTreeModel::OBSFrontendEvent(enum obs_frontend_event event, void *ptr) -{ - SourceTreeModel *stm = reinterpret_cast(ptr); - - switch (event) { - case OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED: - stm->SceneChanged(); - break; - case OBS_FRONTEND_EVENT_EXIT: - stm->Clear(); - obs_frontend_remove_event_callback(OBSFrontendEvent, stm); - break; - case OBS_FRONTEND_EVENT_SCENE_COLLECTION_CLEANUP: - stm->Clear(); - break; - default: - break; - } -} - -void SourceTreeModel::Clear() -{ - beginResetModel(); - items.clear(); - endResetModel(); - - hasGroups = false; -} - -static bool enumItem(obs_scene_t *, obs_sceneitem_t *item, void *ptr) -{ - QVector &items = *reinterpret_cast *>(ptr); - - obs_source_t *src = obs_sceneitem_get_source(item); - if (obs_source_removed(src)) { - return true; - } - - if (obs_sceneitem_is_group(item)) { - OBSDataAutoRelease data = obs_sceneitem_get_private_settings(item); - - bool collapse = obs_data_get_bool(data, "collapsed"); - if (!collapse) { - obs_scene_t *scene = obs_sceneitem_group_get_scene(item); - - obs_scene_enum_items(scene, enumItem, &items); - } - } - - items.insert(0, item); - return true; -} - -void SourceTreeModel::SceneChanged() -{ - OBSScene scene = GetCurrentScene(); - - beginResetModel(); - items.clear(); - obs_scene_enum_items(scene, enumItem, &items); - endResetModel(); - - UpdateGroupState(false); - st->ResetWidgets(); - - for (int i = 0; i < items.count(); i++) { - bool select = obs_sceneitem_selected(items[i]); - QModelIndex index = createIndex(i, 0); - - st->selectionModel()->select(index, - select ? QItemSelectionModel::Select : QItemSelectionModel::Deselect); - } -} - -/* moves a scene item index (blame linux distros for using older Qt builds) */ -static inline void MoveItem(QVector &items, int oldIdx, int newIdx) -{ - OBSSceneItem item = items[oldIdx]; - items.remove(oldIdx); - items.insert(newIdx, item); -} - -/* reorders list optimally with model reorder funcs */ -void SourceTreeModel::ReorderItems() -{ - OBSScene scene = GetCurrentScene(); - - QVector newitems; - obs_scene_enum_items(scene, enumItem, &newitems); - - /* if item list has changed size, do full reset */ - if (newitems.count() != items.count()) { - SceneChanged(); - return; - } - - for (;;) { - int idx1Old = 0; - int idx1New = 0; - int count; - int i; - - /* find first starting changed item index */ - for (i = 0; i < newitems.count(); i++) { - obs_sceneitem_t *oldItem = items[i]; - obs_sceneitem_t *newItem = newitems[i]; - if (oldItem != newItem) { - idx1Old = i; - break; - } - } - - /* if everything is the same, break */ - if (i == newitems.count()) { - break; - } - - /* find new starting index */ - for (i = idx1Old + 1; i < newitems.count(); i++) { - obs_sceneitem_t *oldItem = items[idx1Old]; - obs_sceneitem_t *newItem = newitems[i]; - - if (oldItem == newItem) { - idx1New = i; - break; - } - } - - /* if item could not be found, do full reset */ - if (i == newitems.count()) { - SceneChanged(); - return; - } - - /* get move count */ - for (count = 1; (idx1New + count) < newitems.count(); count++) { - int oldIdx = idx1Old + count; - int newIdx = idx1New + count; - - obs_sceneitem_t *oldItem = items[oldIdx]; - obs_sceneitem_t *newItem = newitems[newIdx]; - - if (oldItem != newItem) { - break; - } - } - - /* move items */ - beginMoveRows(QModelIndex(), idx1Old, idx1Old + count - 1, QModelIndex(), idx1New + count); - for (i = 0; i < count; i++) { - int to = idx1New + count; - if (to > idx1Old) - to--; - MoveItem(items, idx1Old, to); - } - endMoveRows(); - } -} - -void SourceTreeModel::Add(obs_sceneitem_t *item) -{ - if (obs_sceneitem_is_group(item)) { - SceneChanged(); - } else { - beginInsertRows(QModelIndex(), 0, 0); - items.insert(0, item); - endInsertRows(); - - st->UpdateWidget(createIndex(0, 0, nullptr), item); - } -} - -void SourceTreeModel::Remove(obs_sceneitem_t *item) -{ - int idx = -1; - for (int i = 0; i < items.count(); i++) { - if (items[i] == item) { - idx = i; - break; - } - } - - if (idx == -1) - return; - - int startIdx = idx; - int endIdx = idx; - - bool is_group = obs_sceneitem_is_group(item); - if (is_group) { - obs_scene_t *scene = obs_sceneitem_group_get_scene(item); - - for (int i = endIdx + 1; i < items.count(); i++) { - obs_sceneitem_t *subitem = items[i]; - obs_scene_t *subscene = obs_sceneitem_get_scene(subitem); - - if (subscene == scene) - endIdx = i; - else - break; - } - } - - beginRemoveRows(QModelIndex(), startIdx, endIdx); - items.remove(idx, endIdx - startIdx + 1); - endRemoveRows(); - - if (is_group) - UpdateGroupState(true); - - OBSBasic::Get()->UpdateContextBarDeferred(); -} - -OBSSceneItem SourceTreeModel::Get(int idx) -{ - if (idx == -1 || idx >= items.count()) - return OBSSceneItem(); - return items[idx]; -} - -SourceTreeModel::SourceTreeModel(SourceTree *st_) : QAbstractListModel(st_), st(st_) -{ - obs_frontend_add_event_callback(OBSFrontendEvent, this); -} - -int SourceTreeModel::rowCount(const QModelIndex &parent) const -{ - return parent.isValid() ? 0 : items.count(); -} - -QVariant SourceTreeModel::data(const QModelIndex &index, int role) const -{ - if (role == Qt::AccessibleTextRole) { - OBSSceneItem item = items[index.row()]; - obs_source_t *source = obs_sceneitem_get_source(item); - return QVariant(QT_UTF8(obs_source_get_name(source))); - } - - return QVariant(); -} - -Qt::ItemFlags SourceTreeModel::flags(const QModelIndex &index) const -{ - if (!index.isValid()) - return QAbstractListModel::flags(index) | Qt::ItemIsDropEnabled; - - obs_sceneitem_t *item = items[index.row()]; - bool is_group = obs_sceneitem_is_group(item); - - return QAbstractListModel::flags(index) | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | - (is_group ? Qt::ItemIsDropEnabled : Qt::NoItemFlags); -} - -Qt::DropActions SourceTreeModel::supportedDropActions() const -{ - return QAbstractItemModel::supportedDropActions() | Qt::MoveAction; -} - -QString SourceTreeModel::GetNewGroupName() -{ - OBSScene scene = GetCurrentScene(); - QString name = QTStr("Group"); - - int i = 2; - for (;;) { - OBSSourceAutoRelease group = obs_get_source_by_name(QT_TO_UTF8(name)); - if (!group) - break; - name = QTStr("Basic.Main.Group").arg(QString::number(i++)); - } - - return name; -} - -void SourceTreeModel::AddGroup() -{ - QString name = GetNewGroupName(); - obs_sceneitem_t *group = obs_scene_add_group(GetCurrentScene(), QT_TO_UTF8(name)); - if (!group) - return; - - beginInsertRows(QModelIndex(), 0, 0); - items.insert(0, group); - endInsertRows(); - - st->UpdateWidget(createIndex(0, 0, nullptr), group); - UpdateGroupState(true); - - QMetaObject::invokeMethod(st, "Edit", Qt::QueuedConnection, Q_ARG(int, 0)); -} - -void SourceTreeModel::GroupSelectedItems(QModelIndexList &indices) -{ - if (indices.count() == 0) - return; - - OBSBasic *main = OBSBasic::Get(); - OBSScene scene = GetCurrentScene(); - QString name = GetNewGroupName(); - - QVector item_order; - - for (int i = indices.count() - 1; i >= 0; i--) { - obs_sceneitem_t *item = items[indices[i].row()]; - item_order << item; - } - - st->undoSceneData = main->BackupScene(scene); - - obs_sceneitem_t *item = obs_scene_insert_group(scene, QT_TO_UTF8(name), item_order.data(), item_order.size()); - if (!item) { - st->undoSceneData = nullptr; - return; - } - - main->undo_s.push_disabled(); - - for (obs_sceneitem_t *item : item_order) - obs_sceneitem_select(item, false); - - hasGroups = true; - st->UpdateWidgets(true); - - obs_sceneitem_select(item, true); - - /* ----------------------------------------------------------------- */ - /* obs_scene_insert_group triggers a full refresh of scene items via */ - /* the item_add signal. No need to insert a row, just edit the one */ - /* that's created automatically. */ - - int newIdx = indices[0].row(); - QMetaObject::invokeMethod(st, "NewGroupEdit", Qt::QueuedConnection, Q_ARG(int, newIdx)); -} - -void SourceTreeModel::UngroupSelectedGroups(QModelIndexList &indices) -{ - OBSBasic *main = OBSBasic::Get(); - if (indices.count() == 0) - return; - - OBSScene scene = main->GetCurrentScene(); - OBSData undoData = main->BackupScene(scene); - - for (int i = indices.count() - 1; i >= 0; i--) { - obs_sceneitem_t *item = items[indices[i].row()]; - obs_sceneitem_group_ungroup(item); - } - - SceneChanged(); - - OBSData redoData = main->BackupScene(scene); - main->CreateSceneUndoRedoAction(QTStr("Basic.Main.Ungroup"), undoData, redoData); -} - -void SourceTreeModel::ExpandGroup(obs_sceneitem_t *item) -{ - int itemIdx = items.indexOf(item); - if (itemIdx == -1) - return; - - itemIdx++; - - obs_scene_t *scene = obs_sceneitem_group_get_scene(item); - - QVector subItems; - obs_scene_enum_items(scene, enumItem, &subItems); - - if (!subItems.size()) - return; - - beginInsertRows(QModelIndex(), itemIdx, itemIdx + subItems.size() - 1); - for (int i = 0; i < subItems.size(); i++) - items.insert(i + itemIdx, subItems[i]); - endInsertRows(); - - st->UpdateWidgets(); -} - -void SourceTreeModel::CollapseGroup(obs_sceneitem_t *item) -{ - int startIdx = -1; - int endIdx = -1; - - obs_scene_t *scene = obs_sceneitem_group_get_scene(item); - - for (int i = 0; i < items.size(); i++) { - obs_scene_t *itemScene = obs_sceneitem_get_scene(items[i]); - - if (itemScene == scene) { - if (startIdx == -1) - startIdx = i; - endIdx = i; - } - } - - if (startIdx == -1) - return; - - beginRemoveRows(QModelIndex(), startIdx, endIdx); - items.remove(startIdx, endIdx - startIdx + 1); - endRemoveRows(); -} - -void SourceTreeModel::UpdateGroupState(bool update) -{ - bool nowHasGroups = false; - for (auto &item : items) { - if (obs_sceneitem_is_group(item)) { - nowHasGroups = true; - break; - } - } - - if (nowHasGroups != hasGroups) { - hasGroups = nowHasGroups; - if (update) { - st->UpdateWidgets(true); - } - } -} - -/* ========================================================================= */ - -SourceTree::SourceTree(QWidget *parent_) : QListView(parent_) -{ - SourceTreeModel *stm_ = new SourceTreeModel(this); - setModel(stm_); - setStyleSheet(QString("*[bgColor=\"1\"]{background-color:rgba(255,68,68,33%);}" - "*[bgColor=\"2\"]{background-color:rgba(255,255,68,33%);}" - "*[bgColor=\"3\"]{background-color:rgba(68,255,68,33%);}" - "*[bgColor=\"4\"]{background-color:rgba(68,255,255,33%);}" - "*[bgColor=\"5\"]{background-color:rgba(68,68,255,33%);}" - "*[bgColor=\"6\"]{background-color:rgba(255,68,255,33%);}" - "*[bgColor=\"7\"]{background-color:rgba(68,68,68,33%);}" - "*[bgColor=\"8\"]{background-color:rgba(255,255,255,33%);}")); - - UpdateNoSourcesMessage(); - connect(App(), &OBSApp::StyleChanged, this, &SourceTree::UpdateNoSourcesMessage); - connect(App(), &OBSApp::StyleChanged, this, &SourceTree::UpdateIcons); - - setItemDelegate(new SourceTreeDelegate(this)); -} - -void SourceTree::UpdateIcons() -{ - SourceTreeModel *stm = GetStm(); - stm->SceneChanged(); -} - -void SourceTree::SetIconsVisible(bool visible) -{ - SourceTreeModel *stm = GetStm(); - - iconsVisible = visible; - stm->SceneChanged(); -} - -void SourceTree::ResetWidgets() -{ - OBSScene scene = GetCurrentScene(); - - SourceTreeModel *stm = GetStm(); - stm->UpdateGroupState(false); - - for (int i = 0; i < stm->items.count(); i++) { - QModelIndex index = stm->createIndex(i, 0, nullptr); - setIndexWidget(index, new SourceTreeItem(this, stm->items[i])); - } -} - -void SourceTree::UpdateWidget(const QModelIndex &idx, obs_sceneitem_t *item) -{ - setIndexWidget(idx, new SourceTreeItem(this, item)); -} - -void SourceTree::UpdateWidgets(bool force) -{ - SourceTreeModel *stm = GetStm(); - - for (int i = 0; i < stm->items.size(); i++) { - obs_sceneitem_t *item = stm->items[i]; - SourceTreeItem *widget = GetItemWidget(i); - - if (!widget) { - UpdateWidget(stm->createIndex(i, 0), item); - } else { - widget->Update(force); - } - } -} - -void SourceTree::SelectItem(obs_sceneitem_t *sceneitem, bool select) -{ - SourceTreeModel *stm = GetStm(); - int i = 0; - - for (; i < stm->items.count(); i++) { - if (stm->items[i] == sceneitem) - break; - } - - if (i == stm->items.count()) - return; - - QModelIndex index = stm->createIndex(i, 0); - if (index.isValid() && select != selectionModel()->isSelected(index)) - selectionModel()->select(index, select ? QItemSelectionModel::Select : QItemSelectionModel::Deselect); -} - -Q_DECLARE_METATYPE(OBSSceneItem); - -void SourceTree::mouseDoubleClickEvent(QMouseEvent *event) -{ - if (event->button() == Qt::LeftButton) - QListView::mouseDoubleClickEvent(event); -} - -void SourceTree::dropEvent(QDropEvent *event) -{ - if (event->source() != this) { - QListView::dropEvent(event); - return; - } - - OBSBasic *main = OBSBasic::Get(); - - OBSScene scene = GetCurrentScene(); - obs_source_t *scenesource = obs_scene_get_source(scene); - SourceTreeModel *stm = GetStm(); - auto &items = stm->items; - QModelIndexList indices = selectedIndexes(); - - DropIndicatorPosition indicator = dropIndicatorPosition(); - int row = indexAt(event->position().toPoint()).row(); - bool emptyDrop = row == -1; - - if (emptyDrop) { - if (!items.size()) { - QListView::dropEvent(event); - return; - } - - row = items.size() - 1; - indicator = QAbstractItemView::BelowItem; - } - - /* --------------------------------------- */ - /* store destination group if moving to a */ - /* group */ - - obs_sceneitem_t *dropItem = items[row]; /* item being dropped on */ - bool itemIsGroup = obs_sceneitem_is_group(dropItem); - - obs_sceneitem_t *dropGroup = itemIsGroup ? dropItem : obs_sceneitem_get_group(scene, dropItem); - - /* not a group if moving above the group */ - if (indicator == QAbstractItemView::AboveItem && itemIsGroup) - dropGroup = nullptr; - if (emptyDrop) - dropGroup = nullptr; - - /* --------------------------------------- */ - /* remember to remove list items if */ - /* dropping on collapsed group */ - - bool dropOnCollapsed = false; - if (dropGroup) { - obs_data_t *data = obs_sceneitem_get_private_settings(dropGroup); - dropOnCollapsed = obs_data_get_bool(data, "collapsed"); - obs_data_release(data); - } - - if (indicator == QAbstractItemView::BelowItem || indicator == QAbstractItemView::OnItem || - indicator == QAbstractItemView::OnViewport) - row++; - - if (row < 0 || row > stm->items.count()) { - QListView::dropEvent(event); - return; - } - - /* --------------------------------------- */ - /* determine if any base group is selected */ - - bool hasGroups = false; - for (int i = 0; i < indices.size(); i++) { - obs_sceneitem_t *item = items[indices[i].row()]; - if (obs_sceneitem_is_group(item)) { - hasGroups = true; - break; - } - } - - /* --------------------------------------- */ - /* if dropping a group, detect if it's */ - /* below another group */ - - obs_sceneitem_t *itemBelow; - if (row == stm->items.count()) - itemBelow = nullptr; - else - itemBelow = stm->items[row]; - - if (hasGroups) { - if (!itemBelow || obs_sceneitem_get_group(scene, itemBelow) != dropGroup) { - dropGroup = nullptr; - dropOnCollapsed = false; - } - } - - /* --------------------------------------- */ - /* if dropping groups on other groups, */ - /* disregard as invalid drag/drop */ - - if (dropGroup && hasGroups) { - QListView::dropEvent(event); - return; - } - - /* --------------------------------------- */ - /* save undo data */ - std::vector sources; - for (int i = 0; i < indices.size(); i++) { - obs_sceneitem_t *item = items[indices[i].row()]; - if (obs_sceneitem_get_scene(item) != scene) - sources.push_back(obs_scene_get_source(obs_sceneitem_get_scene(item))); - } - if (dropGroup) - sources.push_back(obs_sceneitem_get_source(dropGroup)); - OBSData undo_data = main->BackupScene(scene, &sources); - - /* --------------------------------------- */ - /* if selection includes base group items, */ - /* include all group sub-items and treat */ - /* them all as one */ - - if (hasGroups) { - /* remove sub-items if selected */ - for (int i = indices.size() - 1; i >= 0; i--) { - obs_sceneitem_t *item = items[indices[i].row()]; - obs_scene_t *itemScene = obs_sceneitem_get_scene(item); - - if (itemScene != scene) { - indices.removeAt(i); - } - } - - /* add all sub-items of selected groups */ - for (int i = indices.size() - 1; i >= 0; i--) { - obs_sceneitem_t *item = items[indices[i].row()]; - - if (obs_sceneitem_is_group(item)) { - for (int j = items.size() - 1; j >= 0; j--) { - obs_sceneitem_t *subitem = items[j]; - obs_sceneitem_t *subitemGroup = obs_sceneitem_get_group(scene, subitem); - - if (subitemGroup == item) { - QModelIndex idx = stm->createIndex(j, 0); - indices.insert(i + 1, idx); - } - } - } - } - } - - /* --------------------------------------- */ - /* build persistent indices */ - - QList persistentIndices; - persistentIndices.reserve(indices.count()); - for (QModelIndex &index : indices) - persistentIndices.append(index); - std::sort(persistentIndices.begin(), persistentIndices.end()); - - /* --------------------------------------- */ - /* move all items to destination index */ - - int r = row; - for (auto &persistentIdx : persistentIndices) { - int from = persistentIdx.row(); - int to = r; - int itemTo = to; - - if (itemTo > from) - itemTo--; - - if (itemTo != from) { - stm->beginMoveRows(QModelIndex(), from, from, QModelIndex(), to); - MoveItem(items, from, itemTo); - stm->endMoveRows(); - } - - r = persistentIdx.row() + 1; - } - - std::sort(persistentIndices.begin(), persistentIndices.end()); - int firstIdx = persistentIndices.front().row(); - int lastIdx = persistentIndices.back().row(); - - /* --------------------------------------- */ - /* reorder scene items in back-end */ - - QVector orderList; - obs_sceneitem_t *lastGroup = nullptr; - int insertCollapsedIdx = 0; - - auto insertCollapsed = [&](obs_sceneitem_t *item) { - struct obs_sceneitem_order_info info; - info.group = lastGroup; - info.item = item; - - orderList.insert(insertCollapsedIdx++, info); - }; - - using insertCollapsed_t = decltype(insertCollapsed); - - auto preInsertCollapsed = [](obs_scene_t *, obs_sceneitem_t *item, void *param) { - (*reinterpret_cast(param))(item); - return true; - }; - - auto insertLastGroup = [&]() { - OBSDataAutoRelease data = obs_sceneitem_get_private_settings(lastGroup); - bool collapsed = obs_data_get_bool(data, "collapsed"); - - if (collapsed) { - insertCollapsedIdx = 0; - obs_sceneitem_group_enum_items(lastGroup, preInsertCollapsed, &insertCollapsed); - } - - struct obs_sceneitem_order_info info; - info.group = nullptr; - info.item = lastGroup; - orderList.insert(0, info); - }; - - auto updateScene = [&]() { - struct obs_sceneitem_order_info info; - - for (int i = 0; i < items.size(); i++) { - obs_sceneitem_t *item = items[i]; - obs_sceneitem_t *group; - - if (obs_sceneitem_is_group(item)) { - if (lastGroup) { - insertLastGroup(); - } - lastGroup = item; - continue; - } - - if (!hasGroups && i >= firstIdx && i <= lastIdx) - group = dropGroup; - else - group = obs_sceneitem_get_group(scene, item); - - if (lastGroup && lastGroup != group) { - insertLastGroup(); - } - - lastGroup = group; - - info.group = group; - info.item = item; - orderList.insert(0, info); - } - - if (lastGroup) { - insertLastGroup(); - } - - obs_scene_reorder_items2(scene, orderList.data(), orderList.size()); - }; - - using updateScene_t = decltype(updateScene); - - auto preUpdateScene = [](void *data, obs_scene_t *) { - (*reinterpret_cast(data))(); - }; - - ignoreReorder = true; - obs_scene_atomic_update(scene, preUpdateScene, &updateScene); - ignoreReorder = false; - - /* --------------------------------------- */ - /* save redo data */ - - OBSData redo_data = main->BackupScene(scene, &sources); - - /* --------------------------------------- */ - /* add undo/redo action */ - - const char *scene_name = obs_source_get_name(scenesource); - QString action_name = QTStr("Undo.ReorderSources").arg(scene_name); - main->CreateSceneUndoRedoAction(action_name, undo_data, redo_data); - - /* --------------------------------------- */ - /* remove items if dropped in to collapsed */ - /* group */ - - if (dropOnCollapsed) { - stm->beginRemoveRows(QModelIndex(), firstIdx, lastIdx); - items.remove(firstIdx, lastIdx - firstIdx + 1); - stm->endRemoveRows(); - } - - /* --------------------------------------- */ - /* update widgets and accept event */ - - UpdateWidgets(true); - - event->accept(); - event->setDropAction(Qt::CopyAction); - - QListView::dropEvent(event); -} - -void SourceTree::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) -{ - { - QSignalBlocker sourcesSignalBlocker(this); - SourceTreeModel *stm = GetStm(); - - QModelIndexList selectedIdxs = selected.indexes(); - QModelIndexList deselectedIdxs = deselected.indexes(); - - for (int i = 0; i < selectedIdxs.count(); i++) { - int idx = selectedIdxs[i].row(); - obs_sceneitem_select(stm->items[idx], true); - } - - for (int i = 0; i < deselectedIdxs.count(); i++) { - int idx = deselectedIdxs[i].row(); - obs_sceneitem_select(stm->items[idx], false); - } - } - QListView::selectionChanged(selected, deselected); -} - -void SourceTree::NewGroupEdit(int row) -{ - if (!Edit(row)) { - OBSBasic *main = OBSBasic::Get(); - main->undo_s.pop_disabled(); - - blog(LOG_WARNING, "Uh, somehow the edit didn't process, this " - "code should never be reached.\nAnd by " - "\"never be reached\", I mean that " - "theoretically, it should be\nimpossible " - "for this code to be reached. But if this " - "code is reached,\nfeel free to laugh at " - "Lain, because apparently it is, in fact, " - "actually\npossible for this code to be " - "reached. But I mean, again, theoretically\n" - "it should be impossible. So if you see " - "this in your log, just know that\nit's " - "really dumb, and depressing. But at least " - "the undo/redo action is\nstill covered, so " - "in theory things *should* be fine. But " - "it's entirely\npossible that they might " - "not be exactly. But again, yea. This " - "really\nshould not be possible."); - - OBSData redoSceneData = main->BackupScene(GetCurrentScene()); - - QString text = QTStr("Undo.GroupItems").arg("Unknown"); - main->CreateSceneUndoRedoAction(text, undoSceneData, redoSceneData); - - undoSceneData = nullptr; - } -} - -bool SourceTree::Edit(int row) -{ - SourceTreeModel *stm = GetStm(); - if (row < 0 || row >= stm->items.count()) - return false; - - QModelIndex index = stm->createIndex(row, 0); - QWidget *widget = indexWidget(index); - SourceTreeItem *itemWidget = reinterpret_cast(widget); - if (itemWidget->IsEditing()) { -#ifdef __APPLE__ - itemWidget->ExitEditMode(true); -#endif - return false; - } - - itemWidget->EnterEditMode(); - edit(index); - return true; -} - -bool SourceTree::MultipleBaseSelected() const -{ - SourceTreeModel *stm = GetStm(); - QModelIndexList selectedIndices = selectedIndexes(); - - OBSScene scene = GetCurrentScene(); - - if (selectedIndices.size() < 1) { - return false; - } - - for (auto &idx : selectedIndices) { - obs_sceneitem_t *item = stm->items[idx.row()]; - if (obs_sceneitem_is_group(item)) { - return false; - } - - obs_scene *itemScene = obs_sceneitem_get_scene(item); - if (itemScene != scene) { - return false; - } - } - - return true; -} - -bool SourceTree::GroupsSelected() const -{ - SourceTreeModel *stm = GetStm(); - QModelIndexList selectedIndices = selectedIndexes(); - - OBSScene scene = GetCurrentScene(); - - if (selectedIndices.size() < 1) { - return false; - } - - for (auto &idx : selectedIndices) { - obs_sceneitem_t *item = stm->items[idx.row()]; - if (!obs_sceneitem_is_group(item)) { - return false; - } - } - - return true; -} - -bool SourceTree::GroupedItemsSelected() const -{ - SourceTreeModel *stm = GetStm(); - QModelIndexList selectedIndices = selectedIndexes(); - OBSScene scene = GetCurrentScene(); - - if (!selectedIndices.size()) { - return false; - } - - for (auto &idx : selectedIndices) { - obs_sceneitem_t *item = stm->items[idx.row()]; - obs_scene *itemScene = obs_sceneitem_get_scene(item); - - if (itemScene != scene) { - return true; - } - } - - return false; -} - -void SourceTree::Remove(OBSSceneItem item, OBSScene scene) -{ - OBSBasic *main = reinterpret_cast(App()->GetMainWindow()); - GetStm()->Remove(item); - main->SaveProject(); - - if (!main->SavingDisabled()) { - obs_source_t *sceneSource = obs_scene_get_source(scene); - obs_source_t *itemSource = obs_sceneitem_get_source(item); - blog(LOG_INFO, "User Removed source '%s' (%s) from scene '%s'", obs_source_get_name(itemSource), - obs_source_get_id(itemSource), obs_source_get_name(sceneSource)); - } -} - -void SourceTree::GroupSelectedItems() -{ - QModelIndexList indices = selectedIndexes(); - std::sort(indices.begin(), indices.end()); - GetStm()->GroupSelectedItems(indices); -} - -void SourceTree::UngroupSelectedGroups() -{ - QModelIndexList indices = selectedIndexes(); - GetStm()->UngroupSelectedGroups(indices); -} - -void SourceTree::AddGroup() -{ - GetStm()->AddGroup(); -} - -void SourceTree::UpdateNoSourcesMessage() -{ - QString file = !App()->IsThemeDark() ? ":res/images/no_sources.svg" : "theme:Dark/no_sources.svg"; - iconNoSources.load(file); - - QTextOption opt(Qt::AlignHCenter); - opt.setWrapMode(QTextOption::WordWrap); - textNoSources.setTextOption(opt); - textNoSources.setText(QTStr("NoSources.Label").replace("\n", "
")); - - textPrepared = false; -} - -void SourceTree::paintEvent(QPaintEvent *event) -{ - SourceTreeModel *stm = GetStm(); - if (stm && !stm->items.count()) { - QPainter p(viewport()); - - if (!textPrepared) { - textNoSources.prepare(QTransform(), p.font()); - textPrepared = true; - } - - QRectF iconRect = iconNoSources.viewBoxF(); - iconRect.setSize(QSizeF(32.0, 32.0)); - - QSizeF iconSize = iconRect.size(); - QSizeF textSize = textNoSources.size(); - QSizeF thisSize = size(); - const qreal spacing = 16.0; - - qreal totalHeight = iconSize.height() + spacing + textSize.height(); - - qreal x = thisSize.width() / 2.0 - iconSize.width() / 2.0; - qreal y = thisSize.height() / 2.0 - totalHeight / 2.0; - iconRect.moveTo(std::round(x), std::round(y)); - iconNoSources.render(&p, iconRect); - - x = thisSize.width() / 2.0 - textSize.width() / 2.0; - y += spacing + iconSize.height(); - p.drawStaticText(x, y, textNoSources); - } else { - QListView::paintEvent(event); - } -} - -SourceTreeDelegate::SourceTreeDelegate(QObject *parent) : QStyledItemDelegate(parent) {} - -QSize SourceTreeDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const -{ - SourceTree *tree = qobject_cast(parent()); - QWidget *item = tree->indexWidget(index); - - if (!item) - return (QSize(0, 0)); - - return (QSize(option.widget->minimumWidth(), item->height())); -} diff --git a/frontend/components/SourceTreeItem.hpp b/frontend/components/SourceTreeItem.hpp index 8f8922d52..38f981882 100644 --- a/frontend/components/SourceTreeItem.hpp +++ b/frontend/components/SourceTreeItem.hpp @@ -1,25 +1,17 @@ #pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -class QLabel; -class OBSSourceLabel; -class QCheckBox; -class QLineEdit; -class SourceTree; +#include + class QSpacerItem; +class QCheckBox; +class QLabel; class QHBoxLayout; -class VisibilityItemWidget; +class OBSSourceLabel; +class QLineEdit; + +class SourceTree; class SourceTreeItem : public QFrame { Q_OBJECT @@ -86,117 +78,3 @@ private slots: void Select(); void Deselect(); }; - -class SourceTreeModel : public QAbstractListModel { - Q_OBJECT - - friend class SourceTree; - friend class SourceTreeItem; - - SourceTree *st; - QVector items; - bool hasGroups = false; - - static void OBSFrontendEvent(enum obs_frontend_event event, void *ptr); - void Clear(); - void SceneChanged(); - void ReorderItems(); - - void Add(obs_sceneitem_t *item); - void Remove(obs_sceneitem_t *item); - OBSSceneItem Get(int idx); - QString GetNewGroupName(); - void AddGroup(); - - void GroupSelectedItems(QModelIndexList &indices); - void UngroupSelectedGroups(QModelIndexList &indices); - - void ExpandGroup(obs_sceneitem_t *item); - void CollapseGroup(obs_sceneitem_t *item); - - void UpdateGroupState(bool update); - -public: - explicit SourceTreeModel(SourceTree *st); - - virtual int rowCount(const QModelIndex &parent) const override; - virtual QVariant data(const QModelIndex &index, int role) const override; - - virtual Qt::ItemFlags flags(const QModelIndex &index) const override; - virtual Qt::DropActions supportedDropActions() const override; -}; - -class SourceTree : public QListView { - Q_OBJECT - - bool ignoreReorder = false; - - friend class SourceTreeModel; - friend class SourceTreeItem; - - bool textPrepared = false; - QStaticText textNoSources; - QSvgRenderer iconNoSources; - - OBSData undoSceneData; - - bool iconsVisible = true; - - void UpdateNoSourcesMessage(); - - void ResetWidgets(); - void UpdateWidget(const QModelIndex &idx, obs_sceneitem_t *item); - void UpdateWidgets(bool force = false); - - inline SourceTreeModel *GetStm() const { return reinterpret_cast(model()); } - -public: - inline SourceTreeItem *GetItemWidget(int idx) - { - QWidget *widget = indexWidget(GetStm()->createIndex(idx, 0)); - return reinterpret_cast(widget); - } - - explicit SourceTree(QWidget *parent = nullptr); - - inline bool IgnoreReorder() const { return ignoreReorder; } - inline void Clear() { GetStm()->Clear(); } - - inline void Add(obs_sceneitem_t *item) { GetStm()->Add(item); } - inline OBSSceneItem Get(int idx) { return GetStm()->Get(idx); } - inline QString GetNewGroupName() { return GetStm()->GetNewGroupName(); } - - void SelectItem(obs_sceneitem_t *sceneitem, bool select); - - bool MultipleBaseSelected() const; - bool GroupsSelected() const; - bool GroupedItemsSelected() const; - - void UpdateIcons(); - void SetIconsVisible(bool visible); - -public slots: - inline void ReorderItems() { GetStm()->ReorderItems(); } - inline void RefreshItems() { GetStm()->SceneChanged(); } - void Remove(OBSSceneItem item, OBSScene scene); - void GroupSelectedItems(); - void UngroupSelectedGroups(); - void AddGroup(); - bool Edit(int idx); - void NewGroupEdit(int idx); - -protected: - virtual void mouseDoubleClickEvent(QMouseEvent *event) override; - virtual void dropEvent(QDropEvent *event) override; - virtual void paintEvent(QPaintEvent *event) override; - - virtual void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) override; -}; - -class SourceTreeDelegate : public QStyledItemDelegate { - Q_OBJECT - -public: - SourceTreeDelegate(QObject *parent); - virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; -}; diff --git a/frontend/components/SourceTreeModel.cpp b/frontend/components/SourceTreeModel.cpp index a0242e3cd..61e13d52b 100644 --- a/frontend/components/SourceTreeModel.cpp +++ b/frontend/components/SourceTreeModel.cpp @@ -1,26 +1,10 @@ -#include "window-basic-main.hpp" -#include "obs-app.hpp" -#include "source-tree.hpp" -#include "platform.hpp" -#include "source-label.hpp" +#include "SourceTreeModel.hpp" + +#include #include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include +#include "moc_SourceTreeModel.cpp" static inline OBSScene GetCurrentScene() { @@ -28,536 +12,6 @@ static inline OBSScene GetCurrentScene() return main->GetCurrentScene(); } -/* ========================================================================= */ - -SourceTreeItem::SourceTreeItem(SourceTree *tree_, OBSSceneItem sceneitem_) : tree(tree_), sceneitem(sceneitem_) -{ - setAttribute(Qt::WA_TranslucentBackground); - setMouseTracking(true); - - obs_source_t *source = obs_sceneitem_get_source(sceneitem); - const char *name = obs_source_get_name(source); - - OBSDataAutoRelease privData = obs_sceneitem_get_private_settings(sceneitem); - int preset = obs_data_get_int(privData, "color-preset"); - - if (preset == 1) { - const char *color = obs_data_get_string(privData, "color"); - std::string col = "background: "; - col += color; - setStyleSheet(col.c_str()); - } else if (preset > 1) { - setStyleSheet(""); - setProperty("bgColor", preset - 1); - } else { - setStyleSheet("background: none"); - } - - OBSBasic *main = reinterpret_cast(App()->GetMainWindow()); - const char *id = obs_source_get_id(source); - - bool sourceVisible = obs_sceneitem_visible(sceneitem); - - if (tree->iconsVisible) { - QIcon icon; - - if (strcmp(id, "scene") == 0) - icon = main->GetSceneIcon(); - else if (strcmp(id, "group") == 0) - icon = main->GetGroupIcon(); - else - icon = main->GetSourceIcon(id); - - QPixmap pixmap = icon.pixmap(QSize(16, 16)); - - iconLabel = new QLabel(); - iconLabel->setPixmap(pixmap); - iconLabel->setEnabled(sourceVisible); - iconLabel->setStyleSheet("background: none"); - iconLabel->setProperty("class", "source-icon"); - } - - vis = new QCheckBox(); - vis->setProperty("class", "checkbox-icon indicator-visibility"); - vis->setChecked(sourceVisible); - vis->setAccessibleName(QTStr("Basic.Main.Sources.Visibility")); - vis->setAccessibleDescription(QTStr("Basic.Main.Sources.VisibilityDescription").arg(name)); - - lock = new QCheckBox(); - lock->setProperty("class", "checkbox-icon indicator-lock"); - lock->setChecked(obs_sceneitem_locked(sceneitem)); - lock->setAccessibleName(QTStr("Basic.Main.Sources.Lock")); - lock->setAccessibleDescription(QTStr("Basic.Main.Sources.LockDescription").arg(name)); - - label = new OBSSourceLabel(source); - label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); - label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); - label->setAttribute(Qt::WA_TranslucentBackground); - label->setEnabled(sourceVisible); - -#ifdef __APPLE__ - vis->setAttribute(Qt::WA_LayoutUsesWidgetRect); - lock->setAttribute(Qt::WA_LayoutUsesWidgetRect); -#endif - - boxLayout = new QHBoxLayout(); - - boxLayout->setContentsMargins(0, 0, 0, 0); - boxLayout->setSpacing(0); - if (iconLabel) { - boxLayout->addWidget(iconLabel); - boxLayout->addSpacing(2); - } - boxLayout->addWidget(label); - boxLayout->addWidget(vis); - boxLayout->addWidget(lock); -#ifdef __APPLE__ - /* Hack: Fixes a bug where scrollbars would be above the lock icon */ - boxLayout->addSpacing(16); -#endif - - Update(false); - - setLayout(boxLayout); - - /* --------------------------------------------------------- */ - - auto setItemVisible = [this](bool val) { - obs_scene_t *scene = obs_sceneitem_get_scene(sceneitem); - obs_source_t *scenesource = obs_scene_get_source(scene); - int64_t id = obs_sceneitem_get_id(sceneitem); - const char *name = obs_source_get_name(scenesource); - const char *uuid = obs_source_get_uuid(scenesource); - obs_source_t *source = obs_sceneitem_get_source(sceneitem); - - auto undo_redo = [](const std::string &uuid, int64_t id, bool val) { - OBSSourceAutoRelease s = obs_get_source_by_uuid(uuid.c_str()); - obs_scene_t *sc = obs_group_or_scene_from_source(s); - obs_sceneitem_t *si = obs_scene_find_sceneitem_by_id(sc, id); - if (si) - obs_sceneitem_set_visible(si, val); - }; - - QString str = QTStr(val ? "Undo.ShowSceneItem" : "Undo.HideSceneItem"); - - OBSBasic *main = OBSBasic::Get(); - main->undo_s.add_action(str.arg(obs_source_get_name(source), name), - std::bind(undo_redo, std::placeholders::_1, id, !val), - std::bind(undo_redo, std::placeholders::_1, id, val), uuid, uuid); - - QSignalBlocker sourcesSignalBlocker(this); - obs_sceneitem_set_visible(sceneitem, val); - }; - - auto setItemLocked = [this](bool checked) { - QSignalBlocker sourcesSignalBlocker(this); - obs_sceneitem_set_locked(sceneitem, checked); - }; - - connect(vis, &QAbstractButton::clicked, setItemVisible); - connect(lock, &QAbstractButton::clicked, setItemLocked); -} - -void SourceTreeItem::paintEvent(QPaintEvent *event) -{ - QStyleOption opt; - opt.initFrom(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); - - QWidget::paintEvent(event); -} - -void SourceTreeItem::DisconnectSignals() -{ - sigs.clear(); -} - -void SourceTreeItem::Clear() -{ - DisconnectSignals(); - sceneitem = nullptr; -} - -void SourceTreeItem::ReconnectSignals() -{ - if (!sceneitem) - return; - - DisconnectSignals(); - - /* --------------------------------------------------------- */ - - auto removeItem = [](void *data, calldata_t *cd) { - SourceTreeItem *this_ = reinterpret_cast(data); - obs_sceneitem_t *curItem = (obs_sceneitem_t *)calldata_ptr(cd, "item"); - obs_scene_t *curScene = (obs_scene_t *)calldata_ptr(cd, "scene"); - - if (curItem == this_->sceneitem) { - QMetaObject::invokeMethod(this_->tree, "Remove", Q_ARG(OBSSceneItem, curItem), - Q_ARG(OBSScene, curScene)); - curItem = nullptr; - } - if (!curItem) - QMetaObject::invokeMethod(this_, "Clear"); - }; - - auto itemVisible = [](void *data, calldata_t *cd) { - SourceTreeItem *this_ = reinterpret_cast(data); - obs_sceneitem_t *curItem = (obs_sceneitem_t *)calldata_ptr(cd, "item"); - bool visible = calldata_bool(cd, "visible"); - - if (curItem == this_->sceneitem) - QMetaObject::invokeMethod(this_, "VisibilityChanged", Q_ARG(bool, visible)); - }; - - auto itemLocked = [](void *data, calldata_t *cd) { - SourceTreeItem *this_ = reinterpret_cast(data); - obs_sceneitem_t *curItem = (obs_sceneitem_t *)calldata_ptr(cd, "item"); - bool locked = calldata_bool(cd, "locked"); - - if (curItem == this_->sceneitem) - QMetaObject::invokeMethod(this_, "LockedChanged", Q_ARG(bool, locked)); - }; - - auto itemSelect = [](void *data, calldata_t *cd) { - SourceTreeItem *this_ = reinterpret_cast(data); - obs_sceneitem_t *curItem = (obs_sceneitem_t *)calldata_ptr(cd, "item"); - - if (curItem == this_->sceneitem) - QMetaObject::invokeMethod(this_, "Select"); - }; - - auto itemDeselect = [](void *data, calldata_t *cd) { - SourceTreeItem *this_ = reinterpret_cast(data); - obs_sceneitem_t *curItem = (obs_sceneitem_t *)calldata_ptr(cd, "item"); - - if (curItem == this_->sceneitem) - QMetaObject::invokeMethod(this_, "Deselect"); - }; - - auto reorderGroup = [](void *data, calldata_t *) { - SourceTreeItem *this_ = reinterpret_cast(data); - QMetaObject::invokeMethod(this_->tree, "ReorderItems"); - }; - - obs_scene_t *scene = obs_sceneitem_get_scene(sceneitem); - obs_source_t *sceneSource = obs_scene_get_source(scene); - signal_handler_t *signal = obs_source_get_signal_handler(sceneSource); - - sigs.emplace_back(signal, "remove", removeItem, this); - sigs.emplace_back(signal, "item_remove", removeItem, this); - sigs.emplace_back(signal, "item_visible", itemVisible, this); - sigs.emplace_back(signal, "item_locked", itemLocked, this); - sigs.emplace_back(signal, "item_select", itemSelect, this); - sigs.emplace_back(signal, "item_deselect", itemDeselect, this); - - if (obs_sceneitem_is_group(sceneitem)) { - obs_source_t *source = obs_sceneitem_get_source(sceneitem); - signal = obs_source_get_signal_handler(source); - - sigs.emplace_back(signal, "reorder", reorderGroup, this); - } - - /* --------------------------------------------------------- */ - - auto removeSource = [](void *data, calldata_t *) { - SourceTreeItem *this_ = reinterpret_cast(data); - this_->DisconnectSignals(); - this_->sceneitem = nullptr; - QMetaObject::invokeMethod(this_->tree, "RefreshItems"); - }; - - obs_source_t *source = obs_sceneitem_get_source(sceneitem); - signal = obs_source_get_signal_handler(source); - sigs.emplace_back(signal, "remove", removeSource, this); -} - -void SourceTreeItem::mouseDoubleClickEvent(QMouseEvent *event) -{ - QWidget::mouseDoubleClickEvent(event); - - if (expand) { - expand->setChecked(!expand->isChecked()); - } else { - obs_source_t *source = obs_sceneitem_get_source(sceneitem); - OBSBasic *main = reinterpret_cast(App()->GetMainWindow()); - if (obs_source_configurable(source)) { - main->CreatePropertiesWindow(source); - } - } -} - -void SourceTreeItem::enterEvent(QEnterEvent *event) -{ - QWidget::enterEvent(event); - - OBSBasicPreview *preview = OBSBasicPreview::Get(); - - std::lock_guard lock(preview->selectMutex); - preview->hoveredPreviewItems.clear(); - preview->hoveredPreviewItems.push_back(sceneitem); -} - -void SourceTreeItem::leaveEvent(QEvent *event) -{ - QWidget::leaveEvent(event); - - OBSBasicPreview *preview = OBSBasicPreview::Get(); - - std::lock_guard lock(preview->selectMutex); - preview->hoveredPreviewItems.clear(); -} - -bool SourceTreeItem::IsEditing() -{ - return editor != nullptr; -} - -void SourceTreeItem::EnterEditMode() -{ - setFocusPolicy(Qt::StrongFocus); - int index = boxLayout->indexOf(label); - boxLayout->removeWidget(label); - editor = new QLineEdit(label->text()); - editor->setStyleSheet("background: none"); - editor->selectAll(); - editor->installEventFilter(this); - boxLayout->insertWidget(index, editor); - setFocusProxy(editor); -} - -void SourceTreeItem::ExitEditMode(bool save) -{ - ExitEditModeInternal(save); - - if (tree->undoSceneData) { - OBSBasic *main = OBSBasic::Get(); - main->undo_s.pop_disabled(); - - OBSData redoSceneData = main->BackupScene(GetCurrentScene()); - - QString text = QTStr("Undo.GroupItems").arg(newName.c_str()); - main->CreateSceneUndoRedoAction(text, tree->undoSceneData, redoSceneData); - - tree->undoSceneData = nullptr; - } -} - -void SourceTreeItem::ExitEditModeInternal(bool save) -{ - if (!editor) { - return; - } - - OBSBasic *main = reinterpret_cast(App()->GetMainWindow()); - OBSScene scene = main->GetCurrentScene(); - - newName = QT_TO_UTF8(editor->text()); - - setFocusProxy(nullptr); - int index = boxLayout->indexOf(editor); - boxLayout->removeWidget(editor); - delete editor; - editor = nullptr; - setFocusPolicy(Qt::NoFocus); - boxLayout->insertWidget(index, label); - setFocus(); - - /* ----------------------------------------- */ - /* check for empty string */ - - if (!save) - return; - - if (newName.empty()) { - OBSMessageBox::information(main, QTStr("NoNameEntered.Title"), QTStr("NoNameEntered.Text")); - return; - } - - /* ----------------------------------------- */ - /* Check for same name */ - - obs_source_t *source = obs_sceneitem_get_source(sceneitem); - if (newName == obs_source_get_name(source)) - return; - - /* ----------------------------------------- */ - /* check for existing source */ - - OBSSourceAutoRelease existingSource = obs_get_source_by_name(newName.c_str()); - bool exists = !!existingSource; - - if (exists) { - OBSMessageBox::information(main, QTStr("NameExists.Title"), QTStr("NameExists.Text")); - return; - } - - /* ----------------------------------------- */ - /* rename */ - - QSignalBlocker sourcesSignalBlocker(this); - std::string prevName(obs_source_get_name(source)); - std::string scene_uuid = obs_source_get_uuid(main->GetCurrentSceneSource()); - auto undo = [scene_uuid, prevName, main](const std::string &data) { - OBSSourceAutoRelease source = obs_get_source_by_uuid(data.c_str()); - obs_source_set_name(source, prevName.c_str()); - - OBSSourceAutoRelease scene_source = obs_get_source_by_uuid(scene_uuid.c_str()); - main->SetCurrentScene(scene_source.Get(), true); - }; - - std::string editedName = newName; - - auto redo = [scene_uuid, main, editedName](const std::string &data) { - OBSSourceAutoRelease source = obs_get_source_by_uuid(data.c_str()); - obs_source_set_name(source, editedName.c_str()); - - OBSSourceAutoRelease scene_source = obs_get_source_by_uuid(scene_uuid.c_str()); - main->SetCurrentScene(scene_source.Get(), true); - }; - - const char *uuid = obs_source_get_uuid(source); - main->undo_s.add_action(QTStr("Undo.Rename").arg(newName.c_str()), undo, redo, uuid, uuid); - - obs_source_set_name(source, newName.c_str()); -} - -bool SourceTreeItem::eventFilter(QObject *object, QEvent *event) -{ - if (editor != object) - return false; - - if (LineEditCanceled(event)) { - QMetaObject::invokeMethod(this, "ExitEditMode", Qt::QueuedConnection, Q_ARG(bool, false)); - return true; - } - if (LineEditChanged(event)) { - QMetaObject::invokeMethod(this, "ExitEditMode", Qt::QueuedConnection, Q_ARG(bool, true)); - return true; - } - - return false; -} - -void SourceTreeItem::VisibilityChanged(bool visible) -{ - if (iconLabel) { - iconLabel->setEnabled(visible); - } - label->setEnabled(visible); - vis->setChecked(visible); -} - -void SourceTreeItem::LockedChanged(bool locked) -{ - lock->setChecked(locked); - OBSBasic::Get()->UpdateEditMenu(); -} - -void SourceTreeItem::Update(bool force) -{ - OBSScene scene = GetCurrentScene(); - obs_scene_t *itemScene = obs_sceneitem_get_scene(sceneitem); - - Type newType; - - /* ------------------------------------------------- */ - /* if it's a group item, insert group checkbox */ - - if (obs_sceneitem_is_group(sceneitem)) { - newType = Type::Group; - - /* ------------------------------------------------- */ - /* if it's a group sub-item */ - - } else if (itemScene != scene) { - newType = Type::SubItem; - - /* ------------------------------------------------- */ - /* if it's a regular item */ - - } else { - newType = Type::Item; - } - - /* ------------------------------------------------- */ - - if (!force && newType == type) { - return; - } - - /* ------------------------------------------------- */ - - ReconnectSignals(); - - if (spacer) { - boxLayout->removeItem(spacer); - delete spacer; - spacer = nullptr; - } - - if (type == Type::Group) { - boxLayout->removeWidget(expand); - expand->deleteLater(); - expand = nullptr; - } - - type = newType; - - if (type == Type::SubItem) { - spacer = new QSpacerItem(16, 1); - boxLayout->insertItem(0, spacer); - - } else if (type == Type::Group) { - expand = new QCheckBox(); - expand->setProperty("class", "checkbox-icon indicator-expand"); -#ifdef __APPLE__ - expand->setAttribute(Qt::WA_LayoutUsesWidgetRect); -#endif - boxLayout->insertWidget(0, expand); - - OBSDataAutoRelease data = obs_sceneitem_get_private_settings(sceneitem); - expand->blockSignals(true); - expand->setChecked(obs_data_get_bool(data, "collapsed")); - expand->blockSignals(false); - - connect(expand, &QPushButton::toggled, this, &SourceTreeItem::ExpandClicked); - - } else { - spacer = new QSpacerItem(3, 1); - boxLayout->insertItem(0, spacer); - } -} - -void SourceTreeItem::ExpandClicked(bool checked) -{ - OBSDataAutoRelease data = obs_sceneitem_get_private_settings(sceneitem); - - obs_data_set_bool(data, "collapsed", checked); - - if (!checked) - tree->GetStm()->ExpandGroup(sceneitem); - else - tree->GetStm()->CollapseGroup(sceneitem); -} - -void SourceTreeItem::Select() -{ - tree->SelectItem(sceneitem, true); - OBSBasic::Get()->UpdateContextBarDeferred(); - OBSBasic::Get()->UpdateEditMenu(); -} - -void SourceTreeItem::Deselect() -{ - tree->SelectItem(sceneitem, false); - OBSBasic::Get()->UpdateContextBarDeferred(); - OBSBasic::Get()->UpdateEditMenu(); -} - -/* ========================================================================= */ - void SourceTreeModel::OBSFrontendEvent(enum obs_frontend_event event, void *ptr) { SourceTreeModel *stm = reinterpret_cast(ptr); @@ -978,636 +432,3 @@ void SourceTreeModel::UpdateGroupState(bool update) } } } - -/* ========================================================================= */ - -SourceTree::SourceTree(QWidget *parent_) : QListView(parent_) -{ - SourceTreeModel *stm_ = new SourceTreeModel(this); - setModel(stm_); - setStyleSheet(QString("*[bgColor=\"1\"]{background-color:rgba(255,68,68,33%);}" - "*[bgColor=\"2\"]{background-color:rgba(255,255,68,33%);}" - "*[bgColor=\"3\"]{background-color:rgba(68,255,68,33%);}" - "*[bgColor=\"4\"]{background-color:rgba(68,255,255,33%);}" - "*[bgColor=\"5\"]{background-color:rgba(68,68,255,33%);}" - "*[bgColor=\"6\"]{background-color:rgba(255,68,255,33%);}" - "*[bgColor=\"7\"]{background-color:rgba(68,68,68,33%);}" - "*[bgColor=\"8\"]{background-color:rgba(255,255,255,33%);}")); - - UpdateNoSourcesMessage(); - connect(App(), &OBSApp::StyleChanged, this, &SourceTree::UpdateNoSourcesMessage); - connect(App(), &OBSApp::StyleChanged, this, &SourceTree::UpdateIcons); - - setItemDelegate(new SourceTreeDelegate(this)); -} - -void SourceTree::UpdateIcons() -{ - SourceTreeModel *stm = GetStm(); - stm->SceneChanged(); -} - -void SourceTree::SetIconsVisible(bool visible) -{ - SourceTreeModel *stm = GetStm(); - - iconsVisible = visible; - stm->SceneChanged(); -} - -void SourceTree::ResetWidgets() -{ - OBSScene scene = GetCurrentScene(); - - SourceTreeModel *stm = GetStm(); - stm->UpdateGroupState(false); - - for (int i = 0; i < stm->items.count(); i++) { - QModelIndex index = stm->createIndex(i, 0, nullptr); - setIndexWidget(index, new SourceTreeItem(this, stm->items[i])); - } -} - -void SourceTree::UpdateWidget(const QModelIndex &idx, obs_sceneitem_t *item) -{ - setIndexWidget(idx, new SourceTreeItem(this, item)); -} - -void SourceTree::UpdateWidgets(bool force) -{ - SourceTreeModel *stm = GetStm(); - - for (int i = 0; i < stm->items.size(); i++) { - obs_sceneitem_t *item = stm->items[i]; - SourceTreeItem *widget = GetItemWidget(i); - - if (!widget) { - UpdateWidget(stm->createIndex(i, 0), item); - } else { - widget->Update(force); - } - } -} - -void SourceTree::SelectItem(obs_sceneitem_t *sceneitem, bool select) -{ - SourceTreeModel *stm = GetStm(); - int i = 0; - - for (; i < stm->items.count(); i++) { - if (stm->items[i] == sceneitem) - break; - } - - if (i == stm->items.count()) - return; - - QModelIndex index = stm->createIndex(i, 0); - if (index.isValid() && select != selectionModel()->isSelected(index)) - selectionModel()->select(index, select ? QItemSelectionModel::Select : QItemSelectionModel::Deselect); -} - -Q_DECLARE_METATYPE(OBSSceneItem); - -void SourceTree::mouseDoubleClickEvent(QMouseEvent *event) -{ - if (event->button() == Qt::LeftButton) - QListView::mouseDoubleClickEvent(event); -} - -void SourceTree::dropEvent(QDropEvent *event) -{ - if (event->source() != this) { - QListView::dropEvent(event); - return; - } - - OBSBasic *main = OBSBasic::Get(); - - OBSScene scene = GetCurrentScene(); - obs_source_t *scenesource = obs_scene_get_source(scene); - SourceTreeModel *stm = GetStm(); - auto &items = stm->items; - QModelIndexList indices = selectedIndexes(); - - DropIndicatorPosition indicator = dropIndicatorPosition(); - int row = indexAt(event->position().toPoint()).row(); - bool emptyDrop = row == -1; - - if (emptyDrop) { - if (!items.size()) { - QListView::dropEvent(event); - return; - } - - row = items.size() - 1; - indicator = QAbstractItemView::BelowItem; - } - - /* --------------------------------------- */ - /* store destination group if moving to a */ - /* group */ - - obs_sceneitem_t *dropItem = items[row]; /* item being dropped on */ - bool itemIsGroup = obs_sceneitem_is_group(dropItem); - - obs_sceneitem_t *dropGroup = itemIsGroup ? dropItem : obs_sceneitem_get_group(scene, dropItem); - - /* not a group if moving above the group */ - if (indicator == QAbstractItemView::AboveItem && itemIsGroup) - dropGroup = nullptr; - if (emptyDrop) - dropGroup = nullptr; - - /* --------------------------------------- */ - /* remember to remove list items if */ - /* dropping on collapsed group */ - - bool dropOnCollapsed = false; - if (dropGroup) { - obs_data_t *data = obs_sceneitem_get_private_settings(dropGroup); - dropOnCollapsed = obs_data_get_bool(data, "collapsed"); - obs_data_release(data); - } - - if (indicator == QAbstractItemView::BelowItem || indicator == QAbstractItemView::OnItem || - indicator == QAbstractItemView::OnViewport) - row++; - - if (row < 0 || row > stm->items.count()) { - QListView::dropEvent(event); - return; - } - - /* --------------------------------------- */ - /* determine if any base group is selected */ - - bool hasGroups = false; - for (int i = 0; i < indices.size(); i++) { - obs_sceneitem_t *item = items[indices[i].row()]; - if (obs_sceneitem_is_group(item)) { - hasGroups = true; - break; - } - } - - /* --------------------------------------- */ - /* if dropping a group, detect if it's */ - /* below another group */ - - obs_sceneitem_t *itemBelow; - if (row == stm->items.count()) - itemBelow = nullptr; - else - itemBelow = stm->items[row]; - - if (hasGroups) { - if (!itemBelow || obs_sceneitem_get_group(scene, itemBelow) != dropGroup) { - dropGroup = nullptr; - dropOnCollapsed = false; - } - } - - /* --------------------------------------- */ - /* if dropping groups on other groups, */ - /* disregard as invalid drag/drop */ - - if (dropGroup && hasGroups) { - QListView::dropEvent(event); - return; - } - - /* --------------------------------------- */ - /* save undo data */ - std::vector sources; - for (int i = 0; i < indices.size(); i++) { - obs_sceneitem_t *item = items[indices[i].row()]; - if (obs_sceneitem_get_scene(item) != scene) - sources.push_back(obs_scene_get_source(obs_sceneitem_get_scene(item))); - } - if (dropGroup) - sources.push_back(obs_sceneitem_get_source(dropGroup)); - OBSData undo_data = main->BackupScene(scene, &sources); - - /* --------------------------------------- */ - /* if selection includes base group items, */ - /* include all group sub-items and treat */ - /* them all as one */ - - if (hasGroups) { - /* remove sub-items if selected */ - for (int i = indices.size() - 1; i >= 0; i--) { - obs_sceneitem_t *item = items[indices[i].row()]; - obs_scene_t *itemScene = obs_sceneitem_get_scene(item); - - if (itemScene != scene) { - indices.removeAt(i); - } - } - - /* add all sub-items of selected groups */ - for (int i = indices.size() - 1; i >= 0; i--) { - obs_sceneitem_t *item = items[indices[i].row()]; - - if (obs_sceneitem_is_group(item)) { - for (int j = items.size() - 1; j >= 0; j--) { - obs_sceneitem_t *subitem = items[j]; - obs_sceneitem_t *subitemGroup = obs_sceneitem_get_group(scene, subitem); - - if (subitemGroup == item) { - QModelIndex idx = stm->createIndex(j, 0); - indices.insert(i + 1, idx); - } - } - } - } - } - - /* --------------------------------------- */ - /* build persistent indices */ - - QList persistentIndices; - persistentIndices.reserve(indices.count()); - for (QModelIndex &index : indices) - persistentIndices.append(index); - std::sort(persistentIndices.begin(), persistentIndices.end()); - - /* --------------------------------------- */ - /* move all items to destination index */ - - int r = row; - for (auto &persistentIdx : persistentIndices) { - int from = persistentIdx.row(); - int to = r; - int itemTo = to; - - if (itemTo > from) - itemTo--; - - if (itemTo != from) { - stm->beginMoveRows(QModelIndex(), from, from, QModelIndex(), to); - MoveItem(items, from, itemTo); - stm->endMoveRows(); - } - - r = persistentIdx.row() + 1; - } - - std::sort(persistentIndices.begin(), persistentIndices.end()); - int firstIdx = persistentIndices.front().row(); - int lastIdx = persistentIndices.back().row(); - - /* --------------------------------------- */ - /* reorder scene items in back-end */ - - QVector orderList; - obs_sceneitem_t *lastGroup = nullptr; - int insertCollapsedIdx = 0; - - auto insertCollapsed = [&](obs_sceneitem_t *item) { - struct obs_sceneitem_order_info info; - info.group = lastGroup; - info.item = item; - - orderList.insert(insertCollapsedIdx++, info); - }; - - using insertCollapsed_t = decltype(insertCollapsed); - - auto preInsertCollapsed = [](obs_scene_t *, obs_sceneitem_t *item, void *param) { - (*reinterpret_cast(param))(item); - return true; - }; - - auto insertLastGroup = [&]() { - OBSDataAutoRelease data = obs_sceneitem_get_private_settings(lastGroup); - bool collapsed = obs_data_get_bool(data, "collapsed"); - - if (collapsed) { - insertCollapsedIdx = 0; - obs_sceneitem_group_enum_items(lastGroup, preInsertCollapsed, &insertCollapsed); - } - - struct obs_sceneitem_order_info info; - info.group = nullptr; - info.item = lastGroup; - orderList.insert(0, info); - }; - - auto updateScene = [&]() { - struct obs_sceneitem_order_info info; - - for (int i = 0; i < items.size(); i++) { - obs_sceneitem_t *item = items[i]; - obs_sceneitem_t *group; - - if (obs_sceneitem_is_group(item)) { - if (lastGroup) { - insertLastGroup(); - } - lastGroup = item; - continue; - } - - if (!hasGroups && i >= firstIdx && i <= lastIdx) - group = dropGroup; - else - group = obs_sceneitem_get_group(scene, item); - - if (lastGroup && lastGroup != group) { - insertLastGroup(); - } - - lastGroup = group; - - info.group = group; - info.item = item; - orderList.insert(0, info); - } - - if (lastGroup) { - insertLastGroup(); - } - - obs_scene_reorder_items2(scene, orderList.data(), orderList.size()); - }; - - using updateScene_t = decltype(updateScene); - - auto preUpdateScene = [](void *data, obs_scene_t *) { - (*reinterpret_cast(data))(); - }; - - ignoreReorder = true; - obs_scene_atomic_update(scene, preUpdateScene, &updateScene); - ignoreReorder = false; - - /* --------------------------------------- */ - /* save redo data */ - - OBSData redo_data = main->BackupScene(scene, &sources); - - /* --------------------------------------- */ - /* add undo/redo action */ - - const char *scene_name = obs_source_get_name(scenesource); - QString action_name = QTStr("Undo.ReorderSources").arg(scene_name); - main->CreateSceneUndoRedoAction(action_name, undo_data, redo_data); - - /* --------------------------------------- */ - /* remove items if dropped in to collapsed */ - /* group */ - - if (dropOnCollapsed) { - stm->beginRemoveRows(QModelIndex(), firstIdx, lastIdx); - items.remove(firstIdx, lastIdx - firstIdx + 1); - stm->endRemoveRows(); - } - - /* --------------------------------------- */ - /* update widgets and accept event */ - - UpdateWidgets(true); - - event->accept(); - event->setDropAction(Qt::CopyAction); - - QListView::dropEvent(event); -} - -void SourceTree::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) -{ - { - QSignalBlocker sourcesSignalBlocker(this); - SourceTreeModel *stm = GetStm(); - - QModelIndexList selectedIdxs = selected.indexes(); - QModelIndexList deselectedIdxs = deselected.indexes(); - - for (int i = 0; i < selectedIdxs.count(); i++) { - int idx = selectedIdxs[i].row(); - obs_sceneitem_select(stm->items[idx], true); - } - - for (int i = 0; i < deselectedIdxs.count(); i++) { - int idx = deselectedIdxs[i].row(); - obs_sceneitem_select(stm->items[idx], false); - } - } - QListView::selectionChanged(selected, deselected); -} - -void SourceTree::NewGroupEdit(int row) -{ - if (!Edit(row)) { - OBSBasic *main = OBSBasic::Get(); - main->undo_s.pop_disabled(); - - blog(LOG_WARNING, "Uh, somehow the edit didn't process, this " - "code should never be reached.\nAnd by " - "\"never be reached\", I mean that " - "theoretically, it should be\nimpossible " - "for this code to be reached. But if this " - "code is reached,\nfeel free to laugh at " - "Lain, because apparently it is, in fact, " - "actually\npossible for this code to be " - "reached. But I mean, again, theoretically\n" - "it should be impossible. So if you see " - "this in your log, just know that\nit's " - "really dumb, and depressing. But at least " - "the undo/redo action is\nstill covered, so " - "in theory things *should* be fine. But " - "it's entirely\npossible that they might " - "not be exactly. But again, yea. This " - "really\nshould not be possible."); - - OBSData redoSceneData = main->BackupScene(GetCurrentScene()); - - QString text = QTStr("Undo.GroupItems").arg("Unknown"); - main->CreateSceneUndoRedoAction(text, undoSceneData, redoSceneData); - - undoSceneData = nullptr; - } -} - -bool SourceTree::Edit(int row) -{ - SourceTreeModel *stm = GetStm(); - if (row < 0 || row >= stm->items.count()) - return false; - - QModelIndex index = stm->createIndex(row, 0); - QWidget *widget = indexWidget(index); - SourceTreeItem *itemWidget = reinterpret_cast(widget); - if (itemWidget->IsEditing()) { -#ifdef __APPLE__ - itemWidget->ExitEditMode(true); -#endif - return false; - } - - itemWidget->EnterEditMode(); - edit(index); - return true; -} - -bool SourceTree::MultipleBaseSelected() const -{ - SourceTreeModel *stm = GetStm(); - QModelIndexList selectedIndices = selectedIndexes(); - - OBSScene scene = GetCurrentScene(); - - if (selectedIndices.size() < 1) { - return false; - } - - for (auto &idx : selectedIndices) { - obs_sceneitem_t *item = stm->items[idx.row()]; - if (obs_sceneitem_is_group(item)) { - return false; - } - - obs_scene *itemScene = obs_sceneitem_get_scene(item); - if (itemScene != scene) { - return false; - } - } - - return true; -} - -bool SourceTree::GroupsSelected() const -{ - SourceTreeModel *stm = GetStm(); - QModelIndexList selectedIndices = selectedIndexes(); - - OBSScene scene = GetCurrentScene(); - - if (selectedIndices.size() < 1) { - return false; - } - - for (auto &idx : selectedIndices) { - obs_sceneitem_t *item = stm->items[idx.row()]; - if (!obs_sceneitem_is_group(item)) { - return false; - } - } - - return true; -} - -bool SourceTree::GroupedItemsSelected() const -{ - SourceTreeModel *stm = GetStm(); - QModelIndexList selectedIndices = selectedIndexes(); - OBSScene scene = GetCurrentScene(); - - if (!selectedIndices.size()) { - return false; - } - - for (auto &idx : selectedIndices) { - obs_sceneitem_t *item = stm->items[idx.row()]; - obs_scene *itemScene = obs_sceneitem_get_scene(item); - - if (itemScene != scene) { - return true; - } - } - - return false; -} - -void SourceTree::Remove(OBSSceneItem item, OBSScene scene) -{ - OBSBasic *main = reinterpret_cast(App()->GetMainWindow()); - GetStm()->Remove(item); - main->SaveProject(); - - if (!main->SavingDisabled()) { - obs_source_t *sceneSource = obs_scene_get_source(scene); - obs_source_t *itemSource = obs_sceneitem_get_source(item); - blog(LOG_INFO, "User Removed source '%s' (%s) from scene '%s'", obs_source_get_name(itemSource), - obs_source_get_id(itemSource), obs_source_get_name(sceneSource)); - } -} - -void SourceTree::GroupSelectedItems() -{ - QModelIndexList indices = selectedIndexes(); - std::sort(indices.begin(), indices.end()); - GetStm()->GroupSelectedItems(indices); -} - -void SourceTree::UngroupSelectedGroups() -{ - QModelIndexList indices = selectedIndexes(); - GetStm()->UngroupSelectedGroups(indices); -} - -void SourceTree::AddGroup() -{ - GetStm()->AddGroup(); -} - -void SourceTree::UpdateNoSourcesMessage() -{ - QString file = !App()->IsThemeDark() ? ":res/images/no_sources.svg" : "theme:Dark/no_sources.svg"; - iconNoSources.load(file); - - QTextOption opt(Qt::AlignHCenter); - opt.setWrapMode(QTextOption::WordWrap); - textNoSources.setTextOption(opt); - textNoSources.setText(QTStr("NoSources.Label").replace("\n", "
")); - - textPrepared = false; -} - -void SourceTree::paintEvent(QPaintEvent *event) -{ - SourceTreeModel *stm = GetStm(); - if (stm && !stm->items.count()) { - QPainter p(viewport()); - - if (!textPrepared) { - textNoSources.prepare(QTransform(), p.font()); - textPrepared = true; - } - - QRectF iconRect = iconNoSources.viewBoxF(); - iconRect.setSize(QSizeF(32.0, 32.0)); - - QSizeF iconSize = iconRect.size(); - QSizeF textSize = textNoSources.size(); - QSizeF thisSize = size(); - const qreal spacing = 16.0; - - qreal totalHeight = iconSize.height() + spacing + textSize.height(); - - qreal x = thisSize.width() / 2.0 - iconSize.width() / 2.0; - qreal y = thisSize.height() / 2.0 - totalHeight / 2.0; - iconRect.moveTo(std::round(x), std::round(y)); - iconNoSources.render(&p, iconRect); - - x = thisSize.width() / 2.0 - textSize.width() / 2.0; - y += spacing + iconSize.height(); - p.drawStaticText(x, y, textNoSources); - } else { - QListView::paintEvent(event); - } -} - -SourceTreeDelegate::SourceTreeDelegate(QObject *parent) : QStyledItemDelegate(parent) {} - -QSize SourceTreeDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const -{ - SourceTree *tree = qobject_cast(parent()); - QWidget *item = tree->indexWidget(index); - - if (!item) - return (QSize(0, 0)); - - return (QSize(option.widget->minimumWidth(), item->height())); -} diff --git a/frontend/components/SourceTreeModel.hpp b/frontend/components/SourceTreeModel.hpp index 8f8922d52..a94835346 100644 --- a/frontend/components/SourceTreeModel.hpp +++ b/frontend/components/SourceTreeModel.hpp @@ -1,91 +1,11 @@ #pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include +#include + +#include -class QLabel; -class OBSSourceLabel; -class QCheckBox; -class QLineEdit; class SourceTree; -class QSpacerItem; -class QHBoxLayout; -class VisibilityItemWidget; - -class SourceTreeItem : public QFrame { - Q_OBJECT - - friend class SourceTree; - friend class SourceTreeModel; - - void mouseDoubleClickEvent(QMouseEvent *event) override; - void enterEvent(QEnterEvent *event) override; - void leaveEvent(QEvent *event) override; - - virtual bool eventFilter(QObject *object, QEvent *event) override; - - void Update(bool force); - - enum class Type { - Unknown, - Item, - Group, - SubItem, - }; - - void DisconnectSignals(); - void ReconnectSignals(); - - Type type = Type::Unknown; - -public: - explicit SourceTreeItem(SourceTree *tree, OBSSceneItem sceneitem); - bool IsEditing(); - -private: - QSpacerItem *spacer = nullptr; - QCheckBox *expand = nullptr; - QLabel *iconLabel = nullptr; - QCheckBox *vis = nullptr; - QCheckBox *lock = nullptr; - QHBoxLayout *boxLayout = nullptr; - OBSSourceLabel *label = nullptr; - - QLineEdit *editor = nullptr; - - std::string newName; - - SourceTree *tree; - OBSSceneItem sceneitem; - std::vector sigs; - - virtual void paintEvent(QPaintEvent *event) override; - - void ExitEditModeInternal(bool save); - -private slots: - void Clear(); - - void EnterEditMode(); - void ExitEditMode(bool save); - - void VisibilityChanged(bool visible); - void LockedChanged(bool locked); - - void ExpandClicked(bool checked); - - void Select(); - void Deselect(); -}; class SourceTreeModel : public QAbstractListModel { Q_OBJECT @@ -125,78 +45,3 @@ public: virtual Qt::ItemFlags flags(const QModelIndex &index) const override; virtual Qt::DropActions supportedDropActions() const override; }; - -class SourceTree : public QListView { - Q_OBJECT - - bool ignoreReorder = false; - - friend class SourceTreeModel; - friend class SourceTreeItem; - - bool textPrepared = false; - QStaticText textNoSources; - QSvgRenderer iconNoSources; - - OBSData undoSceneData; - - bool iconsVisible = true; - - void UpdateNoSourcesMessage(); - - void ResetWidgets(); - void UpdateWidget(const QModelIndex &idx, obs_sceneitem_t *item); - void UpdateWidgets(bool force = false); - - inline SourceTreeModel *GetStm() const { return reinterpret_cast(model()); } - -public: - inline SourceTreeItem *GetItemWidget(int idx) - { - QWidget *widget = indexWidget(GetStm()->createIndex(idx, 0)); - return reinterpret_cast(widget); - } - - explicit SourceTree(QWidget *parent = nullptr); - - inline bool IgnoreReorder() const { return ignoreReorder; } - inline void Clear() { GetStm()->Clear(); } - - inline void Add(obs_sceneitem_t *item) { GetStm()->Add(item); } - inline OBSSceneItem Get(int idx) { return GetStm()->Get(idx); } - inline QString GetNewGroupName() { return GetStm()->GetNewGroupName(); } - - void SelectItem(obs_sceneitem_t *sceneitem, bool select); - - bool MultipleBaseSelected() const; - bool GroupsSelected() const; - bool GroupedItemsSelected() const; - - void UpdateIcons(); - void SetIconsVisible(bool visible); - -public slots: - inline void ReorderItems() { GetStm()->ReorderItems(); } - inline void RefreshItems() { GetStm()->SceneChanged(); } - void Remove(OBSSceneItem item, OBSScene scene); - void GroupSelectedItems(); - void UngroupSelectedGroups(); - void AddGroup(); - bool Edit(int idx); - void NewGroupEdit(int idx); - -protected: - virtual void mouseDoubleClickEvent(QMouseEvent *event) override; - virtual void dropEvent(QDropEvent *event) override; - virtual void paintEvent(QPaintEvent *event) override; - - virtual void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) override; -}; - -class SourceTreeDelegate : public QStyledItemDelegate { - Q_OBJECT - -public: - SourceTreeDelegate(QObject *parent); - virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; -}; diff --git a/frontend/components/TextSourceToolbar.cpp b/frontend/components/TextSourceToolbar.cpp index c45d06976..be2d46525 100644 --- a/frontend/components/TextSourceToolbar.cpp +++ b/frontend/components/TextSourceToolbar.cpp @@ -1,574 +1,18 @@ -#include "window-basic-main.hpp" -#include "moc_context-bar-controls.cpp" -#include "obs-app.hpp" +#include "TextSourceToolbar.hpp" +#include "ui_text-source-toolbar.h" + +#include #include -#include + #include #include -#include "ui_browser-source-toolbar.h" -#include "ui_device-select-toolbar.h" -#include "ui_game-capture-toolbar.h" -#include "ui_image-source-toolbar.h" -#include "ui_color-source-toolbar.h" -#include "ui_text-source-toolbar.h" - -#ifdef _WIN32 -#define get_os_module(win, mac, linux) obs_get_module(win) -#define get_os_text(mod, win, mac, linux) obs_module_get_locale_text(mod, win) -#elif __APPLE__ -#define get_os_module(win, mac, linux) obs_get_module(mac) -#define get_os_text(mod, win, mac, linux) obs_module_get_locale_text(mod, mac) -#else -#define get_os_module(win, mac, linux) obs_get_module(linux) -#define get_os_text(mod, win, mac, linux) obs_module_get_locale_text(mod, linux) -#endif - -/* ========================================================================= */ - -SourceToolbar::SourceToolbar(QWidget *parent, OBSSource source) - : QWidget(parent), - weakSource(OBSGetWeakRef(source)), - props(obs_source_properties(source), obs_properties_destroy) -{ -} - -void SourceToolbar::SaveOldProperties(obs_source_t *source) -{ - oldData = obs_data_create(); - - OBSDataAutoRelease oldSettings = obs_source_get_settings(source); - obs_data_apply(oldData, oldSettings); - obs_data_set_string(oldData, "undo_suuid", obs_source_get_uuid(source)); -} - -void SourceToolbar::SetUndoProperties(obs_source_t *source, bool repeatable) -{ - if (!oldData) { - blog(LOG_ERROR, "%s: somehow oldData was null.", __FUNCTION__); - return; - } - - OBSBasic *main = reinterpret_cast(App()->GetMainWindow()); - - OBSSource currentSceneSource = main->GetCurrentSceneSource(); - if (!currentSceneSource) - return; - std::string scene_uuid = obs_source_get_uuid(currentSceneSource); - auto undo_redo = [scene_uuid = std::move(scene_uuid), main](const std::string &data) { - OBSDataAutoRelease settings = obs_data_create_from_json(data.c_str()); - OBSSourceAutoRelease source = obs_get_source_by_uuid(obs_data_get_string(settings, "undo_suuid")); - obs_source_reset_settings(source, settings); - - OBSSourceAutoRelease scene_source = obs_get_source_by_uuid(scene_uuid.c_str()); - main->SetCurrentScene(scene_source.Get(), true); - - main->UpdateContextBar(); - }; - - OBSDataAutoRelease new_settings = obs_data_create(); - OBSDataAutoRelease curr_settings = obs_source_get_settings(source); - obs_data_apply(new_settings, curr_settings); - obs_data_set_string(new_settings, "undo_suuid", obs_source_get_uuid(source)); - - std::string undo_data(obs_data_get_json(oldData)); - std::string redo_data(obs_data_get_json(new_settings)); - - if (undo_data.compare(redo_data) != 0) - main->undo_s.add_action(QTStr("Undo.Properties").arg(obs_source_get_name(source)), undo_redo, undo_redo, - undo_data, redo_data, repeatable); - - oldData = nullptr; -} - -/* ========================================================================= */ - -BrowserToolbar::BrowserToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_BrowserSourceToolbar) -{ - ui->setupUi(this); -} - -BrowserToolbar::~BrowserToolbar() {} - -void BrowserToolbar::on_refresh_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - obs_property_t *p = obs_properties_get(props.get(), "refreshnocache"); - obs_property_button_clicked(p, source.Get()); -} - -/* ========================================================================= */ - -ComboSelectToolbar::ComboSelectToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_DeviceSelectToolbar) -{ - ui->setupUi(this); -} - -ComboSelectToolbar::~ComboSelectToolbar() {} - -static int FillPropertyCombo(QComboBox *c, obs_property_t *p, const std::string &cur_id, bool is_int = false) -{ - size_t count = obs_property_list_item_count(p); - int cur_idx = -1; - - for (size_t i = 0; i < count; i++) { - const char *name = obs_property_list_item_name(p, i); - std::string id; - - if (is_int) { - id = std::to_string(obs_property_list_item_int(p, i)); - } else { - const char *val = obs_property_list_item_string(p, i); - id = val ? val : ""; - } - - if (cur_id == id) - cur_idx = (int)i; - - c->addItem(name, id.c_str()); - } - - return cur_idx; -} - -void UpdateSourceComboToolbarProperties(QComboBox *combo, OBSSource source, obs_properties_t *props, - const char *prop_name, bool is_int) -{ - std::string cur_id; - - OBSDataAutoRelease settings = obs_source_get_settings(source); - if (is_int) { - cur_id = std::to_string(obs_data_get_int(settings, prop_name)); - } else { - cur_id = obs_data_get_string(settings, prop_name); - } - - combo->blockSignals(true); - - obs_property_t *p = obs_properties_get(props, prop_name); - int cur_idx = FillPropertyCombo(combo, p, cur_id, is_int); - - if (cur_idx == -1 || obs_property_list_item_disabled(p, cur_idx)) { - if (cur_idx == -1) { - combo->insertItem(0, QTStr("Basic.Settings.Audio.UnknownAudioDevice")); - cur_idx = 0; - } - - SetComboItemEnabled(combo, cur_idx, false); - } - - combo->setCurrentIndex(cur_idx); - combo->blockSignals(false); -} - -void ComboSelectToolbar::Init() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - UpdateSourceComboToolbarProperties(ui->device, source, props.get(), prop_name, is_int); -} - -void UpdateSourceComboToolbarValue(QComboBox *combo, OBSSource source, int idx, const char *prop_name, bool is_int) -{ - QString id = combo->itemData(idx).toString(); - - OBSDataAutoRelease settings = obs_data_create(); - if (is_int) { - obs_data_set_int(settings, prop_name, id.toInt()); - } else { - obs_data_set_string(settings, prop_name, QT_TO_UTF8(id)); - } - obs_source_update(source, settings); -} - -void ComboSelectToolbar::on_device_currentIndexChanged(int idx) -{ - OBSSource source = GetSource(); - if (idx == -1 || !source) { - return; - } - - SaveOldProperties(source); - UpdateSourceComboToolbarValue(ui->device, source, idx, prop_name, is_int); - SetUndoProperties(source); -} - -AudioCaptureToolbar::AudioCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) {} - -void AudioCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = get_os_module("win-wasapi", "mac-capture", "linux-pulseaudio"); - if (!mod) - return; - - const char *device_str = get_os_text(mod, "Device", "CoreAudio.Device", "Device"); - ui->deviceLabel->setText(device_str); - - prop_name = "device_id"; - - ComboSelectToolbar::Init(); -} - -WindowCaptureToolbar::WindowCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) {} - -void WindowCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = get_os_module("win-capture", "mac-capture", "linux-capture"); - if (!mod) - return; - - const char *device_str = get_os_text(mod, "WindowCapture.Window", "WindowUtils.Window", "Window"); - ui->deviceLabel->setText(device_str); - -#if !defined(_WIN32) && !defined(__APPLE__) //linux - prop_name = "capture_window"; -#else - prop_name = "window"; -#endif - -#ifdef __APPLE__ - is_int = true; -#endif - - ComboSelectToolbar::Init(); -} - -ApplicationAudioCaptureToolbar::ApplicationAudioCaptureToolbar(QWidget *parent, OBSSource source) - : ComboSelectToolbar(parent, source) -{ -} - -void ApplicationAudioCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = obs_get_module("win-wasapi"); - const char *device_str = obs_module_get_locale_text(mod, "Window"); - ui->deviceLabel->setText(device_str); - - prop_name = "window"; - - ComboSelectToolbar::Init(); -} - -DisplayCaptureToolbar::DisplayCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) {} - -void DisplayCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = get_os_module("win-capture", "mac-capture", "linux-capture"); - if (!mod) - return; - - const char *device_str = get_os_text(mod, "Monitor", "DisplayCapture.Display", "Screen"); - ui->deviceLabel->setText(device_str); - -#ifdef _WIN32 - prop_name = "monitor_id"; -#elif __APPLE__ - prop_name = "display_uuid"; -#else - is_int = true; - prop_name = "screen"; -#endif - - ComboSelectToolbar::Init(); -} - -/* ========================================================================= */ - -DeviceCaptureToolbar::DeviceCaptureToolbar(QWidget *parent, OBSSource source) - : QWidget(parent), - weakSource(OBSGetWeakRef(source)), - ui(new Ui_DeviceSelectToolbar) -{ - ui->setupUi(this); - - delete ui->deviceLabel; - delete ui->device; - ui->deviceLabel = nullptr; - ui->device = nullptr; - - OBSDataAutoRelease settings = obs_source_get_settings(source); - active = obs_data_get_bool(settings, "active"); - - obs_module_t *mod = obs_get_module("win-dshow"); - if (!mod) - return; - - activateText = obs_module_get_locale_text(mod, "Activate"); - deactivateText = obs_module_get_locale_text(mod, "Deactivate"); - - ui->activateButton->setText(active ? deactivateText : activateText); -} - -DeviceCaptureToolbar::~DeviceCaptureToolbar() {} - -void DeviceCaptureToolbar::on_activateButton_clicked() -{ - OBSSource source = OBSGetStrongRef(weakSource); - if (!source) { - return; - } - - OBSDataAutoRelease settings = obs_source_get_settings(source); - bool now_active = obs_data_get_bool(settings, "active"); - - bool desyncedSetting = now_active != active; - - active = !active; - - const char *text = active ? deactivateText : activateText; - ui->activateButton->setText(text); - - if (desyncedSetting) { - return; - } - - calldata_t cd = {}; - calldata_set_bool(&cd, "active", active); - proc_handler_t *ph = obs_source_get_proc_handler(source); - proc_handler_call(ph, "activate", &cd); - calldata_free(&cd); -} - -/* ========================================================================= */ - -GameCaptureToolbar::GameCaptureToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_GameCaptureToolbar) -{ - obs_property_t *p; - int cur_idx; - - ui->setupUi(this); - - obs_module_t *mod = obs_get_module("win-capture"); - if (!mod) - return; - - ui->modeLabel->setText(obs_module_get_locale_text(mod, "Mode")); - ui->windowLabel->setText(obs_module_get_locale_text(mod, "WindowCapture.Window")); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - std::string cur_mode = obs_data_get_string(settings, "capture_mode"); - std::string cur_window = obs_data_get_string(settings, "window"); - - ui->mode->blockSignals(true); - p = obs_properties_get(props.get(), "capture_mode"); - cur_idx = FillPropertyCombo(ui->mode, p, cur_mode); - ui->mode->setCurrentIndex(cur_idx); - ui->mode->blockSignals(false); - - ui->window->blockSignals(true); - p = obs_properties_get(props.get(), "window"); - cur_idx = FillPropertyCombo(ui->window, p, cur_window); - ui->window->setCurrentIndex(cur_idx); - ui->window->blockSignals(false); - - if (cur_idx != -1 && obs_property_list_item_disabled(p, cur_idx)) { - SetComboItemEnabled(ui->window, cur_idx, false); - } - - UpdateWindowVisibility(); -} - -GameCaptureToolbar::~GameCaptureToolbar() {} - -void GameCaptureToolbar::UpdateWindowVisibility() -{ - QString mode = ui->mode->currentData().toString(); - bool is_window = (mode == "window"); - ui->windowLabel->setVisible(is_window); - ui->window->setVisible(is_window); -} - -void GameCaptureToolbar::on_mode_currentIndexChanged(int idx) -{ - OBSSource source = GetSource(); - if (idx == -1 || !source) { - return; - } - - QString id = ui->mode->itemData(idx).toString(); - - SaveOldProperties(source); - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_string(settings, "capture_mode", QT_TO_UTF8(id)); - obs_source_update(source, settings); - SetUndoProperties(source); - - UpdateWindowVisibility(); -} - -void GameCaptureToolbar::on_window_currentIndexChanged(int idx) -{ - OBSSource source = GetSource(); - if (idx == -1 || !source) { - return; - } - - QString id = ui->window->itemData(idx).toString(); - - SaveOldProperties(source); - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_string(settings, "window", QT_TO_UTF8(id)); - obs_source_update(source, settings); - SetUndoProperties(source); -} - -/* ========================================================================= */ - -ImageSourceToolbar::ImageSourceToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_ImageSourceToolbar) -{ - ui->setupUi(this); - - obs_module_t *mod = obs_get_module("image-source"); - ui->pathLabel->setText(obs_module_get_locale_text(mod, "File")); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - std::string file = obs_data_get_string(settings, "file"); - - ui->path->setText(file.c_str()); -} - -ImageSourceToolbar::~ImageSourceToolbar() {} - -void ImageSourceToolbar::on_browse_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - obs_property_t *p = obs_properties_get(props.get(), "file"); - const char *desc = obs_property_description(p); - const char *filter = obs_property_path_filter(p); - const char *default_path = obs_property_path_default_path(p); - - QString startDir = ui->path->text(); - if (startDir.isEmpty()) - startDir = default_path; - - QString path = OpenFile(this, desc, startDir, filter); - if (path.isEmpty()) { - return; - } - - ui->path->setText(path); - - SaveOldProperties(source); - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_string(settings, "file", QT_TO_UTF8(path)); - obs_source_update(source, settings); - SetUndoProperties(source); -} - -/* ========================================================================= */ - -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); -} - -ColorSourceToolbar::ColorSourceToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_ColorSourceToolbar) -{ - ui->setupUi(this); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - unsigned int val = (unsigned int)obs_data_get_int(settings, "color"); - - color = color_from_int(val); - UpdateColor(); -} - -ColorSourceToolbar::~ColorSourceToolbar() {} - -void ColorSourceToolbar::UpdateColor() -{ - QPalette palette = QPalette(color); - ui->color->setFrameStyle(QFrame::Sunken | QFrame::Panel); - ui->color->setText(color.name(QColor::HexRgb)); - ui->color->setPalette(palette); - ui->color->setStyleSheet(QString("background-color :%1; color: %2;") - .arg(palette.color(QPalette::Window).name(QColor::HexRgb)) - .arg(palette.color(QPalette::WindowText).name(QColor::HexRgb))); - ui->color->setAutoFillBackground(true); - ui->color->setAlignment(Qt::AlignCenter); -} - -void ColorSourceToolbar::on_choose_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - obs_property_t *p = obs_properties_get(props.get(), "color"); - const char *desc = obs_property_description(p); - - QColorDialog::ColorDialogOptions options; - - options |= QColorDialog::ShowAlphaChannel; -#ifdef __linux__ - // TODO: Revisit hang on Ubuntu with native dialog - options |= QColorDialog::DontUseNativeDialog; -#endif - - QColor newColor = QColorDialog::getColor(color, this, desc, options); - if (!newColor.isValid()) { - return; - } - - color = newColor; - UpdateColor(); - - SaveOldProperties(source); - - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_int(settings, "color", color_to_int(color)); - obs_source_update(source, settings); - - SetUndoProperties(source); -} - -/* ========================================================================= */ +#include "moc_TextSourceToolbar.cpp" extern void MakeQFont(obs_data_t *font_obj, QFont &font, bool limit = false); +extern QColor color_from_int(long long val); +extern long long color_to_int(QColor color); TextSourceToolbar::TextSourceToolbar(QWidget *parent, OBSSource source) : SourceToolbar(parent, source), diff --git a/frontend/components/TextSourceToolbar.hpp b/frontend/components/TextSourceToolbar.hpp index acf88a5fb..38833803a 100644 --- a/frontend/components/TextSourceToolbar.hpp +++ b/frontend/components/TextSourceToolbar.hpp @@ -1,165 +1,9 @@ #pragma once -#include -#include -#include +#include "SourceToolbar.hpp" -class Ui_BrowserSourceToolbar; -class Ui_DeviceSelectToolbar; -class Ui_GameCaptureToolbar; -class Ui_ImageSourceToolbar; -class Ui_ColorSourceToolbar; class Ui_TextSourceToolbar; -class SourceToolbar : public QWidget { - Q_OBJECT - - OBSWeakSource weakSource; - -protected: - using properties_delete_t = decltype(&obs_properties_destroy); - using properties_t = std::unique_ptr; - - properties_t props; - OBSDataAutoRelease oldData; - - void SaveOldProperties(obs_source_t *source); - void SetUndoProperties(obs_source_t *source, bool repeatable = false); - -public: - SourceToolbar(QWidget *parent, OBSSource source); - - OBSSource GetSource() { return OBSGetStrongRef(weakSource); } - -public slots: - virtual void Update() {} -}; - -class BrowserToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - -public: - BrowserToolbar(QWidget *parent, OBSSource source); - ~BrowserToolbar(); - -public slots: - void on_refresh_clicked(); -}; - -class ComboSelectToolbar : public SourceToolbar { - Q_OBJECT - -protected: - std::unique_ptr ui; - const char *prop_name; - bool is_int = false; - -public: - ComboSelectToolbar(QWidget *parent, OBSSource source); - ~ComboSelectToolbar(); - virtual void Init(); - -public slots: - void on_device_currentIndexChanged(int idx); -}; - -class AudioCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - AudioCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class WindowCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - WindowCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class ApplicationAudioCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - ApplicationAudioCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class DisplayCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - DisplayCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class DeviceCaptureToolbar : public QWidget { - Q_OBJECT - - OBSWeakSource weakSource; - - std::unique_ptr ui; - const char *activateText; - const char *deactivateText; - bool active; - -public: - DeviceCaptureToolbar(QWidget *parent, OBSSource source); - ~DeviceCaptureToolbar(); - -public slots: - void on_activateButton_clicked(); -}; - -class GameCaptureToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - - void UpdateWindowVisibility(); - -public: - GameCaptureToolbar(QWidget *parent, OBSSource source); - ~GameCaptureToolbar(); - -public slots: - void on_mode_currentIndexChanged(int idx); - void on_window_currentIndexChanged(int idx); -}; - -class ImageSourceToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - -public: - ImageSourceToolbar(QWidget *parent, OBSSource source); - ~ImageSourceToolbar(); - -public slots: - void on_browse_clicked(); -}; - -class ColorSourceToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - QColor color; - - void UpdateColor(); - -public: - ColorSourceToolbar(QWidget *parent, OBSSource source); - ~ColorSourceToolbar(); - -public slots: - void on_choose_clicked(); -}; - class TextSourceToolbar : public SourceToolbar { Q_OBJECT diff --git a/frontend/components/VisibilityItemDelegate.cpp b/frontend/components/VisibilityItemDelegate.cpp index 50ea425ad..d9e76ee5c 100644 --- a/frontend/components/VisibilityItemDelegate.cpp +++ b/frontend/components/VisibilityItemDelegate.cpp @@ -1,69 +1,9 @@ -#include "moc_visibility-item-widget.cpp" -#include "obs-app.hpp" -#include "source-label.hpp" +#include "VisibilityItemWidget.hpp" +#include "VisibilityItemDelegate.hpp" -#include -#include -#include -#include -#include -#include #include -#include -VisibilityItemWidget::VisibilityItemWidget(obs_source_t *source_) - : source(source_), - enabledSignal(obs_source_get_signal_handler(source), "enable", OBSSourceEnabled, this) -{ - bool enabled = obs_source_enabled(source); - - vis = new QCheckBox(); - vis->setProperty("class", "checkbox-icon indicator-visibility"); - vis->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); - vis->setChecked(enabled); - - label = new OBSSourceLabel(source); - label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); - - QHBoxLayout *itemLayout = new QHBoxLayout(); - itemLayout->addWidget(vis); - itemLayout->addWidget(label); - itemLayout->setContentsMargins(0, 0, 0, 0); - - setLayout(itemLayout); - - connect(vis, &QCheckBox::clicked, [this](bool visible) { obs_source_set_enabled(source, visible); }); -} - -void VisibilityItemWidget::OBSSourceEnabled(void *param, calldata_t *data) -{ - VisibilityItemWidget *window = reinterpret_cast(param); - bool enabled = calldata_bool(data, "enabled"); - - QMetaObject::invokeMethod(window, "SourceEnabled", Q_ARG(bool, enabled)); -} - -void VisibilityItemWidget::SourceEnabled(bool enabled) -{ - if (vis->isChecked() != enabled) - vis->setChecked(enabled); -} - -void VisibilityItemWidget::SetColor(const QColor &color, bool active_, bool selected_) -{ - /* Do not update unless the state has actually changed */ - if (active_ == active && selected_ == selected) - return; - - QPalette pal = vis->palette(); - pal.setColor(QPalette::WindowText, color); - vis->setPalette(pal); - - label->setStyleSheet(QString("color: %1;").arg(color.name())); - - active = active_; - selected = selected_; -} +#include "moc_VisibilityItemDelegate.cpp" VisibilityItemDelegate::VisibilityItemDelegate(QObject *parent) : QStyledItemDelegate(parent) {} @@ -124,10 +64,3 @@ bool VisibilityItemDelegate::eventFilter(QObject *object, QEvent *event) return QStyledItemDelegate::eventFilter(object, event); } - -void SetupVisibilityItem(QListWidget *list, QListWidgetItem *item, obs_source_t *source) -{ - VisibilityItemWidget *baseWidget = new VisibilityItemWidget(source); - - list->setItemWidget(item, baseWidget); -} diff --git a/frontend/components/VisibilityItemDelegate.hpp b/frontend/components/VisibilityItemDelegate.hpp index ec6b35e37..d81b51dae 100644 --- a/frontend/components/VisibilityItemDelegate.hpp +++ b/frontend/components/VisibilityItemDelegate.hpp @@ -1,39 +1,8 @@ #pragma once -#include #include -#include -class QLabel; -class QLineEdit; -class QListWidget; -class QListWidgetItem; -class QCheckBox; -class OBSSourceLabel; - -class VisibilityItemWidget : public QWidget { - Q_OBJECT - -private: - OBSSource source; - OBSSourceLabel *label = nullptr; - QCheckBox *vis = nullptr; - - OBSSignal enabledSignal; - - bool active = false; - bool selected = false; - - static void OBSSourceEnabled(void *param, calldata_t *data); - -private slots: - void SourceEnabled(bool enabled); - -public: - VisibilityItemWidget(obs_source_t *source); - - void SetColor(const QColor &color, bool active, bool selected); -}; +class QObject; class VisibilityItemDelegate : public QStyledItemDelegate { Q_OBJECT @@ -46,5 +15,3 @@ public: protected: bool eventFilter(QObject *object, QEvent *event) override; }; - -void SetupVisibilityItem(QListWidget *list, QListWidgetItem *item, obs_source_t *source); diff --git a/frontend/components/VisibilityItemWidget.cpp b/frontend/components/VisibilityItemWidget.cpp index 50ea425ad..1283f6fbe 100644 --- a/frontend/components/VisibilityItemWidget.cpp +++ b/frontend/components/VisibilityItemWidget.cpp @@ -1,15 +1,11 @@ -#include "moc_visibility-item-widget.cpp" -#include "obs-app.hpp" -#include "source-label.hpp" +#include "VisibilityItemWidget.hpp" + +#include -#include -#include -#include -#include -#include -#include -#include #include +#include + +#include "moc_VisibilityItemWidget.cpp" VisibilityItemWidget::VisibilityItemWidget(obs_source_t *source_) : source(source_), @@ -65,66 +61,6 @@ void VisibilityItemWidget::SetColor(const QColor &color, bool active_, bool sele selected = selected_; } -VisibilityItemDelegate::VisibilityItemDelegate(QObject *parent) : QStyledItemDelegate(parent) {} - -void VisibilityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, - const QModelIndex &index) const -{ - QStyledItemDelegate::paint(painter, option, index); - - QObject *parentObj = parent(); - QListWidget *list = qobject_cast(parentObj); - if (!list) - return; - - QListWidgetItem *item = list->item(index.row()); - VisibilityItemWidget *widget = qobject_cast(list->itemWidget(item)); - if (!widget) - return; - - bool selected = option.state.testFlag(QStyle::State_Selected); - bool active = option.state.testFlag(QStyle::State_Active); - - QPalette palette = list->palette(); -#if defined(_WIN32) || defined(__APPLE__) - QPalette::ColorGroup group = active ? QPalette::Active : QPalette::Inactive; -#else - QPalette::ColorGroup group = QPalette::Active; -#endif - -#ifdef _WIN32 - QPalette::ColorRole highlightRole = QPalette::WindowText; -#else - QPalette::ColorRole highlightRole = QPalette::HighlightedText; -#endif - - QPalette::ColorRole role; - - if (selected && active) - role = highlightRole; - else - role = QPalette::WindowText; - - widget->SetColor(palette.color(group, role), active, selected); -} - -bool VisibilityItemDelegate::eventFilter(QObject *object, QEvent *event) -{ - QWidget *editor = qobject_cast(object); - if (!editor) - return false; - - if (event->type() == QEvent::KeyPress) { - QKeyEvent *keyEvent = static_cast(event); - - if (keyEvent->key() == Qt::Key_Tab || keyEvent->key() == Qt::Key_Backtab) { - return false; - } - } - - return QStyledItemDelegate::eventFilter(object, event); -} - void SetupVisibilityItem(QListWidget *list, QListWidgetItem *item, obs_source_t *source) { VisibilityItemWidget *baseWidget = new VisibilityItemWidget(source); diff --git a/frontend/components/VisibilityItemWidget.hpp b/frontend/components/VisibilityItemWidget.hpp index ec6b35e37..3c4322c87 100644 --- a/frontend/components/VisibilityItemWidget.hpp +++ b/frontend/components/VisibilityItemWidget.hpp @@ -1,15 +1,12 @@ #pragma once -#include -#include #include -class QLabel; -class QLineEdit; -class QListWidget; -class QListWidgetItem; -class QCheckBox; +#include +#include + class OBSSourceLabel; +class QCheckBox; class VisibilityItemWidget : public QWidget { Q_OBJECT @@ -35,16 +32,4 @@ public: void SetColor(const QColor &color, bool active, bool selected); }; -class VisibilityItemDelegate : public QStyledItemDelegate { - Q_OBJECT - -public: - VisibilityItemDelegate(QObject *parent = nullptr); - - void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; - -protected: - bool eventFilter(QObject *object, QEvent *event) override; -}; - void SetupVisibilityItem(QListWidget *list, QListWidgetItem *item, obs_source_t *source); diff --git a/frontend/components/WindowCaptureToolbar.cpp b/frontend/components/WindowCaptureToolbar.cpp index c45d06976..3f1e4ebba 100644 --- a/frontend/components/WindowCaptureToolbar.cpp +++ b/frontend/components/WindowCaptureToolbar.cpp @@ -1,18 +1,6 @@ -#include "window-basic-main.hpp" -#include "moc_context-bar-controls.cpp" -#include "obs-app.hpp" - -#include -#include -#include -#include - -#include "ui_browser-source-toolbar.h" +#include "WindowCaptureToolbar.hpp" #include "ui_device-select-toolbar.h" -#include "ui_game-capture-toolbar.h" -#include "ui_image-source-toolbar.h" -#include "ui_color-source-toolbar.h" -#include "ui_text-source-toolbar.h" +#include "moc_WindowCaptureToolbar.cpp" #ifdef _WIN32 #define get_os_module(win, mac, linux) obs_get_module(win) @@ -25,205 +13,6 @@ #define get_os_text(mod, win, mac, linux) obs_module_get_locale_text(mod, linux) #endif -/* ========================================================================= */ - -SourceToolbar::SourceToolbar(QWidget *parent, OBSSource source) - : QWidget(parent), - weakSource(OBSGetWeakRef(source)), - props(obs_source_properties(source), obs_properties_destroy) -{ -} - -void SourceToolbar::SaveOldProperties(obs_source_t *source) -{ - oldData = obs_data_create(); - - OBSDataAutoRelease oldSettings = obs_source_get_settings(source); - obs_data_apply(oldData, oldSettings); - obs_data_set_string(oldData, "undo_suuid", obs_source_get_uuid(source)); -} - -void SourceToolbar::SetUndoProperties(obs_source_t *source, bool repeatable) -{ - if (!oldData) { - blog(LOG_ERROR, "%s: somehow oldData was null.", __FUNCTION__); - return; - } - - OBSBasic *main = reinterpret_cast(App()->GetMainWindow()); - - OBSSource currentSceneSource = main->GetCurrentSceneSource(); - if (!currentSceneSource) - return; - std::string scene_uuid = obs_source_get_uuid(currentSceneSource); - auto undo_redo = [scene_uuid = std::move(scene_uuid), main](const std::string &data) { - OBSDataAutoRelease settings = obs_data_create_from_json(data.c_str()); - OBSSourceAutoRelease source = obs_get_source_by_uuid(obs_data_get_string(settings, "undo_suuid")); - obs_source_reset_settings(source, settings); - - OBSSourceAutoRelease scene_source = obs_get_source_by_uuid(scene_uuid.c_str()); - main->SetCurrentScene(scene_source.Get(), true); - - main->UpdateContextBar(); - }; - - OBSDataAutoRelease new_settings = obs_data_create(); - OBSDataAutoRelease curr_settings = obs_source_get_settings(source); - obs_data_apply(new_settings, curr_settings); - obs_data_set_string(new_settings, "undo_suuid", obs_source_get_uuid(source)); - - std::string undo_data(obs_data_get_json(oldData)); - std::string redo_data(obs_data_get_json(new_settings)); - - if (undo_data.compare(redo_data) != 0) - main->undo_s.add_action(QTStr("Undo.Properties").arg(obs_source_get_name(source)), undo_redo, undo_redo, - undo_data, redo_data, repeatable); - - oldData = nullptr; -} - -/* ========================================================================= */ - -BrowserToolbar::BrowserToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_BrowserSourceToolbar) -{ - ui->setupUi(this); -} - -BrowserToolbar::~BrowserToolbar() {} - -void BrowserToolbar::on_refresh_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - obs_property_t *p = obs_properties_get(props.get(), "refreshnocache"); - obs_property_button_clicked(p, source.Get()); -} - -/* ========================================================================= */ - -ComboSelectToolbar::ComboSelectToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_DeviceSelectToolbar) -{ - ui->setupUi(this); -} - -ComboSelectToolbar::~ComboSelectToolbar() {} - -static int FillPropertyCombo(QComboBox *c, obs_property_t *p, const std::string &cur_id, bool is_int = false) -{ - size_t count = obs_property_list_item_count(p); - int cur_idx = -1; - - for (size_t i = 0; i < count; i++) { - const char *name = obs_property_list_item_name(p, i); - std::string id; - - if (is_int) { - id = std::to_string(obs_property_list_item_int(p, i)); - } else { - const char *val = obs_property_list_item_string(p, i); - id = val ? val : ""; - } - - if (cur_id == id) - cur_idx = (int)i; - - c->addItem(name, id.c_str()); - } - - return cur_idx; -} - -void UpdateSourceComboToolbarProperties(QComboBox *combo, OBSSource source, obs_properties_t *props, - const char *prop_name, bool is_int) -{ - std::string cur_id; - - OBSDataAutoRelease settings = obs_source_get_settings(source); - if (is_int) { - cur_id = std::to_string(obs_data_get_int(settings, prop_name)); - } else { - cur_id = obs_data_get_string(settings, prop_name); - } - - combo->blockSignals(true); - - obs_property_t *p = obs_properties_get(props, prop_name); - int cur_idx = FillPropertyCombo(combo, p, cur_id, is_int); - - if (cur_idx == -1 || obs_property_list_item_disabled(p, cur_idx)) { - if (cur_idx == -1) { - combo->insertItem(0, QTStr("Basic.Settings.Audio.UnknownAudioDevice")); - cur_idx = 0; - } - - SetComboItemEnabled(combo, cur_idx, false); - } - - combo->setCurrentIndex(cur_idx); - combo->blockSignals(false); -} - -void ComboSelectToolbar::Init() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - UpdateSourceComboToolbarProperties(ui->device, source, props.get(), prop_name, is_int); -} - -void UpdateSourceComboToolbarValue(QComboBox *combo, OBSSource source, int idx, const char *prop_name, bool is_int) -{ - QString id = combo->itemData(idx).toString(); - - OBSDataAutoRelease settings = obs_data_create(); - if (is_int) { - obs_data_set_int(settings, prop_name, id.toInt()); - } else { - obs_data_set_string(settings, prop_name, QT_TO_UTF8(id)); - } - obs_source_update(source, settings); -} - -void ComboSelectToolbar::on_device_currentIndexChanged(int idx) -{ - OBSSource source = GetSource(); - if (idx == -1 || !source) { - return; - } - - SaveOldProperties(source); - UpdateSourceComboToolbarValue(ui->device, source, idx, prop_name, is_int); - SetUndoProperties(source); -} - -AudioCaptureToolbar::AudioCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) {} - -void AudioCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = get_os_module("win-wasapi", "mac-capture", "linux-pulseaudio"); - if (!mod) - return; - - const char *device_str = get_os_text(mod, "Device", "CoreAudio.Device", "Device"); - ui->deviceLabel->setText(device_str); - - prop_name = "device_id"; - - ComboSelectToolbar::Init(); -} - WindowCaptureToolbar::WindowCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) {} void WindowCaptureToolbar::Init() @@ -250,458 +39,3 @@ void WindowCaptureToolbar::Init() ComboSelectToolbar::Init(); } - -ApplicationAudioCaptureToolbar::ApplicationAudioCaptureToolbar(QWidget *parent, OBSSource source) - : ComboSelectToolbar(parent, source) -{ -} - -void ApplicationAudioCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = obs_get_module("win-wasapi"); - const char *device_str = obs_module_get_locale_text(mod, "Window"); - ui->deviceLabel->setText(device_str); - - prop_name = "window"; - - ComboSelectToolbar::Init(); -} - -DisplayCaptureToolbar::DisplayCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) {} - -void DisplayCaptureToolbar::Init() -{ - delete ui->activateButton; - ui->activateButton = nullptr; - - obs_module_t *mod = get_os_module("win-capture", "mac-capture", "linux-capture"); - if (!mod) - return; - - const char *device_str = get_os_text(mod, "Monitor", "DisplayCapture.Display", "Screen"); - ui->deviceLabel->setText(device_str); - -#ifdef _WIN32 - prop_name = "monitor_id"; -#elif __APPLE__ - prop_name = "display_uuid"; -#else - is_int = true; - prop_name = "screen"; -#endif - - ComboSelectToolbar::Init(); -} - -/* ========================================================================= */ - -DeviceCaptureToolbar::DeviceCaptureToolbar(QWidget *parent, OBSSource source) - : QWidget(parent), - weakSource(OBSGetWeakRef(source)), - ui(new Ui_DeviceSelectToolbar) -{ - ui->setupUi(this); - - delete ui->deviceLabel; - delete ui->device; - ui->deviceLabel = nullptr; - ui->device = nullptr; - - OBSDataAutoRelease settings = obs_source_get_settings(source); - active = obs_data_get_bool(settings, "active"); - - obs_module_t *mod = obs_get_module("win-dshow"); - if (!mod) - return; - - activateText = obs_module_get_locale_text(mod, "Activate"); - deactivateText = obs_module_get_locale_text(mod, "Deactivate"); - - ui->activateButton->setText(active ? deactivateText : activateText); -} - -DeviceCaptureToolbar::~DeviceCaptureToolbar() {} - -void DeviceCaptureToolbar::on_activateButton_clicked() -{ - OBSSource source = OBSGetStrongRef(weakSource); - if (!source) { - return; - } - - OBSDataAutoRelease settings = obs_source_get_settings(source); - bool now_active = obs_data_get_bool(settings, "active"); - - bool desyncedSetting = now_active != active; - - active = !active; - - const char *text = active ? deactivateText : activateText; - ui->activateButton->setText(text); - - if (desyncedSetting) { - return; - } - - calldata_t cd = {}; - calldata_set_bool(&cd, "active", active); - proc_handler_t *ph = obs_source_get_proc_handler(source); - proc_handler_call(ph, "activate", &cd); - calldata_free(&cd); -} - -/* ========================================================================= */ - -GameCaptureToolbar::GameCaptureToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_GameCaptureToolbar) -{ - obs_property_t *p; - int cur_idx; - - ui->setupUi(this); - - obs_module_t *mod = obs_get_module("win-capture"); - if (!mod) - return; - - ui->modeLabel->setText(obs_module_get_locale_text(mod, "Mode")); - ui->windowLabel->setText(obs_module_get_locale_text(mod, "WindowCapture.Window")); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - std::string cur_mode = obs_data_get_string(settings, "capture_mode"); - std::string cur_window = obs_data_get_string(settings, "window"); - - ui->mode->blockSignals(true); - p = obs_properties_get(props.get(), "capture_mode"); - cur_idx = FillPropertyCombo(ui->mode, p, cur_mode); - ui->mode->setCurrentIndex(cur_idx); - ui->mode->blockSignals(false); - - ui->window->blockSignals(true); - p = obs_properties_get(props.get(), "window"); - cur_idx = FillPropertyCombo(ui->window, p, cur_window); - ui->window->setCurrentIndex(cur_idx); - ui->window->blockSignals(false); - - if (cur_idx != -1 && obs_property_list_item_disabled(p, cur_idx)) { - SetComboItemEnabled(ui->window, cur_idx, false); - } - - UpdateWindowVisibility(); -} - -GameCaptureToolbar::~GameCaptureToolbar() {} - -void GameCaptureToolbar::UpdateWindowVisibility() -{ - QString mode = ui->mode->currentData().toString(); - bool is_window = (mode == "window"); - ui->windowLabel->setVisible(is_window); - ui->window->setVisible(is_window); -} - -void GameCaptureToolbar::on_mode_currentIndexChanged(int idx) -{ - OBSSource source = GetSource(); - if (idx == -1 || !source) { - return; - } - - QString id = ui->mode->itemData(idx).toString(); - - SaveOldProperties(source); - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_string(settings, "capture_mode", QT_TO_UTF8(id)); - obs_source_update(source, settings); - SetUndoProperties(source); - - UpdateWindowVisibility(); -} - -void GameCaptureToolbar::on_window_currentIndexChanged(int idx) -{ - OBSSource source = GetSource(); - if (idx == -1 || !source) { - return; - } - - QString id = ui->window->itemData(idx).toString(); - - SaveOldProperties(source); - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_string(settings, "window", QT_TO_UTF8(id)); - obs_source_update(source, settings); - SetUndoProperties(source); -} - -/* ========================================================================= */ - -ImageSourceToolbar::ImageSourceToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_ImageSourceToolbar) -{ - ui->setupUi(this); - - obs_module_t *mod = obs_get_module("image-source"); - ui->pathLabel->setText(obs_module_get_locale_text(mod, "File")); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - std::string file = obs_data_get_string(settings, "file"); - - ui->path->setText(file.c_str()); -} - -ImageSourceToolbar::~ImageSourceToolbar() {} - -void ImageSourceToolbar::on_browse_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - obs_property_t *p = obs_properties_get(props.get(), "file"); - const char *desc = obs_property_description(p); - const char *filter = obs_property_path_filter(p); - const char *default_path = obs_property_path_default_path(p); - - QString startDir = ui->path->text(); - if (startDir.isEmpty()) - startDir = default_path; - - QString path = OpenFile(this, desc, startDir, filter); - if (path.isEmpty()) { - return; - } - - ui->path->setText(path); - - SaveOldProperties(source); - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_string(settings, "file", QT_TO_UTF8(path)); - obs_source_update(source, settings); - SetUndoProperties(source); -} - -/* ========================================================================= */ - -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); -} - -ColorSourceToolbar::ColorSourceToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_ColorSourceToolbar) -{ - ui->setupUi(this); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - unsigned int val = (unsigned int)obs_data_get_int(settings, "color"); - - color = color_from_int(val); - UpdateColor(); -} - -ColorSourceToolbar::~ColorSourceToolbar() {} - -void ColorSourceToolbar::UpdateColor() -{ - QPalette palette = QPalette(color); - ui->color->setFrameStyle(QFrame::Sunken | QFrame::Panel); - ui->color->setText(color.name(QColor::HexRgb)); - ui->color->setPalette(palette); - ui->color->setStyleSheet(QString("background-color :%1; color: %2;") - .arg(palette.color(QPalette::Window).name(QColor::HexRgb)) - .arg(palette.color(QPalette::WindowText).name(QColor::HexRgb))); - ui->color->setAutoFillBackground(true); - ui->color->setAlignment(Qt::AlignCenter); -} - -void ColorSourceToolbar::on_choose_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - obs_property_t *p = obs_properties_get(props.get(), "color"); - const char *desc = obs_property_description(p); - - QColorDialog::ColorDialogOptions options; - - options |= QColorDialog::ShowAlphaChannel; -#ifdef __linux__ - // TODO: Revisit hang on Ubuntu with native dialog - options |= QColorDialog::DontUseNativeDialog; -#endif - - QColor newColor = QColorDialog::getColor(color, this, desc, options); - if (!newColor.isValid()) { - return; - } - - color = newColor; - UpdateColor(); - - SaveOldProperties(source); - - OBSDataAutoRelease settings = obs_data_create(); - obs_data_set_int(settings, "color", color_to_int(color)); - obs_source_update(source, settings); - - SetUndoProperties(source); -} - -/* ========================================================================= */ - -extern void MakeQFont(obs_data_t *font_obj, QFont &font, bool limit = false); - -TextSourceToolbar::TextSourceToolbar(QWidget *parent, OBSSource source) - : SourceToolbar(parent, source), - ui(new Ui_TextSourceToolbar) -{ - ui->setupUi(this); - - OBSDataAutoRelease settings = obs_source_get_settings(source); - - const char *id = obs_source_get_unversioned_id(source); - bool ft2 = strcmp(id, "text_ft2_source") == 0; - bool read_from_file = obs_data_get_bool(settings, ft2 ? "from_file" : "read_from_file"); - - OBSDataAutoRelease font_obj = obs_data_get_obj(settings, "font"); - MakeQFont(font_obj, font); - - // Use "color1" if it's a freetype source and "color" elsewise - unsigned int val = (unsigned int)obs_data_get_int( - settings, (strncmp(obs_source_get_id(source), "text_ft2_source", 15) == 0) ? "color1" : "color"); - - color = color_from_int(val); - - const char *text = obs_data_get_string(settings, "text"); - - bool single_line = !read_from_file && (!text || (strchr(text, '\n') == nullptr)); - ui->emptySpace->setVisible(!single_line); - ui->text->setVisible(single_line); - if (single_line) - ui->text->setText(text); -} - -TextSourceToolbar::~TextSourceToolbar() {} - -void TextSourceToolbar::on_selectFont_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - QFontDialog::FontDialogOptions options; - uint32_t flags; - bool success; - -#ifndef _WIN32 - options = QFontDialog::DontUseNativeDialog; -#endif - - font = QFontDialog::getFont(&success, font, this, QTStr("Basic.PropertiesWindow.SelectFont.WindowTitle"), - options); - if (!success) { - return; - } - - OBSDataAutoRelease font_obj = obs_data_create(); - - obs_data_set_string(font_obj, "face", QT_TO_UTF8(font.family())); - obs_data_set_string(font_obj, "style", QT_TO_UTF8(font.styleName())); - obs_data_set_int(font_obj, "size", font.pointSize()); - flags = font.bold() ? OBS_FONT_BOLD : 0; - flags |= font.italic() ? OBS_FONT_ITALIC : 0; - flags |= font.underline() ? OBS_FONT_UNDERLINE : 0; - flags |= font.strikeOut() ? OBS_FONT_STRIKEOUT : 0; - obs_data_set_int(font_obj, "flags", flags); - - SaveOldProperties(source); - - OBSDataAutoRelease settings = obs_data_create(); - - obs_data_set_obj(settings, "font", font_obj); - - obs_source_update(source, settings); - - SetUndoProperties(source); -} - -void TextSourceToolbar::on_selectColor_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - bool freetype = strncmp(obs_source_get_id(source), "text_ft2_source", 15) == 0; - - obs_property_t *p = obs_properties_get(props.get(), freetype ? "color1" : "color"); - - const char *desc = obs_property_description(p); - - QColorDialog::ColorDialogOptions options; - - options |= QColorDialog::ShowAlphaChannel; -#ifdef __linux__ - // TODO: Revisit hang on Ubuntu with native dialog - options |= QColorDialog::DontUseNativeDialog; -#endif - - QColor newColor = QColorDialog::getColor(color, this, desc, options); - if (!newColor.isValid()) { - return; - } - - color = newColor; - - SaveOldProperties(source); - - OBSDataAutoRelease settings = obs_data_create(); - if (freetype) { - obs_data_set_int(settings, "color1", color_to_int(color)); - obs_data_set_int(settings, "color2", color_to_int(color)); - } else { - obs_data_set_int(settings, "color", color_to_int(color)); - } - obs_source_update(source, settings); - - SetUndoProperties(source); -} - -void TextSourceToolbar::on_text_textChanged() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - std::string newText = QT_TO_UTF8(ui->text->text()); - OBSDataAutoRelease settings = obs_source_get_settings(source); - if (newText == obs_data_get_string(settings, "text")) { - return; - } - SaveOldProperties(source); - - obs_data_set_string(settings, "text", newText.c_str()); - obs_source_update(source, nullptr); - - SetUndoProperties(source, true); -} diff --git a/frontend/components/WindowCaptureToolbar.hpp b/frontend/components/WindowCaptureToolbar.hpp index acf88a5fb..760a95402 100644 --- a/frontend/components/WindowCaptureToolbar.hpp +++ b/frontend/components/WindowCaptureToolbar.hpp @@ -1,77 +1,6 @@ #pragma once -#include -#include -#include - -class Ui_BrowserSourceToolbar; -class Ui_DeviceSelectToolbar; -class Ui_GameCaptureToolbar; -class Ui_ImageSourceToolbar; -class Ui_ColorSourceToolbar; -class Ui_TextSourceToolbar; - -class SourceToolbar : public QWidget { - Q_OBJECT - - OBSWeakSource weakSource; - -protected: - using properties_delete_t = decltype(&obs_properties_destroy); - using properties_t = std::unique_ptr; - - properties_t props; - OBSDataAutoRelease oldData; - - void SaveOldProperties(obs_source_t *source); - void SetUndoProperties(obs_source_t *source, bool repeatable = false); - -public: - SourceToolbar(QWidget *parent, OBSSource source); - - OBSSource GetSource() { return OBSGetStrongRef(weakSource); } - -public slots: - virtual void Update() {} -}; - -class BrowserToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - -public: - BrowserToolbar(QWidget *parent, OBSSource source); - ~BrowserToolbar(); - -public slots: - void on_refresh_clicked(); -}; - -class ComboSelectToolbar : public SourceToolbar { - Q_OBJECT - -protected: - std::unique_ptr ui; - const char *prop_name; - bool is_int = false; - -public: - ComboSelectToolbar(QWidget *parent, OBSSource source); - ~ComboSelectToolbar(); - virtual void Init(); - -public slots: - void on_device_currentIndexChanged(int idx); -}; - -class AudioCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - AudioCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; +#include "ComboSelectToolbar.hpp" class WindowCaptureToolbar : public ComboSelectToolbar { Q_OBJECT @@ -80,99 +9,3 @@ public: WindowCaptureToolbar(QWidget *parent, OBSSource source); void Init() override; }; - -class ApplicationAudioCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - ApplicationAudioCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class DisplayCaptureToolbar : public ComboSelectToolbar { - Q_OBJECT - -public: - DisplayCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; -}; - -class DeviceCaptureToolbar : public QWidget { - Q_OBJECT - - OBSWeakSource weakSource; - - std::unique_ptr ui; - const char *activateText; - const char *deactivateText; - bool active; - -public: - DeviceCaptureToolbar(QWidget *parent, OBSSource source); - ~DeviceCaptureToolbar(); - -public slots: - void on_activateButton_clicked(); -}; - -class GameCaptureToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - - void UpdateWindowVisibility(); - -public: - GameCaptureToolbar(QWidget *parent, OBSSource source); - ~GameCaptureToolbar(); - -public slots: - void on_mode_currentIndexChanged(int idx); - void on_window_currentIndexChanged(int idx); -}; - -class ImageSourceToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - -public: - ImageSourceToolbar(QWidget *parent, OBSSource source); - ~ImageSourceToolbar(); - -public slots: - void on_browse_clicked(); -}; - -class ColorSourceToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - QColor color; - - void UpdateColor(); - -public: - ColorSourceToolbar(QWidget *parent, OBSSource source); - ~ColorSourceToolbar(); - -public slots: - void on_choose_clicked(); -}; - -class TextSourceToolbar : public SourceToolbar { - Q_OBJECT - - std::unique_ptr ui; - QFont font; - QColor color; - -public: - TextSourceToolbar(QWidget *parent, OBSSource source); - ~TextSourceToolbar(); - -public slots: - void on_selectFont_clicked(); - void on_selectColor_clicked(); - void on_text_textChanged(); -};