frontend: Split Qt UI component into single file per C++ class

This commit is contained in:
PatTheMav 2024-12-04 18:22:25 +01:00
parent 819850c0f6
commit f4fe30a5b3
No known key found for this signature in database
40 changed files with 108 additions and 15510 deletions

View File

@ -1,255 +1,6 @@
#include "window-basic-main.hpp"
#include "moc_context-bar-controls.cpp"
#include "obs-app.hpp"
#include <qt-wrappers.hpp>
#include <QStandardItemModel>
#include <QColorDialog>
#include <QFontDialog>
#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<OBSBasic *>(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);
}

View File

@ -1,85 +1,6 @@
#pragma once
#include <memory>
#include <obs.hpp>
#include <QWidget>
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<obs_properties_t, properties_delete_t>;
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_BrowserSourceToolbar> 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_DeviceSelectToolbar> 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_DeviceSelectToolbar> 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_GameCaptureToolbar> 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_ImageSourceToolbar> ui;
public:
ImageSourceToolbar(QWidget *parent, OBSSource source);
~ImageSourceToolbar();
public slots:
void on_browse_clicked();
};
class ColorSourceToolbar : public SourceToolbar {
Q_OBJECT
std::unique_ptr<Ui_ColorSourceToolbar> 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_TextSourceToolbar> 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();
};

View File

@ -1,18 +1,6 @@
#include "window-basic-main.hpp"
#include "moc_context-bar-controls.cpp"
#include "obs-app.hpp"
#include <qt-wrappers.hpp>
#include <QStandardItemModel>
#include <QColorDialog>
#include <QFontDialog>
#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<OBSBasic *>(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);
}

View File

@ -1,69 +1,6 @@
#pragma once
#include <memory>
#include <obs.hpp>
#include <QWidget>
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<obs_properties_t, properties_delete_t>;
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_BrowserSourceToolbar> 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_DeviceSelectToolbar> 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_DeviceSelectToolbar> 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_GameCaptureToolbar> 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_ImageSourceToolbar> ui;
public:
ImageSourceToolbar(QWidget *parent, OBSSource source);
~ImageSourceToolbar();
public slots:
void on_browse_clicked();
};
class ColorSourceToolbar : public SourceToolbar {
Q_OBJECT
std::unique_ptr<Ui_ColorSourceToolbar> 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_TextSourceToolbar> 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();
};

View File

@ -1,88 +1,6 @@
#include "window-basic-main.hpp"
#include "moc_context-bar-controls.cpp"
#include "obs-app.hpp"
#include <qt-wrappers.hpp>
#include <QStandardItemModel>
#include <QColorDialog>
#include <QFontDialog>
#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<OBSBasic *>(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);
}

View File

@ -1,39 +1,8 @@
#pragma once
#include <memory>
#include <obs.hpp>
#include <QWidget>
#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<obs_properties_t, properties_delete_t>;
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_DeviceSelectToolbar> 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_DeviceSelectToolbar> 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_GameCaptureToolbar> 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_ImageSourceToolbar> ui;
public:
ImageSourceToolbar(QWidget *parent, OBSSource source);
~ImageSourceToolbar();
public slots:
void on_browse_clicked();
};
class ColorSourceToolbar : public SourceToolbar {
Q_OBJECT
std::unique_ptr<Ui_ColorSourceToolbar> 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_TextSourceToolbar> 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();
};

View File

@ -1,500 +1,16 @@
#include "window-basic-main.hpp"
#include "moc_context-bar-controls.cpp"
#include "obs-app.hpp"
#include <qt-wrappers.hpp>
#include <QStandardItemModel>
#include <QColorDialog>
#include <QFontDialog>
#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 <QColorDialog>
/* ========================================================================= */
#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<OBSBasic *>(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);
}

View File

@ -1,148 +1,8 @@
#pragma once
#include <memory>
#include <obs.hpp>
#include <QWidget>
#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<obs_properties_t, properties_delete_t>;
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_BrowserSourceToolbar> 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_DeviceSelectToolbar> 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_DeviceSelectToolbar> 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_GameCaptureToolbar> 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_ImageSourceToolbar> 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_TextSourceToolbar> 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();
};

View File

@ -1,110 +1,10 @@
#include "window-basic-main.hpp"
#include "moc_context-bar-controls.cpp"
#include "obs-app.hpp"
#include <qt-wrappers.hpp>
#include <QStandardItemModel>
#include <QColorDialog>
#include <QFontDialog>
#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 <OBSApp.hpp>
#include <qt-wrappers.hpp>
/* ========================================================================= */
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<OBSBasic *>(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);
}

View File

@ -1,52 +1,8 @@
#pragma once
#include <memory>
#include <obs.hpp>
#include <QWidget>
#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<obs_properties_t, properties_delete_t>;
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_BrowserSourceToolbar> 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_DeviceSelectToolbar> 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_GameCaptureToolbar> 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_ImageSourceToolbar> ui;
public:
ImageSourceToolbar(QWidget *parent, OBSSource source);
~ImageSourceToolbar();
public slots:
void on_browse_clicked();
};
class ColorSourceToolbar : public SourceToolbar {
Q_OBJECT
std::unique_ptr<Ui_ColorSourceToolbar> 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_TextSourceToolbar> 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();
};

View File

@ -1,302 +1,6 @@
#include "window-basic-main.hpp"
#include "moc_context-bar-controls.cpp"
#include "obs-app.hpp"
#include <qt-wrappers.hpp>
#include <QStandardItemModel>
#include <QColorDialog>
#include <QFontDialog>
#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<OBSBasic *>(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);
}

View File

@ -1,101 +1,10 @@
#pragma once
#include <memory>
#include <obs.hpp>
#include <QWidget>
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<obs_properties_t, properties_delete_t>;
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_BrowserSourceToolbar> 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_DeviceSelectToolbar> 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_GameCaptureToolbar> 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_ImageSourceToolbar> ui;
public:
ImageSourceToolbar(QWidget *parent, OBSSource source);
~ImageSourceToolbar();
public slots:
void on_browse_clicked();
};
class ColorSourceToolbar : public SourceToolbar {
Q_OBJECT
std::unique_ptr<Ui_ColorSourceToolbar> 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_TextSourceToolbar> 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();
};

View File

@ -1,18 +1,6 @@
#include "window-basic-main.hpp"
#include "moc_context-bar-controls.cpp"
#include "obs-app.hpp"
#include <qt-wrappers.hpp>
#include <QStandardItemModel>
#include <QColorDialog>
#include <QFontDialog>
#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<OBSBasic *>(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);
}

View File

@ -1,93 +1,6 @@
#pragma once
#include <memory>
#include <obs.hpp>
#include <QWidget>
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<obs_properties_t, properties_delete_t>;
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_BrowserSourceToolbar> 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_DeviceSelectToolbar> 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_DeviceSelectToolbar> 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_GameCaptureToolbar> 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_ImageSourceToolbar> ui;
public:
ImageSourceToolbar(QWidget *parent, OBSSource source);
~ImageSourceToolbar();
public slots:
void on_browse_clicked();
};
class ColorSourceToolbar : public SourceToolbar {
Q_OBJECT
std::unique_ptr<Ui_ColorSourceToolbar> 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_TextSourceToolbar> 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();
};

View File

@ -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 <qt-wrappers.hpp>
#include <QStandardItemModel>
#include <QColorDialog>
#include <QFontDialog>
#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<OBSBasic *>(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);
}

View File

@ -1,119 +1,8 @@
#pragma once
#include <memory>
#include <obs.hpp>
#include <QWidget>
#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<obs_properties_t, properties_delete_t>;
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_BrowserSourceToolbar> 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_DeviceSelectToolbar> 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_DeviceSelectToolbar> 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_ImageSourceToolbar> ui;
public:
ImageSourceToolbar(QWidget *parent, OBSSource source);
~ImageSourceToolbar();
public slots:
void on_browse_clicked();
};
class ColorSourceToolbar : public SourceToolbar {
Q_OBJECT
std::unique_ptr<Ui_ColorSourceToolbar> 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_TextSourceToolbar> 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();
};

View File

@ -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 <qt-wrappers.hpp>
#include <QStandardItemModel>
#include <QColorDialog>
#include <QFontDialog>
#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<OBSBasic *>(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);
}

View File

@ -1,135 +1,8 @@
#pragma once
#include <memory>
#include <obs.hpp>
#include <QWidget>
#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<obs_properties_t, properties_delete_t>;
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_BrowserSourceToolbar> 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_DeviceSelectToolbar> 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_DeviceSelectToolbar> 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_GameCaptureToolbar> 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_ColorSourceToolbar> 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_TextSourceToolbar> 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();
};

View File

@ -15,23 +15,12 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#include "preview-controls.hpp"
#include <obs-app.hpp>
#include "OBSPreviewScalingComboBox.hpp"
/* Preview Scale Label */
void OBSPreviewScalingLabel::PreviewScaleChanged(float scale)
{
previewScale = scale;
UpdateScaleLabel();
}
#include <OBSApp.hpp>
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)

View File

@ -17,23 +17,8 @@
#pragma once
#include <QLabel>
#include <QComboBox>
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

View File

@ -15,10 +15,9 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#include "preview-controls.hpp"
#include <obs-app.hpp>
#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);
}
}
}

View File

@ -18,7 +18,6 @@
#pragma once
#include <QLabel>
#include <QComboBox>
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();
};

View File

@ -1,31 +1,8 @@
#include "window-basic-main.hpp"
#include "moc_context-bar-controls.cpp"
#include "obs-app.hpp"
#include "SourceToolbar.hpp"
#include <qt-wrappers.hpp>
#include <QStandardItemModel>
#include <QColorDialog>
#include <QFontDialog>
#include <widgets/OBSBasic.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
/* ========================================================================= */
#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);
}

View File

@ -1,15 +1,8 @@
#pragma once
#include <memory>
#include <obs.hpp>
#include <QWidget>
class Ui_BrowserSourceToolbar;
class Ui_DeviceSelectToolbar;
class Ui_GameCaptureToolbar;
class Ui_ImageSourceToolbar;
class Ui_ColorSourceToolbar;
class Ui_TextSourceToolbar;
#include <QWidget>
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_BrowserSourceToolbar> 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_DeviceSelectToolbar> 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_DeviceSelectToolbar> 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_GameCaptureToolbar> 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_ImageSourceToolbar> ui;
public:
ImageSourceToolbar(QWidget *parent, OBSSource source);
~ImageSourceToolbar();
public slots:
void on_browse_clicked();
};
class ColorSourceToolbar : public SourceToolbar {
Q_OBJECT
std::unique_ptr<Ui_ColorSourceToolbar> 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_TextSourceToolbar> 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();
};

File diff suppressed because it is too large Load Diff

View File

@ -1,130 +1,11 @@
#pragma once
#include <QList>
#include <QVector>
#include <QPointer>
#include "SourceTreeItem.hpp"
#include "SourceTreeModel.hpp"
#include <QListView>
#include <QCheckBox>
#include <QStaticText>
#include <QSvgRenderer>
#include <QAbstractListModel>
#include <QStyledItemDelegate>
#include <obs.hpp>
#include <obs-frontend-api.h>
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<OBSSignal> 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<OBSSceneItem> 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;
};

File diff suppressed because it is too large Load Diff

View File

@ -1,197 +1,10 @@
#pragma once
#include <QList>
#include <QVector>
#include <QPointer>
#include <QListView>
#include <QCheckBox>
#include <QStaticText>
#include <QSvgRenderer>
#include <QAbstractListModel>
#include <QModelIndex>
#include <QObject>
#include <QSize>
#include <QStyledItemDelegate>
#include <obs.hpp>
#include <obs-frontend-api.h>
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<OBSSignal> 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<OBSSceneItem> 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<SourceTreeModel *>(model()); }
public:
inline SourceTreeItem *GetItemWidget(int idx)
{
QWidget *widget = indexWidget(GetStm()->createIndex(idx, 0));
return reinterpret_cast<SourceTreeItem *>(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 <QStyleOptionViewItem>
class SourceTreeDelegate : public QStyledItemDelegate {
Q_OBJECT

File diff suppressed because it is too large Load Diff

View File

@ -1,25 +1,17 @@
#pragma once
#include <QList>
#include <QVector>
#include <QPointer>
#include <QListView>
#include <QCheckBox>
#include <QStaticText>
#include <QSvgRenderer>
#include <QAbstractListModel>
#include <QStyledItemDelegate>
#include <obs.hpp>
#include <obs-frontend-api.h>
class QLabel;
class OBSSourceLabel;
class QCheckBox;
class QLineEdit;
class SourceTree;
#include <QFrame>
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<OBSSceneItem> 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<SourceTreeModel *>(model()); }
public:
inline SourceTreeItem *GetItemWidget(int idx)
{
QWidget *widget = indexWidget(GetStm()->createIndex(idx, 0));
return reinterpret_cast<SourceTreeItem *>(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;
};

File diff suppressed because it is too large Load Diff

View File

@ -1,91 +1,11 @@
#pragma once
#include <QList>
#include <QVector>
#include <QPointer>
#include <QListView>
#include <QCheckBox>
#include <QStaticText>
#include <QSvgRenderer>
#include <QAbstractListModel>
#include <QStyledItemDelegate>
#include <obs.hpp>
#include <obs-frontend-api.h>
#include <obs.hpp>
#include <QAbstractListModel>
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<OBSSignal> 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<SourceTreeModel *>(model()); }
public:
inline SourceTreeItem *GetItemWidget(int idx)
{
QWidget *widget = indexWidget(GetStm()->createIndex(idx, 0));
return reinterpret_cast<SourceTreeItem *>(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;
};

View File

@ -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 <OBSApp.hpp>
#include <qt-wrappers.hpp>
#include <QStandardItemModel>
#include <QColorDialog>
#include <QFontDialog>
#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<OBSBasic *>(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),

View File

@ -1,165 +1,9 @@
#pragma once
#include <memory>
#include <obs.hpp>
#include <QWidget>
#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<obs_properties_t, properties_delete_t>;
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_BrowserSourceToolbar> 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_DeviceSelectToolbar> 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_DeviceSelectToolbar> 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_GameCaptureToolbar> 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_ImageSourceToolbar> ui;
public:
ImageSourceToolbar(QWidget *parent, OBSSource source);
~ImageSourceToolbar();
public slots:
void on_browse_clicked();
};
class ColorSourceToolbar : public SourceToolbar {
Q_OBJECT
std::unique_ptr<Ui_ColorSourceToolbar> ui;
QColor color;
void UpdateColor();
public:
ColorSourceToolbar(QWidget *parent, OBSSource source);
~ColorSourceToolbar();
public slots:
void on_choose_clicked();
};
class TextSourceToolbar : public SourceToolbar {
Q_OBJECT

View File

@ -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 <qt-wrappers.hpp>
#include <QListWidget>
#include <QLineEdit>
#include <QHBoxLayout>
#include <QMessageBox>
#include <QLabel>
#include <QKeyEvent>
#include <QCheckBox>
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<VisibilityItemWidget *>(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);
}

View File

@ -1,39 +1,8 @@
#pragma once
#include <QWidget>
#include <QStyledItemDelegate>
#include <obs.hpp>
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);

View File

@ -1,15 +1,11 @@
#include "moc_visibility-item-widget.cpp"
#include "obs-app.hpp"
#include "source-label.hpp"
#include "VisibilityItemWidget.hpp"
#include <components/OBSSourceLabel.hpp>
#include <qt-wrappers.hpp>
#include <QListWidget>
#include <QLineEdit>
#include <QHBoxLayout>
#include <QMessageBox>
#include <QLabel>
#include <QKeyEvent>
#include <QCheckBox>
#include <QHBoxLayout>
#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<QListWidget *>(parentObj);
if (!list)
return;
QListWidgetItem *item = list->item(index.row());
VisibilityItemWidget *widget = qobject_cast<VisibilityItemWidget *>(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<QWidget *>(object);
if (!editor)
return false;
if (event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(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);

View File

@ -1,15 +1,12 @@
#pragma once
#include <QWidget>
#include <QStyledItemDelegate>
#include <obs.hpp>
class QLabel;
class QLineEdit;
class QListWidget;
class QListWidgetItem;
class QCheckBox;
#include <QListWidget>
#include <QWidget>
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);

View File

@ -1,18 +1,6 @@
#include "window-basic-main.hpp"
#include "moc_context-bar-controls.cpp"
#include "obs-app.hpp"
#include <qt-wrappers.hpp>
#include <QStandardItemModel>
#include <QColorDialog>
#include <QFontDialog>
#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<OBSBasic *>(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);
}

View File

@ -1,77 +1,6 @@
#pragma once
#include <memory>
#include <obs.hpp>
#include <QWidget>
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<obs_properties_t, properties_delete_t>;
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_BrowserSourceToolbar> 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_DeviceSelectToolbar> 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_DeviceSelectToolbar> 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_GameCaptureToolbar> 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_ImageSourceToolbar> ui;
public:
ImageSourceToolbar(QWidget *parent, OBSSource source);
~ImageSourceToolbar();
public slots:
void on_browse_clicked();
};
class ColorSourceToolbar : public SourceToolbar {
Q_OBJECT
std::unique_ptr<Ui_ColorSourceToolbar> 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_TextSourceToolbar> 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();
};