Merge pull request #3268 from obsproject/context-bar
Add Source Toolbar
@ -46,6 +46,7 @@ configure_file(
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR TRUE)
|
||||
set(CMAKE_AUTOMOC TRUE)
|
||||
|
||||
find_package(Qt5Widgets ${FIND_MODE})
|
||||
find_package(Qt5Svg ${FIND_MODE})
|
||||
find_package(Qt5Xml ${FIND_MODE})
|
||||
|
||||
@ -214,6 +215,7 @@ set(obs_SOURCES
|
||||
window-basic-preview.cpp
|
||||
window-basic-about.cpp
|
||||
window-importer.cpp
|
||||
media-controls.cpp
|
||||
window-namedialog.cpp
|
||||
window-log-reply.cpp
|
||||
window-projector.cpp
|
||||
@ -234,6 +236,7 @@ set(obs_SOURCES
|
||||
volume-control.cpp
|
||||
adv-audio-control.cpp
|
||||
item-widget-helpers.cpp
|
||||
context-bar-controls.cpp
|
||||
horizontal-scroll-area.cpp
|
||||
vertical-scroll-area.cpp
|
||||
visibility-item-widget.cpp
|
||||
@ -245,7 +248,11 @@ set(obs_SOURCES
|
||||
remote-text.cpp
|
||||
audio-encoders.cpp
|
||||
qt-wrappers.cpp
|
||||
log-viewer.cpp)
|
||||
log-viewer.cpp
|
||||
obs-proxy-style.cpp
|
||||
locked-checkbox.cpp
|
||||
visibility-checkbox.cpp
|
||||
media-slider.cpp)
|
||||
|
||||
set(obs_HEADERS
|
||||
${obs_PLATFORM_HEADERS}
|
||||
@ -270,6 +277,7 @@ set(obs_HEADERS
|
||||
window-basic-transform.hpp
|
||||
window-basic-preview.hpp
|
||||
window-importer.hpp
|
||||
media-controls.hpp
|
||||
window-namedialog.hpp
|
||||
window-log-reply.hpp
|
||||
window-projector.hpp
|
||||
@ -296,6 +304,7 @@ set(obs_HEADERS
|
||||
adv-audio-control.hpp
|
||||
item-widget-helpers.hpp
|
||||
visibility-checkbox.hpp
|
||||
context-bar-controls.hpp
|
||||
locked-checkbox.hpp
|
||||
horizontal-scroll-area.hpp
|
||||
expand-checkbox.hpp
|
||||
@ -310,7 +319,10 @@ set(obs_HEADERS
|
||||
audio-encoders.hpp
|
||||
qt-wrappers.hpp
|
||||
clickable-label.hpp
|
||||
log-viewer.hpp)
|
||||
log-viewer.hpp
|
||||
obs-proxy-style.hpp
|
||||
obs-proxy-style.hpp
|
||||
media-slider.hpp)
|
||||
|
||||
set(obs_importers_HEADERS
|
||||
importers/importers.hpp)
|
||||
@ -326,6 +338,13 @@ source_group("importers\\Source Files" FILES ${obs_importers_SOURCES})
|
||||
source_group("importers\\Header Files" FILES ${obs_importers_HEADERS})
|
||||
|
||||
set(obs_UI
|
||||
forms/source-toolbar/browser-source-toolbar.ui
|
||||
forms/source-toolbar/device-select-toolbar.ui
|
||||
forms/source-toolbar/game-capture-toolbar.ui
|
||||
forms/source-toolbar/image-source-toolbar.ui
|
||||
forms/source-toolbar/color-source-toolbar.ui
|
||||
forms/source-toolbar/text-source-toolbar.ui
|
||||
forms/source-toolbar/media-controls.ui
|
||||
forms/NameDialog.ui
|
||||
forms/AutoConfigStartPage.ui
|
||||
forms/AutoConfigVideoPage.ui
|
||||
|
631
UI/context-bar-controls.cpp
Normal file
@ -0,0 +1,631 @@
|
||||
#include "context-bar-controls.hpp"
|
||||
#include "qt-wrappers.hpp"
|
||||
#include "obs-app.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)
|
||||
{
|
||||
obs_data_t *settings = obs_source_get_settings(source);
|
||||
obs_properties_apply_settings(props.get(), settings);
|
||||
obs_data_release(settings);
|
||||
}
|
||||
|
||||
/* ========================================================================= */
|
||||
|
||||
BrowserToolbar::BrowserToolbar(QWidget *parent, OBSSource source)
|
||||
: SourceToolbar(parent, source), ui(new Ui_BrowserSourceToolbar)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
BrowserToolbar::~BrowserToolbar()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static void SetComboItemDisabled(QComboBox *c, int idx)
|
||||
{
|
||||
QStandardItemModel *model =
|
||||
dynamic_cast<QStandardItemModel *>(c->model());
|
||||
QStandardItem *item = model->item(idx);
|
||||
item->setFlags(Qt::NoItemFlags);
|
||||
}
|
||||
|
||||
void ComboSelectToolbar::Init()
|
||||
{
|
||||
OBSSource source = GetSource();
|
||||
if (!source) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string cur_id;
|
||||
|
||||
obs_data_t *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);
|
||||
}
|
||||
obs_data_release(settings);
|
||||
|
||||
ui->device->blockSignals(true);
|
||||
|
||||
obs_property_t *p = obs_properties_get(props.get(), prop_name);
|
||||
int cur_idx = FillPropertyCombo(ui->device, p, cur_id, is_int);
|
||||
|
||||
if (cur_idx == -1 || obs_property_list_item_disabled(p, cur_idx)) {
|
||||
if (cur_idx == -1) {
|
||||
ui->device->insertItem(
|
||||
0,
|
||||
QTStr("Basic.Settings.Audio.UnknownAudioDevice"));
|
||||
cur_idx = 0;
|
||||
}
|
||||
|
||||
SetComboItemDisabled(ui->device, cur_idx);
|
||||
} else {
|
||||
ui->device->setCurrentIndex(cur_idx);
|
||||
}
|
||||
|
||||
ui->device->blockSignals(false);
|
||||
}
|
||||
|
||||
void ComboSelectToolbar::UpdateActivateButtonName()
|
||||
{
|
||||
obs_property_t *p = obs_properties_get(props.get(), "activate");
|
||||
ui->activateButton->setText(obs_property_description(p));
|
||||
}
|
||||
|
||||
void ComboSelectToolbar::on_device_currentIndexChanged(int idx)
|
||||
{
|
||||
OBSSource source = GetSource();
|
||||
if (idx == -1 || !source) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString id = ui->device->itemData(idx).toString();
|
||||
|
||||
obs_data_t *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);
|
||||
obs_data_release(settings);
|
||||
}
|
||||
|
||||
void ComboSelectToolbar::on_activateButton_clicked()
|
||||
{
|
||||
OBSSource source = GetSource();
|
||||
if (!source) {
|
||||
return;
|
||||
}
|
||||
|
||||
obs_property_t *p = obs_properties_get(props.get(), "activate");
|
||||
if (!p) {
|
||||
return;
|
||||
}
|
||||
|
||||
obs_property_button_clicked(p, source.Get());
|
||||
UpdateActivateButtonName();
|
||||
}
|
||||
|
||||
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");
|
||||
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");
|
||||
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();
|
||||
}
|
||||
|
||||
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");
|
||||
const char *device_str =
|
||||
get_os_text(mod, "Monitor", "DisplayCapture.Display", "Screen");
|
||||
ui->deviceLabel->setText(device_str);
|
||||
is_int = true;
|
||||
|
||||
#ifdef _WIN32
|
||||
prop_name = "monitor";
|
||||
#elif __APPLE__
|
||||
prop_name = "display";
|
||||
#else
|
||||
prop_name = "screen";
|
||||
#endif
|
||||
|
||||
ComboSelectToolbar::Init();
|
||||
}
|
||||
|
||||
DeviceCaptureToolbar::DeviceCaptureToolbar(QWidget *parent, OBSSource source)
|
||||
: ComboSelectToolbar(parent, source)
|
||||
{
|
||||
}
|
||||
|
||||
void DeviceCaptureToolbar::Init()
|
||||
{
|
||||
#ifndef _WIN32
|
||||
delete ui->activateButton;
|
||||
ui->activateButton = nullptr;
|
||||
#endif
|
||||
|
||||
obs_module_t *mod =
|
||||
get_os_module("win-dshow", "mac-avcapture", "linux-v4l2");
|
||||
const char *device_str = obs_module_get_locale_text(mod, "Device");
|
||||
ui->deviceLabel->setText(device_str);
|
||||
|
||||
#ifdef _WIN32
|
||||
prop_name = "video_device_id";
|
||||
#elif __APPLE__
|
||||
prop_name = "device";
|
||||
#else
|
||||
prop_name = "device_id";
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
UpdateActivateButtonName();
|
||||
#endif
|
||||
|
||||
ComboSelectToolbar::Init();
|
||||
}
|
||||
|
||||
/* ========================================================================= */
|
||||
|
||||
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");
|
||||
ui->modeLabel->setText(obs_module_get_locale_text(mod, "Mode"));
|
||||
ui->windowLabel->setText(
|
||||
obs_module_get_locale_text(mod, "WindowCapture.Window"));
|
||||
|
||||
obs_data_t *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");
|
||||
obs_data_release(settings);
|
||||
|
||||
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)) {
|
||||
SetComboItemDisabled(ui->window, cur_idx);
|
||||
}
|
||||
|
||||
UpdateWindowVisibility();
|
||||
}
|
||||
|
||||
GameCaptureToolbar::~GameCaptureToolbar()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void GameCaptureToolbar::UpdateWindowVisibility()
|
||||
{
|
||||
QString mode = ui->mode->currentData().toString();
|
||||
bool is_window = (mode == "window");
|
||||
ui->windowLabel->setVisible(is_window);
|
||||
ui->window->setVisible(is_window);
|
||||
ui->empty->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();
|
||||
|
||||
obs_data_t *settings = obs_data_create();
|
||||
obs_data_set_string(settings, "capture_mode", QT_TO_UTF8(id));
|
||||
obs_source_update(source, settings);
|
||||
obs_data_release(settings);
|
||||
|
||||
UpdateWindowVisibility();
|
||||
}
|
||||
|
||||
void GameCaptureToolbar::on_window_currentIndexChanged(int idx)
|
||||
{
|
||||
OBSSource source = GetSource();
|
||||
if (idx == -1 || !source) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString id = ui->window->itemData(idx).toString();
|
||||
|
||||
obs_data_t *settings = obs_data_create();
|
||||
obs_data_set_string(settings, "window", QT_TO_UTF8(id));
|
||||
obs_source_update(source, settings);
|
||||
obs_data_release(settings);
|
||||
}
|
||||
|
||||
/* ========================================================================= */
|
||||
|
||||
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"));
|
||||
|
||||
obs_data_t *settings = obs_source_get_settings(source);
|
||||
std::string file = obs_data_get_string(settings, "file");
|
||||
obs_data_release(settings);
|
||||
|
||||
ui->path->setText(file.c_str());
|
||||
}
|
||||
|
||||
ImageSourceToolbar::~ImageSourceToolbar()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
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 path = OpenFile(this, desc, default_path, filter);
|
||||
if (path.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ui->path->setText(path);
|
||||
|
||||
obs_data_t *settings = obs_data_create();
|
||||
obs_data_set_string(settings, "file", QT_TO_UTF8(path));
|
||||
obs_source_update(source, settings);
|
||||
obs_data_release(settings);
|
||||
}
|
||||
|
||||
/* ========================================================================= */
|
||||
|
||||
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);
|
||||
|
||||
obs_data_t *settings = obs_source_get_settings(source);
|
||||
unsigned int val = (unsigned int)obs_data_get_int(settings, "color");
|
||||
obs_data_release(settings);
|
||||
|
||||
color = color_from_int(val);
|
||||
UpdateColor();
|
||||
}
|
||||
|
||||
ColorSourceToolbar::~ColorSourceToolbar()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void ColorSourceToolbar::UpdateColor()
|
||||
{
|
||||
color.setAlpha(255);
|
||||
|
||||
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;
|
||||
|
||||
#ifndef _WIN32
|
||||
options |= QColorDialog::DontUseNativeDialog;
|
||||
#endif
|
||||
|
||||
color = QColorDialog::getColor(color, this, desc, options);
|
||||
UpdateColor();
|
||||
|
||||
obs_data_t *settings = obs_data_create();
|
||||
obs_data_set_int(settings, "color", color_to_int(color));
|
||||
obs_source_update(source, settings);
|
||||
obs_data_release(settings);
|
||||
}
|
||||
|
||||
/* ========================================================================= */
|
||||
|
||||
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);
|
||||
|
||||
obs_data_t *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");
|
||||
|
||||
obs_data_t *font_obj = obs_data_get_obj(settings, "font");
|
||||
MakeQFont(font_obj, font);
|
||||
obs_data_release(font_obj);
|
||||
|
||||
unsigned int val = (unsigned int)obs_data_get_int(settings, "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);
|
||||
|
||||
obs_data_release(settings);
|
||||
}
|
||||
|
||||
TextSourceToolbar::~TextSourceToolbar()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
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, "Pick a Font",
|
||||
options);
|
||||
if (!success) {
|
||||
return;
|
||||
}
|
||||
|
||||
obs_data_t *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);
|
||||
|
||||
obs_data_t *settings = obs_data_create();
|
||||
|
||||
obs_data_set_obj(settings, "font", font_obj);
|
||||
obs_data_release(font_obj);
|
||||
|
||||
obs_source_update(source, settings);
|
||||
obs_data_release(settings);
|
||||
}
|
||||
|
||||
void TextSourceToolbar::on_selectColor_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;
|
||||
|
||||
#ifndef _WIN32
|
||||
options |= QColorDialog::DontUseNativeDialog;
|
||||
#endif
|
||||
|
||||
QColor newColor = QColorDialog::getColor(color, this, desc, options);
|
||||
if (!newColor.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
color = newColor;
|
||||
|
||||
obs_data_t *settings = obs_data_create();
|
||||
obs_data_set_int(settings, "color", color_to_int(color));
|
||||
obs_source_update(source, settings);
|
||||
obs_data_release(settings);
|
||||
}
|
||||
|
||||
void TextSourceToolbar::on_text_textChanged()
|
||||
{
|
||||
OBSSource source = GetSource();
|
||||
if (!source) {
|
||||
return;
|
||||
}
|
||||
|
||||
obs_data_t *settings = obs_data_create();
|
||||
obs_data_set_string(settings, "text", QT_TO_UTF8(ui->text->text()));
|
||||
obs_source_update(source, settings);
|
||||
obs_data_release(settings);
|
||||
}
|
160
UI/context-bar-controls.hpp
Normal file
@ -0,0 +1,160 @@
|
||||
#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;
|
||||
|
||||
public:
|
||||
SourceToolbar(QWidget *parent, OBSSource source);
|
||||
|
||||
OBSSource GetSource() { return OBSGetStrongRef(weakSource); }
|
||||
|
||||
public slots:
|
||||
virtual void Update() {}
|
||||
};
|
||||
|
||||
class BrowserToolbar : public SourceToolbar {
|
||||
Q_OBJECT
|
||||
|
||||
Ui_BrowserSourceToolbar *ui;
|
||||
|
||||
public:
|
||||
BrowserToolbar(QWidget *parent, OBSSource source);
|
||||
~BrowserToolbar();
|
||||
|
||||
public slots:
|
||||
void on_refresh_clicked();
|
||||
};
|
||||
|
||||
class ComboSelectToolbar : public SourceToolbar {
|
||||
Q_OBJECT
|
||||
|
||||
protected:
|
||||
Ui_DeviceSelectToolbar *ui;
|
||||
const char *prop_name;
|
||||
bool is_int = false;
|
||||
|
||||
void UpdateActivateButtonName();
|
||||
|
||||
public:
|
||||
ComboSelectToolbar(QWidget *parent, OBSSource source);
|
||||
~ComboSelectToolbar();
|
||||
virtual void Init();
|
||||
|
||||
public slots:
|
||||
void on_device_currentIndexChanged(int idx);
|
||||
void on_activateButton_clicked();
|
||||
};
|
||||
|
||||
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 DisplayCaptureToolbar : public ComboSelectToolbar {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DisplayCaptureToolbar(QWidget *parent, OBSSource source);
|
||||
void Init() override;
|
||||
};
|
||||
|
||||
class DeviceCaptureToolbar : public ComboSelectToolbar {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DeviceCaptureToolbar(QWidget *parent, OBSSource source);
|
||||
void Init() override;
|
||||
};
|
||||
|
||||
class GameCaptureToolbar : public SourceToolbar {
|
||||
Q_OBJECT
|
||||
|
||||
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
|
||||
|
||||
Ui_ImageSourceToolbar *ui;
|
||||
|
||||
public:
|
||||
ImageSourceToolbar(QWidget *parent, OBSSource source);
|
||||
~ImageSourceToolbar();
|
||||
|
||||
public slots:
|
||||
void on_browse_clicked();
|
||||
};
|
||||
|
||||
class ColorSourceToolbar : public SourceToolbar {
|
||||
Q_OBJECT
|
||||
|
||||
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
|
||||
|
||||
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();
|
||||
};
|
@ -92,6 +92,7 @@ Calculating="Calculating..."
|
||||
Fullscreen="Fullscreen"
|
||||
Windowed="Windowed"
|
||||
Percent="Percent"
|
||||
RefreshBrowser="Refresh"
|
||||
AspectRatio="Aspect Ratio <b>%1:%2</b>"
|
||||
LockVolume="Lock Volume"
|
||||
LogViewer="Log Viewer"
|
||||
@ -538,6 +539,8 @@ Basic.Main.StoppingReplayBuffer="Stopping Replay Buffer..."
|
||||
Basic.Main.StopStreaming="Stop Streaming"
|
||||
Basic.Main.StoppingStreaming="Stopping Stream..."
|
||||
Basic.Main.ForceStopStreaming="Stop Streaming (discard delay)"
|
||||
Basic.Main.ShowContextBar="Show Source Toolbar"
|
||||
Basic.Main.HideContextBar="Hide Source Toolbar"
|
||||
Basic.Main.StopVirtualCam="Stop Virtual Camera"
|
||||
Basic.Main.Group="Group %1"
|
||||
Basic.Main.GroupItems="Group Selected Items"
|
||||
@ -598,6 +601,7 @@ Basic.MainMenu.View.Docks.ResetUI="Reset UI"
|
||||
Basic.MainMenu.View.Docks.LockUI="Lock UI"
|
||||
Basic.MainMenu.View.Docks.CustomBrowserDocks="Custom Browser Docks..."
|
||||
Basic.MainMenu.View.ListboxToolbars="Scene/Source List Buttons"
|
||||
Basic.MainMenu.View.ContextBar="Source Toolbar"
|
||||
Basic.MainMenu.View.SceneTransitions="S&cene Transitions"
|
||||
Basic.MainMenu.View.SourceIcons="Source &Icons"
|
||||
Basic.MainMenu.View.StatusBar="&Status Bar"
|
||||
@ -1033,3 +1037,18 @@ XSplitBroadcaster="XSplit Broadcaster"
|
||||
# OBS restart
|
||||
Restart="Restart"
|
||||
NeedsRestart="OBS Studio needs to be restarted. Do you want to restart now?"
|
||||
|
||||
# Context Bar
|
||||
ContextBar.NoSelectedSource="No source selected"
|
||||
ContextBar.ResetTransform="Reset Transform"
|
||||
ContextBar.FitToCanvas="Fit to Canvas"
|
||||
|
||||
# Context Bar Media Controls
|
||||
ContextBar.MediaControls.PlayMedia="Play Media"
|
||||
ContextBar.MediaControls.PauseMedia="Pause Media"
|
||||
ContextBar.MediaControls.StopMedia="Stop Media"
|
||||
ContextBar.MediaControls.RestartMedia="Restart Media"
|
||||
ContextBar.MediaControls.PlaylistNext="Next in Playlist"
|
||||
ContextBar.MediaControls.PlaylistPrevious="Previous in Playlist"
|
||||
ContextBar.MediaControls.MediaProperties="Media Properties"
|
||||
ContextBar.MediaControls.BlindSeek="Media Seek Widget"
|
||||
|
@ -311,6 +311,24 @@ QScrollBar::left-arrow:horizontal, QScrollBar::right-arrow:horizontal, QScrollBa
|
||||
color: none;
|
||||
}
|
||||
|
||||
/* Source Context */
|
||||
#contextContainer {
|
||||
min-height: 40px;
|
||||
max-height: 40px;
|
||||
}
|
||||
|
||||
#contextContainer QPushButton[themeID2=contextBarButton] {
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
QPushButton#sourcePropertiesButton {
|
||||
qproperty-icon: url(./Dark/settings/general.svg);
|
||||
}
|
||||
|
||||
QPushButton#sourceFiltersButton {
|
||||
qproperty-icon: url(./Dark/filter.svg);
|
||||
}
|
||||
|
||||
/* Scenes and Sources toolbar */
|
||||
|
||||
QToolBar {
|
||||
@ -1108,3 +1126,29 @@ QSlider::handle:horizontal[themeID="tBarSlider"] {
|
||||
height: 28px;
|
||||
margin: -28px 0px;
|
||||
}
|
||||
|
||||
/* Media icons */
|
||||
|
||||
* [themeID="playIcon"] {
|
||||
qproperty-icon: url(./Dark/media/media_play.svg);
|
||||
}
|
||||
|
||||
* [themeID="pauseIcon"] {
|
||||
qproperty-icon: url(./Dark/media/media_pause.svg);
|
||||
}
|
||||
|
||||
* [themeID="restartIcon"] {
|
||||
qproperty-icon: url(./Dark/media/media_restart.svg);
|
||||
}
|
||||
|
||||
* [themeID="stopIcon"] {
|
||||
qproperty-icon: url(./Dark/media/media_stop.svg);
|
||||
}
|
||||
|
||||
* [themeID="nextIcon"] {
|
||||
qproperty-icon: url(./Dark/media/media_next.svg);
|
||||
}
|
||||
|
||||
* [themeID="previousIcon"] {
|
||||
qproperty-icon: url(./Dark/media/media_previous.svg);
|
||||
}
|
||||
|
@ -220,6 +220,19 @@ QScrollBar::left-arrow:horizontal, QScrollBar::right-arrow:horizontal, QScrollBa
|
||||
color: none;
|
||||
}
|
||||
|
||||
/* Source Context */
|
||||
#contextContainer QPushButton[themeID2=contextBarButton] {
|
||||
padding: 3px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
#contextContainer QPushButton#sourcePropertiesButton {
|
||||
qproperty-icon: url(./Dark/settings/general.svg);
|
||||
}
|
||||
|
||||
#contextContainer QPushButton#sourceFiltersButton {
|
||||
qproperty-icon: url(./Dark/filter.svg);
|
||||
}
|
||||
|
||||
/* Scenes and Sources toolbar */
|
||||
|
||||
@ -839,3 +852,29 @@ QSlider::handle:horizontal[themeID="tBarSlider"] {
|
||||
height: 24px;
|
||||
margin: -24px 0px;
|
||||
}
|
||||
|
||||
/* Media icons */
|
||||
|
||||
* [themeID="playIcon"] {
|
||||
qproperty-icon: url(./Dark/media/media_play.svg);
|
||||
}
|
||||
|
||||
* [themeID="pauseIcon"] {
|
||||
qproperty-icon: url(./Dark/media/media_pause.svg);
|
||||
}
|
||||
|
||||
* [themeID="restartIcon"] {
|
||||
qproperty-icon: url(./Dark/media/media_restart.svg);
|
||||
}
|
||||
|
||||
* [themeID="stopIcon"] {
|
||||
qproperty-icon: url(./Dark/media/media_stop.svg);
|
||||
}
|
||||
|
||||
* [themeID="nextIcon"] {
|
||||
qproperty-icon: url(./Dark/media/media_next.svg);
|
||||
}
|
||||
|
||||
* [themeID="previousIcon"] {
|
||||
qproperty-icon: url(./Dark/media/media_previous.svg);
|
||||
}
|
||||
|
1
UI/data/themes/Dark/filter.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" viewBox="185.25 184.25 100 100" enable-background="new 185.25 184.25 100 100" xml:space="preserve"><g><g><g><path fill="#FFFFFF" d="M204.608,244.706l11.525,11.525c2.041,0.365,4.142,0.556,6.288,0.556c1.898,0,3.761-0.151,5.579-0.438l-22.379-22.38 c0.704-2.995,1.747-5.863,3.092-8.559l28.263,28.263c2.623-1.181,5.076-2.672,7.314-4.426l-30.99-30.99 c1.723-2.143,3.667-4.102,5.796-5.847l31.043,31.043c1.776-2.22,3.29-4.658,4.497-7.268l-28.425-28.426 c2.683-1.367,5.545-2.44,8.546-3.17l22.646,22.646c0.324-1.926,0.495-3.905,0.495-5.923c0-1.985-0.166-3.93-0.479-5.826 l-12.002-12.002c2.857,0.088,5.641,0.482,8.321,1.148c-5.969-11.183-17.752-18.795-31.315-18.795 c-19.592,0-35.475,15.883-35.475,35.475c0,13.563,7.612,25.346,18.796,31.315C205.11,250.078,204.721,247.429,204.608,244.706z"></path></g><path fill="#FFFFFF" d="M243.651,282.651c-0.88-0.002-1.77-0.034-2.644-0.095l0.587-8.494c1.239,0.086,2.503,0.097,3.757,0.035 c1.263-0.063,2.531-0.203,3.768-0.416l1.442,8.392c-1.572,0.27-3.182,0.448-4.785,0.528 C245.069,282.636,244.354,282.653,243.651,282.651z"></path><path fill="#FFFFFF" d="M231.594,280.743c-3.043-0.982-5.969-2.335-8.695-4.023l4.482-7.24c2.142,1.326,4.439,2.389,6.828,3.159L231.594,280.743z "></path><path fill="#FFFFFF" d="M259.738,279.319l-3.419-7.798c2.297-1.007,4.474-2.295,6.47-3.83l5.189,6.751 C265.437,276.395,262.665,278.036,259.738,279.319z"></path><path fill="#FFFFFF" d="M215.423,270.741c-2.244-2.286-4.208-4.839-5.837-7.587l7.325-4.341c1.28,2.16,2.824,4.166,4.588,5.964L215.423,270.741z"></path><path fill="#FFFFFF" d="M274.813,267.741l-6.647-5.322c1.575-1.967,2.909-4.12,3.965-6.398l7.725,3.58 C278.512,262.501,276.815,265.239,274.813,267.741z"></path><path fill="#FFFFFF" d="M282.803,250.48l-8.36-1.614c0.369-1.911,0.559-3.874,0.564-5.833c0.001-0.555-0.012-1.119-0.04-1.675l-0.004-0.072 l8.504-0.425l0.004,0.073c0.035,0.703,0.052,1.418,0.05,2.122C283.515,245.547,283.273,248.046,282.803,250.48z"></path><path fill="#FFFFFF" d="M273.677,233.877c-0.725-2.404-1.744-4.719-3.028-6.881l7.32-4.349c1.637,2.755,2.935,5.706,3.86,8.771L273.677,233.877z"></path><path fill="#FFFFFF" d="M266.055,221.036c-1.766-1.795-3.746-3.376-5.885-4.697l4.475-7.244c2.72,1.68,5.237,3.689,7.481,5.971L266.055,221.036z"></path></g></g></svg>
|
After Width: | Height: | Size: 2.3 KiB |
3
UI/data/themes/Dark/media/media_next.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8" fill="#d2d2d2">
|
||||
<path d="M0 0v6l5-3-5-3zm5 3v3h2v-6h-2v3z" transform="translate(0 1)" />
|
||||
</svg>
|
After Width: | Height: | Size: 177 B |
3
UI/data/themes/Dark/media/media_pause.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8" fill="#d2d2d2">
|
||||
<path d="M0 0v6h2v-6h-2zm4 0v6h2v-6h-2z" transform="translate(1 1)" />
|
||||
</svg>
|
After Width: | Height: | Size: 175 B |
3
UI/data/themes/Dark/media/media_play.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8" fill="#d2d2d2">
|
||||
<path d="M0 0v6l6-3-6-3z" transform="translate(1 1)" />
|
||||
</svg>
|
After Width: | Height: | Size: 160 B |
3
UI/data/themes/Dark/media/media_previous.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8" fill="#d2d2d2">
|
||||
<path d="M0 0v6h2v-6h-2zm2 3l5 3v-6l-5 3z" transform="translate(0 1)" />
|
||||
</svg>
|
After Width: | Height: | Size: 177 B |
3
UI/data/themes/Dark/media/media_restart.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8" fill="#d2d2d2">
|
||||
<path d="M4 0c-2.2 0-4 1.8-4 4s1.8 4 4 4c1.1 0 2.12-.43 2.84-1.16l-.72-.72c-.54.54-1.29.88-2.13.88-1.66 0-3-1.34-3-3s1.34-3 3-3c.83 0 1.55.36 2.09.91l-1.09 1.09h3v-3l-1.19 1.19c-.72-.72-1.71-1.19-2.81-1.19z" />
|
||||
</svg>
|
After Width: | Height: | Size: 315 B |
3
UI/data/themes/Dark/media/media_stop.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8" fill="#d2d2d2">
|
||||
<path d="M0 0v6h6v-6h-6z" transform="translate(1 1)" />
|
||||
</svg>
|
After Width: | Height: | Size: 160 B |
@ -981,6 +981,12 @@ QPushButton[themeID="removeIconSmall"],
|
||||
QPushButton[themeID="configIconSmall"],
|
||||
QPushButton[themeID="trashIcon"],
|
||||
QPushButton[themeID="revertIcon"],
|
||||
QPushButton[themeID="playIcon"],
|
||||
QPushButton[themeID="pauseIcon"],
|
||||
QPushButton[themeID="restartIcon"],
|
||||
QPushButton[themeID="stopIcon"],
|
||||
QPushButton[themeID="nextIcon"],
|
||||
QPushButton[themeID="previousIcon"],
|
||||
QPushButton#transitionRemove,
|
||||
QPushButton#moveAsyncFilterUp,
|
||||
QPushButton#moveAsyncFilterDown,
|
||||
@ -996,6 +1002,12 @@ QPushButton:hover[themeID="removeIconSmall"],
|
||||
QPushButton:hover[themeID="configIconSmall"],
|
||||
QPushButton:hover[themeID="trashIcon"],
|
||||
QPushButton:hover[themeID="revertIcon"],
|
||||
QPushButton:hover[themeID="playIcon"],
|
||||
QPushButton:hover[themeID="pauseIcon"],
|
||||
QPushButton:hover[themeID="restartIcon"],
|
||||
QPushButton:hover[themeID="stopIcon"],
|
||||
QPushButton:hover[themeID="nextIcon"],
|
||||
QPushButton:hover[themeID="previousIcon"],
|
||||
QPushButton:hover#transitionRemove,
|
||||
QPushButton:hover#moveAsyncFilterUp,
|
||||
QPushButton:hover#moveAsyncFilterDown,
|
||||
@ -1409,3 +1421,40 @@ QSlider::handle:horizontal[themeID="tBarSlider"] {
|
||||
height: 24px;
|
||||
margin: -24px 0px;
|
||||
}
|
||||
|
||||
/* Source Context */
|
||||
#contextContainer QPushButton[themeID2=contextBarButton] {
|
||||
padding: 0px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
QPushButton#sourcePropertiesButton {
|
||||
qproperty-icon: url(./Dark/settings/general.svg);
|
||||
}
|
||||
|
||||
QPushButton#sourceFiltersButton {
|
||||
qproperty-icon: url(./Dark/filter.svg);
|
||||
}
|
||||
|
||||
/* Media icons */
|
||||
|
||||
* [themeID="playIcon"] {
|
||||
qproperty-icon: url(./Dark/media/media_play.svg);
|
||||
}
|
||||
|
||||
* [themeID="pauseIcon"] {
|
||||
qproperty-icon: url(./Dark/media/media_pause.svg);
|
||||
}
|
||||
|
||||
* [themeID="restartIcon"] {
|
||||
qproperty-icon: url(./Dark/media/media_restart.svg);
|
||||
}
|
||||
|
||||
* [themeID="stopIcon"] {
|
||||
qproperty-icon: url(./Dark/media/media_stop.svg);
|
||||
}
|
||||
|
||||
* [themeID="nextIcon"] {
|
||||
qproperty-icon: url(./Dark/media/media_next.svg);
|
||||
}
|
||||
|
@ -265,3 +265,34 @@ QSlider::handle:horizontal[themeID="tBarSlider"] {
|
||||
height: 24px;
|
||||
margin: -24px 0px;
|
||||
}
|
||||
|
||||
/* Source Context */
|
||||
#contextContainer QPushButton[themeID2=contextBarButton] {
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
/* Media icons */
|
||||
|
||||
* [themeID="playIcon"] {
|
||||
qproperty-icon: url(:res/images/media/media_play.svg);
|
||||
}
|
||||
|
||||
* [themeID="pauseIcon"] {
|
||||
qproperty-icon: url(:/res/images/media/media_pause.svg);
|
||||
}
|
||||
|
||||
* [themeID="restartIcon"] {
|
||||
qproperty-icon: url(:/res/images/media/media_restart.svg);
|
||||
}
|
||||
|
||||
* [themeID="stopIcon"] {
|
||||
qproperty-icon: url(:/res/images/media/media_stop.svg);
|
||||
}
|
||||
|
||||
* [themeID="nextIcon"] {
|
||||
qproperty-icon: url(:/res/images/media/media_next.svg);
|
||||
}
|
||||
|
||||
* [themeID="previousIcon"] {
|
||||
qproperty-icon: url(./Dark/media/media_previous.svg);
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1079</width>
|
||||
<height>730</height>
|
||||
<height>729</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
@ -195,6 +195,187 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="contextContainer" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout9">
|
||||
<property name="spacing">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetDefaultConstraint</enum>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QWidget" name="contextSubContainer" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="contextSourceLabel">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="sourcePropertiesButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Properties</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Properties</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="obs.qrc">
|
||||
<normaloff>:/settings/images/settings/general.svg</normaloff>:/settings/images/settings/general.svg</iconset>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="themeID2" stdset="0">
|
||||
<string notr="true">contextBarButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="sourceFiltersButton">
|
||||
<property name="toolTip">
|
||||
<string>Filters</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Filters</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="obs.qrc">
|
||||
<normaloff>:/res/images/filter.svg</normaloff>:/res/images/filter.svg</iconset>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="themeID2" stdset="0">
|
||||
<string notr="true">contextBarButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="emptySpace" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
@ -402,6 +583,7 @@
|
||||
<addaction name="separator"/>
|
||||
<addaction name="viewMenuDocks"/>
|
||||
<addaction name="toggleListboxToolbars"/>
|
||||
<addaction name="toggleContextBar"/>
|
||||
<addaction name="toggleSourceIcons"/>
|
||||
<addaction name="toggleStatusBar"/>
|
||||
<addaction name="separator"/>
|
||||
@ -747,7 +929,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>82</width>
|
||||
<width>92</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -801,7 +983,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>16</width>
|
||||
<height>16</height>
|
||||
<height>28</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
@ -1762,6 +1944,25 @@
|
||||
<string>Basic.MainMenu.View.SourceIcons</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="toggleContextToolbars">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Basic.MainMenu.View.Toolbars.Context</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="toggleContextBar">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Basic.MainMenu.View.ContextBar</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
|
1
UI/forms/images/filter.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" viewBox="185.25 184.25 100 100" enable-background="new 185.25 184.25 100 100" xml:space="preserve"><g><g><g><path d="M204.608,244.706l11.525,11.525c2.041,0.365,4.142,0.556,6.288,0.556c1.898,0,3.761-0.151,5.579-0.438l-22.379-22.38 c0.704-2.995,1.747-5.863,3.092-8.559l28.263,28.263c2.623-1.181,5.076-2.672,7.314-4.426l-30.99-30.99 c1.723-2.143,3.667-4.102,5.796-5.847l31.043,31.043c1.776-2.22,3.29-4.658,4.497-7.268l-28.425-28.426 c2.683-1.367,5.545-2.44,8.546-3.17l22.646,22.646c0.324-1.926,0.495-3.905,0.495-5.923c0-1.985-0.166-3.93-0.479-5.826 l-12.002-12.002c2.857,0.088,5.641,0.482,8.321,1.148c-5.969-11.183-17.752-18.795-31.315-18.795 c-19.592,0-35.475,15.883-35.475,35.475c0,13.563,7.612,25.346,18.796,31.315C205.11,250.078,204.721,247.429,204.608,244.706z"></path></g><path d="M243.651,282.651c-0.88-0.002-1.77-0.034-2.644-0.095l0.587-8.494c1.239,0.086,2.503,0.097,3.757,0.035 c1.263-0.063,2.531-0.203,3.768-0.416l1.442,8.392c-1.572,0.27-3.182,0.448-4.785,0.528 C245.069,282.636,244.354,282.653,243.651,282.651z"></path><path d="M231.594,280.743c-3.043-0.982-5.969-2.335-8.695-4.023l4.482-7.24c2.142,1.326,4.439,2.389,6.828,3.159L231.594,280.743z "></path><path d="M259.738,279.319l-3.419-7.798c2.297-1.007,4.474-2.295,6.47-3.83l5.189,6.751 C265.437,276.395,262.665,278.036,259.738,279.319z"></path><path d="M215.423,270.741c-2.244-2.286-4.208-4.839-5.837-7.587l7.325-4.341c1.28,2.16,2.824,4.166,4.588,5.964L215.423,270.741z"></path><path d="M274.813,267.741l-6.647-5.322c1.575-1.967,2.909-4.12,3.965-6.398l7.725,3.58 C278.512,262.501,276.815,265.239,274.813,267.741z"></path><path d="M282.803,250.48l-8.36-1.614c0.369-1.911,0.559-3.874,0.564-5.833c0.001-0.555-0.012-1.119-0.04-1.675l-0.004-0.072 l8.504-0.425l0.004,0.073c0.035,0.703,0.052,1.418,0.05,2.122C283.515,245.547,283.273,248.046,282.803,250.48z"></path><path d="M273.677,233.877c-0.725-2.404-1.744-4.719-3.028-6.881l7.32-4.349c1.637,2.755,2.935,5.706,3.86,8.771L273.677,233.877z"></path><path d="M266.055,221.036c-1.766-1.795-3.746-3.376-5.885-4.697l4.475-7.244c2.72,1.68,5.237,3.689,7.481,5.971L266.055,221.036z"></path></g></g></svg>
|
After Width: | Height: | Size: 2.2 KiB |
3
UI/forms/images/media/media_next.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8">
|
||||
<path d="M0 0v6l5-3-5-3zm5 3v3h2v-6h-2v3z" transform="translate(0 1)" />
|
||||
</svg>
|
After Width: | Height: | Size: 161 B |
3
UI/forms/images/media/media_pause.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8">
|
||||
<path d="M0 0v6h2v-6h-2zm4 0v6h2v-6h-2z" transform="translate(1 1)" />
|
||||
</svg>
|
After Width: | Height: | Size: 159 B |
3
UI/forms/images/media/media_play.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8">
|
||||
<path d="M0 0v6l6-3-6-3z" transform="translate(1 1)" />
|
||||
</svg>
|
After Width: | Height: | Size: 144 B |
3
UI/forms/images/media/media_previous.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8">
|
||||
<path d="M0 0v6h2v-6h-2zm2 3l5 3v-6l-5 3z" transform="translate(0 1)" />
|
||||
</svg>
|
After Width: | Height: | Size: 161 B |
3
UI/forms/images/media/media_restart.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8">
|
||||
<path d="M4 0c-2.2 0-4 1.8-4 4s1.8 4 4 4c1.1 0 2.12-.43 2.84-1.16l-.72-.72c-.54.54-1.29.88-2.13.88-1.66 0-3-1.34-3-3s1.34-3 3-3c.83 0 1.55.36 2.09.91l-1.09 1.09h3v-3l-1.19 1.19c-.72-.72-1.71-1.19-2.81-1.19z" />
|
||||
</svg>
|
After Width: | Height: | Size: 299 B |
3
UI/forms/images/media/media_stop.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8">
|
||||
<path d="M0 0v6h6v-6h-6z" transform="translate(1 1)" />
|
||||
</svg>
|
After Width: | Height: | Size: 144 B |
@ -2,6 +2,7 @@
|
||||
<qresource prefix="/res">
|
||||
<file>images/save.svg</file>
|
||||
<file>images/media-pause.svg</file>
|
||||
<file>images/filter.svg</file>
|
||||
<file>images/mute.svg</file>
|
||||
<file>images/refresh.svg</file>
|
||||
<file>images/no_sources.svg</file>
|
||||
@ -40,6 +41,12 @@
|
||||
<file>images/recording-pause-inactive.svg</file>
|
||||
<file>images/streaming-active.svg</file>
|
||||
<file>images/streaming-inactive.svg</file>
|
||||
<file>images/media/media_play.svg</file>
|
||||
<file>images/media/media_pause.svg</file>
|
||||
<file>images/media/media_next.svg</file>
|
||||
<file>images/media/media_previous.svg</file>
|
||||
<file>images/media/media_restart.svg</file>
|
||||
<file>images/media/media_stop.svg</file>
|
||||
</qresource>
|
||||
<qresource prefix="/settings">
|
||||
<file>images/settings/output.svg</file>
|
||||
|
75
UI/forms/source-toolbar/browser-source-toolbar.ui
Normal file
@ -0,0 +1,75 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>BrowserSourceToolbar</class>
|
||||
<widget class="QWidget" name="BrowserSourceToolbar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>628</width>
|
||||
<height>38</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Form</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="refresh">
|
||||
<property name="text">
|
||||
<string>RefreshBrowser</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../obs.qrc">
|
||||
<normaloff>:/res/images/refresh.svg</normaloff>:/res/images/refresh.svg</iconset>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="themeID" stdset="0">
|
||||
<string notr="true">refreshIconSmall</string>
|
||||
</property>
|
||||
<property name="themeID2" stdset="0">
|
||||
<string notr="true">contextBarButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../obs.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
69
UI/forms/source-toolbar/color-source-toolbar.ui
Normal file
@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ColorSourceToolbar</class>
|
||||
<widget class="QWidget" name="ColorSourceToolbar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>565</width>
|
||||
<height>37</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Form</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="color">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>80</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">color here</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="choose">
|
||||
<property name="text">
|
||||
<string>Basic.PropertiesWindow.SelectColor</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
88
UI/forms/source-toolbar/device-select-toolbar.ui
Normal file
@ -0,0 +1,88 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>DeviceSelectToolbar</class>
|
||||
<widget class="QWidget" name="DeviceSelectToolbar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>665</width>
|
||||
<height>43</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Form</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetNoConstraint</enum>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="deviceLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">Device</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>device</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="device">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="currentText">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QComboBox::AdjustToMinimumContentsLength</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="activateButton">
|
||||
<property name="text">
|
||||
<string notr="true">Activate</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
98
UI/forms/source-toolbar/game-capture-toolbar.ui
Normal file
@ -0,0 +1,98 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>GameCaptureToolbar</class>
|
||||
<widget class="QWidget" name="GameCaptureToolbar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>650</width>
|
||||
<height>29</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Form</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="modeLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">Mode</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>mode</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="mode">
|
||||
<property name="currentText">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="windowLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">Window</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>window</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="window">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="currentText">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QComboBox::AdjustToMinimumContentsLength</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="empty" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
100
UI/forms/source-toolbar/image-source-toolbar.ui
Normal file
@ -0,0 +1,100 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ImageSourceToolbar</class>
|
||||
<widget class="QWidget" name="ImageSourceToolbar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>580</width>
|
||||
<height>41</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Form</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="pathLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">Image File</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>path</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="path">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>600</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="browse">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Browse</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
305
UI/forms/source-toolbar/media-controls.ui
Normal file
@ -0,0 +1,305 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MediaControls</class>
|
||||
<widget class="QWidget" name="MediaControls">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>888</width>
|
||||
<height>28</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Form</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="playPauseButton">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>ContextBar.MediaControls.RestartMedia</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../obs.qrc">
|
||||
<normaloff>:/res/images/media/media_restart.svg</normaloff>:/res/images/media/media_restart.svg</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Space</string>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>8</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="previousButton">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>ContextBar.MediaControls.PlaylistPrevious</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../obs.qrc">
|
||||
<normaloff>:/res/images/media/media_previous.svg</normaloff>:/res/images/media/media_previous.svg</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>P</string>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="stopButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>ContextBar.MediaControls.StopMedia</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../obs.qrc">
|
||||
<normaloff>:/res/images/media/media_stop.svg</normaloff>:/res/images/media/media_stop.svg</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>S</string>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="nextButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>ContextBar.MediaControls.PlaylistNext</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../obs.qrc">
|
||||
<normaloff>:/res/images/media/media_next.svg</normaloff>:/res/images/media/media_next.svg</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>N</string>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="MediaSlider" name="slider">
|
||||
<property name="accessibleName">
|
||||
<string>ContextBar.MediaControls.BlindSeek</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1024</number>
|
||||
</property>
|
||||
<property name="tracking">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>6</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="timerLabel">
|
||||
<property name="text">
|
||||
<string>--:--:--</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>/</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="ClickableLabel" name="durationLabel">
|
||||
<property name="text">
|
||||
<string>--:--:--</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="emptySpaceAgain" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>MediaSlider</class>
|
||||
<extends>QSlider</extends>
|
||||
<header>media-slider.hpp</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ClickableLabel</class>
|
||||
<extends>QLabel</extends>
|
||||
<header>clickable-label.hpp</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../obs.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
60
UI/forms/source-toolbar/text-source-toolbar.ui
Normal file
@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TextSourceToolbar</class>
|
||||
<widget class="QWidget" name="TextSourceToolbar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>726</width>
|
||||
<height>49</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Form</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="selectFont">
|
||||
<property name="text">
|
||||
<string>Basic.PropertiesWindow.SelectFont</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="selectColor">
|
||||
<property name="text">
|
||||
<string>Basic.PropertiesWindow.SelectColor</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="emptySpace" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="text"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
5
UI/locked-checkbox.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
#include "locked-checkbox.hpp"
|
||||
|
||||
LockedCheckBox::LockedCheckBox() {}
|
||||
|
||||
LockedCheckBox::LockedCheckBox(QWidget *parent) : QCheckBox(parent) {}
|
@ -4,4 +4,8 @@
|
||||
|
||||
class LockedCheckBox : public QCheckBox {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
LockedCheckBox();
|
||||
explicit LockedCheckBox(QWidget *parent);
|
||||
};
|
||||
|
428
UI/media-controls.cpp
Normal file
@ -0,0 +1,428 @@
|
||||
#include "window-basic-main.hpp"
|
||||
#include "media-controls.hpp"
|
||||
#include "obs-app.hpp"
|
||||
#include <QToolTip>
|
||||
#include <QStyle>
|
||||
#include <QMenu>
|
||||
|
||||
#include "ui_media-controls.h"
|
||||
|
||||
void MediaControls::OBSMediaStopped(void *data, calldata_t *)
|
||||
{
|
||||
MediaControls *media = static_cast<MediaControls *>(data);
|
||||
QMetaObject::invokeMethod(media, "SetRestartState");
|
||||
}
|
||||
|
||||
void MediaControls::OBSMediaPlay(void *data, calldata_t *)
|
||||
{
|
||||
MediaControls *media = static_cast<MediaControls *>(data);
|
||||
QMetaObject::invokeMethod(media, "SetPlayingState");
|
||||
}
|
||||
|
||||
void MediaControls::OBSMediaPause(void *data, calldata_t *)
|
||||
{
|
||||
MediaControls *media = static_cast<MediaControls *>(data);
|
||||
QMetaObject::invokeMethod(media, "SetPausedState");
|
||||
}
|
||||
|
||||
void MediaControls::OBSMediaStarted(void *data, calldata_t *)
|
||||
{
|
||||
MediaControls *media = static_cast<MediaControls *>(data);
|
||||
QMetaObject::invokeMethod(media, "SetPlayingState");
|
||||
}
|
||||
|
||||
MediaControls::MediaControls(QWidget *parent)
|
||||
: QWidget(parent), ui(new Ui::MediaControls)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->playPauseButton->setProperty("themeID", "playIcon");
|
||||
ui->previousButton->setProperty("themeID", "previousIcon");
|
||||
ui->nextButton->setProperty("themeID", "nextIcon");
|
||||
ui->stopButton->setProperty("themeID", "stopIcon");
|
||||
|
||||
connect(&mediaTimer, SIGNAL(timeout()), this,
|
||||
SLOT(SetSliderPosition()));
|
||||
connect(&seekTimer, SIGNAL(timeout()), this, SLOT(SeekTimerCallback()));
|
||||
connect(ui->slider, SIGNAL(sliderPressed()), this,
|
||||
SLOT(MediaSliderClicked()));
|
||||
connect(ui->slider, SIGNAL(mediaSliderHovered(int)), this,
|
||||
SLOT(MediaSliderHovered(int)));
|
||||
connect(ui->slider, SIGNAL(sliderReleased()), this,
|
||||
SLOT(MediaSliderReleased()));
|
||||
connect(ui->slider, SIGNAL(sliderMoved(int)), this,
|
||||
SLOT(MediaSliderMoved(int)));
|
||||
|
||||
countDownTimer = config_get_bool(App()->GlobalConfig(), "BasicWindow",
|
||||
"MediaControlsCountdownTimer");
|
||||
|
||||
QAction *restartAction = new QAction(this);
|
||||
restartAction->setShortcut({Qt::Key_R});
|
||||
connect(restartAction, SIGNAL(triggered()), this, SLOT(RestartMedia()));
|
||||
addAction(restartAction);
|
||||
}
|
||||
|
||||
MediaControls::~MediaControls()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
bool MediaControls::MediaPaused()
|
||||
{
|
||||
OBSSource source = OBSGetStrongRef(weakSource);
|
||||
if (!source) {
|
||||
return false;
|
||||
}
|
||||
|
||||
obs_media_state state = obs_source_media_get_state(source);
|
||||
return state == OBS_MEDIA_STATE_PAUSED;
|
||||
}
|
||||
|
||||
int64_t MediaControls::GetSliderTime(int val)
|
||||
{
|
||||
OBSSource source = OBSGetStrongRef(weakSource);
|
||||
if (!source) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
float percent = (float)val / (float)ui->slider->maximum();
|
||||
float duration = (float)obs_source_media_get_duration(source);
|
||||
int64_t seekTo = (int64_t)(percent * duration);
|
||||
|
||||
return seekTo;
|
||||
}
|
||||
|
||||
void MediaControls::MediaSliderClicked()
|
||||
{
|
||||
OBSSource source = OBSGetStrongRef(weakSource);
|
||||
if (!source) {
|
||||
return;
|
||||
}
|
||||
|
||||
obs_media_state state = obs_source_media_get_state(source);
|
||||
|
||||
if (state == OBS_MEDIA_STATE_PAUSED) {
|
||||
prevPaused = true;
|
||||
} else if (state == OBS_MEDIA_STATE_PLAYING) {
|
||||
prevPaused = false;
|
||||
PauseMedia();
|
||||
mediaTimer.stop();
|
||||
}
|
||||
|
||||
seek = ui->slider->value();
|
||||
seekTimer.start(100);
|
||||
}
|
||||
|
||||
void MediaControls::MediaSliderReleased()
|
||||
{
|
||||
OBSSource source = OBSGetStrongRef(weakSource);
|
||||
if (!source) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (seekTimer.isActive()) {
|
||||
seekTimer.stop();
|
||||
if (lastSeek != seek) {
|
||||
obs_source_media_set_time(source, GetSliderTime(seek));
|
||||
}
|
||||
|
||||
seek = lastSeek = -1;
|
||||
}
|
||||
|
||||
if (!prevPaused) {
|
||||
PlayMedia();
|
||||
mediaTimer.start(1000);
|
||||
}
|
||||
}
|
||||
|
||||
void MediaControls::MediaSliderHovered(int val)
|
||||
{
|
||||
float seconds = ((float)GetSliderTime(val) / 1000.0f);
|
||||
QToolTip::showText(QCursor::pos(), FormatSeconds((int)seconds), this);
|
||||
}
|
||||
|
||||
void MediaControls::MediaSliderMoved(int val)
|
||||
{
|
||||
if (seekTimer.isActive()) {
|
||||
seek = val;
|
||||
}
|
||||
}
|
||||
|
||||
void MediaControls::SeekTimerCallback()
|
||||
{
|
||||
if (lastSeek != seek) {
|
||||
OBSSource source = OBSGetStrongRef(weakSource);
|
||||
if (source) {
|
||||
obs_source_media_set_time(source, GetSliderTime(seek));
|
||||
}
|
||||
lastSeek = seek;
|
||||
}
|
||||
}
|
||||
|
||||
void MediaControls::StartMediaTimer()
|
||||
{
|
||||
if (isSlideshow)
|
||||
return;
|
||||
|
||||
if (!mediaTimer.isActive())
|
||||
mediaTimer.start(1000);
|
||||
}
|
||||
|
||||
void MediaControls::StopMediaTimer()
|
||||
{
|
||||
if (mediaTimer.isActive())
|
||||
mediaTimer.stop();
|
||||
}
|
||||
|
||||
void MediaControls::SetPlayingState()
|
||||
{
|
||||
ui->slider->setEnabled(true);
|
||||
ui->playPauseButton->setProperty("themeID", "pauseIcon");
|
||||
ui->playPauseButton->style()->unpolish(ui->playPauseButton);
|
||||
ui->playPauseButton->style()->polish(ui->playPauseButton);
|
||||
ui->playPauseButton->setToolTip(
|
||||
QTStr("ContextBar.MediaControls.PauseMedia"));
|
||||
|
||||
prevPaused = false;
|
||||
|
||||
StartMediaTimer();
|
||||
}
|
||||
|
||||
void MediaControls::SetPausedState()
|
||||
{
|
||||
ui->playPauseButton->setProperty("themeID", "playIcon");
|
||||
ui->playPauseButton->style()->unpolish(ui->playPauseButton);
|
||||
ui->playPauseButton->style()->polish(ui->playPauseButton);
|
||||
ui->playPauseButton->setToolTip(
|
||||
QTStr("ContextBar.MediaControls.PlayMedia"));
|
||||
|
||||
StopMediaTimer();
|
||||
}
|
||||
|
||||
void MediaControls::SetRestartState()
|
||||
{
|
||||
ui->playPauseButton->setProperty("themeID", "restartIcon");
|
||||
ui->playPauseButton->style()->unpolish(ui->playPauseButton);
|
||||
ui->playPauseButton->style()->polish(ui->playPauseButton);
|
||||
ui->playPauseButton->setToolTip(
|
||||
QTStr("ContextBar.MediaControls.RestartMedia"));
|
||||
|
||||
ui->slider->setValue(0);
|
||||
ui->timerLabel->setText("--:--:--");
|
||||
ui->durationLabel->setText("--:--:--");
|
||||
ui->slider->setEnabled(false);
|
||||
|
||||
StopMediaTimer();
|
||||
}
|
||||
|
||||
void MediaControls::RefreshControls()
|
||||
{
|
||||
OBSSource source;
|
||||
source = OBSGetStrongRef(weakSource);
|
||||
|
||||
uint32_t flags = 0;
|
||||
const char *id = nullptr;
|
||||
|
||||
if (source) {
|
||||
flags = obs_source_get_output_flags(source);
|
||||
id = obs_source_get_unversioned_id(source);
|
||||
}
|
||||
|
||||
if (!source || !(flags & OBS_SOURCE_CONTROLLABLE_MEDIA)) {
|
||||
SetRestartState();
|
||||
setEnabled(false);
|
||||
hide();
|
||||
return;
|
||||
} else {
|
||||
setEnabled(true);
|
||||
show();
|
||||
}
|
||||
|
||||
bool has_playlist = strcmp(id, "ffmpeg_source") != 0;
|
||||
ui->previousButton->setVisible(has_playlist);
|
||||
ui->nextButton->setVisible(has_playlist);
|
||||
|
||||
isSlideshow = strcmp(id, "slideshow") == 0;
|
||||
ui->slider->setVisible(!isSlideshow);
|
||||
ui->timerLabel->setVisible(!isSlideshow);
|
||||
ui->label->setVisible(!isSlideshow);
|
||||
ui->durationLabel->setVisible(!isSlideshow);
|
||||
ui->emptySpaceAgain->setVisible(isSlideshow);
|
||||
|
||||
obs_media_state state = obs_source_media_get_state(source);
|
||||
|
||||
switch (state) {
|
||||
case OBS_MEDIA_STATE_STOPPED:
|
||||
case OBS_MEDIA_STATE_ENDED:
|
||||
SetRestartState();
|
||||
break;
|
||||
case OBS_MEDIA_STATE_PLAYING:
|
||||
SetPlayingState();
|
||||
break;
|
||||
case OBS_MEDIA_STATE_PAUSED:
|
||||
SetPausedState();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
SetSliderPosition();
|
||||
}
|
||||
|
||||
OBSSource MediaControls::GetSource()
|
||||
{
|
||||
return OBSGetStrongRef(weakSource);
|
||||
}
|
||||
|
||||
void MediaControls::SetSource(OBSSource source)
|
||||
{
|
||||
sigs.clear();
|
||||
|
||||
if (source) {
|
||||
weakSource = OBSGetWeakRef(source);
|
||||
signal_handler_t *sh = obs_source_get_signal_handler(source);
|
||||
sigs.emplace_back(sh, "media_play", OBSMediaPlay, this);
|
||||
sigs.emplace_back(sh, "media_pause", OBSMediaPause, this);
|
||||
sigs.emplace_back(sh, "media_restart", OBSMediaPlay, this);
|
||||
sigs.emplace_back(sh, "media_stopped", OBSMediaStopped, this);
|
||||
sigs.emplace_back(sh, "media_started", OBSMediaStarted, this);
|
||||
sigs.emplace_back(sh, "media_ended", OBSMediaStopped, this);
|
||||
} else {
|
||||
weakSource = nullptr;
|
||||
}
|
||||
|
||||
RefreshControls();
|
||||
}
|
||||
|
||||
void MediaControls::SetSliderPosition()
|
||||
{
|
||||
OBSSource source = OBSGetStrongRef(weakSource);
|
||||
if (!source) {
|
||||
return;
|
||||
}
|
||||
|
||||
float time = (float)obs_source_media_get_time(source);
|
||||
float duration = (float)obs_source_media_get_duration(source);
|
||||
|
||||
float sliderPosition = (time / duration) * (float)ui->slider->maximum();
|
||||
|
||||
ui->slider->setValue((int)sliderPosition);
|
||||
|
||||
ui->timerLabel->setText(FormatSeconds((int)(time / 1000.0f)));
|
||||
|
||||
if (!countDownTimer)
|
||||
ui->durationLabel->setText(
|
||||
FormatSeconds((int)(duration / 1000.0f)));
|
||||
else
|
||||
ui->durationLabel->setText(
|
||||
QString("-") +
|
||||
FormatSeconds((int)((duration - time) / 1000.0f)));
|
||||
}
|
||||
|
||||
QString MediaControls::FormatSeconds(int totalSeconds)
|
||||
{
|
||||
int seconds = totalSeconds % 60;
|
||||
int totalMinutes = totalSeconds / 60;
|
||||
int minutes = totalMinutes % 60;
|
||||
int hours = totalMinutes / 60;
|
||||
|
||||
return QString::asprintf("%02d:%02d:%02d", hours, minutes, seconds);
|
||||
}
|
||||
|
||||
void MediaControls::on_playPauseButton_clicked()
|
||||
{
|
||||
OBSSource source = OBSGetStrongRef(weakSource);
|
||||
if (!source) {
|
||||
return;
|
||||
}
|
||||
|
||||
obs_media_state state = obs_source_media_get_state(source);
|
||||
|
||||
switch (state) {
|
||||
case OBS_MEDIA_STATE_STOPPED:
|
||||
case OBS_MEDIA_STATE_ENDED:
|
||||
RestartMedia();
|
||||
break;
|
||||
case OBS_MEDIA_STATE_PLAYING:
|
||||
PauseMedia();
|
||||
break;
|
||||
case OBS_MEDIA_STATE_PAUSED:
|
||||
PlayMedia();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MediaControls::RestartMedia()
|
||||
{
|
||||
OBSSource source = OBSGetStrongRef(weakSource);
|
||||
if (source) {
|
||||
obs_source_media_restart(source);
|
||||
}
|
||||
}
|
||||
|
||||
void MediaControls::PlayMedia()
|
||||
{
|
||||
OBSSource source = OBSGetStrongRef(weakSource);
|
||||
if (source) {
|
||||
obs_source_media_play_pause(source, false);
|
||||
}
|
||||
}
|
||||
|
||||
void MediaControls::PauseMedia()
|
||||
{
|
||||
OBSSource source = OBSGetStrongRef(weakSource);
|
||||
if (source) {
|
||||
obs_source_media_play_pause(source, true);
|
||||
}
|
||||
}
|
||||
|
||||
void MediaControls::StopMedia()
|
||||
{
|
||||
OBSSource source = OBSGetStrongRef(weakSource);
|
||||
if (source) {
|
||||
obs_source_media_stop(source);
|
||||
}
|
||||
}
|
||||
|
||||
void MediaControls::PlaylistNext()
|
||||
{
|
||||
OBSSource source = OBSGetStrongRef(weakSource);
|
||||
if (source) {
|
||||
obs_source_media_next(source);
|
||||
}
|
||||
}
|
||||
|
||||
void MediaControls::PlaylistPrevious()
|
||||
{
|
||||
OBSSource source = OBSGetStrongRef(weakSource);
|
||||
if (source) {
|
||||
obs_source_media_previous(source);
|
||||
}
|
||||
}
|
||||
|
||||
void MediaControls::on_stopButton_clicked()
|
||||
{
|
||||
StopMedia();
|
||||
}
|
||||
|
||||
void MediaControls::on_nextButton_clicked()
|
||||
{
|
||||
PlaylistNext();
|
||||
}
|
||||
|
||||
void MediaControls::on_previousButton_clicked()
|
||||
{
|
||||
PlaylistPrevious();
|
||||
}
|
||||
|
||||
void MediaControls::on_durationLabel_clicked()
|
||||
{
|
||||
countDownTimer = !countDownTimer;
|
||||
|
||||
config_set_bool(App()->GlobalConfig(), "BasicWindow",
|
||||
"MediaControlsCountdownTimer", countDownTimer);
|
||||
|
||||
if (MediaPaused())
|
||||
SetSliderPosition();
|
||||
}
|
72
UI/media-controls.hpp
Normal file
@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
#include <QTimer>
|
||||
#include <vector>
|
||||
#include <obs.hpp>
|
||||
#include "qt-wrappers.hpp"
|
||||
|
||||
class Ui_MediaControls;
|
||||
|
||||
class MediaControls : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
std::vector<OBSSignal> sigs;
|
||||
OBSWeakSource weakSource = nullptr;
|
||||
QTimer mediaTimer;
|
||||
QTimer seekTimer;
|
||||
int seek;
|
||||
int lastSeek;
|
||||
bool prevPaused = false;
|
||||
bool countDownTimer = false;
|
||||
bool isSlideshow = false;
|
||||
|
||||
QString FormatSeconds(int totalSeconds);
|
||||
void StartMediaTimer();
|
||||
void StopMediaTimer();
|
||||
void RefreshControls();
|
||||
void SetScene(OBSScene scene);
|
||||
int64_t GetSliderTime(int val);
|
||||
|
||||
static void OBSMediaStopped(void *data, calldata_t *calldata);
|
||||
static void OBSMediaPlay(void *data, calldata_t *calldata);
|
||||
static void OBSMediaPause(void *data, calldata_t *calldata);
|
||||
static void OBSMediaStarted(void *data, calldata_t *calldata);
|
||||
|
||||
Ui_MediaControls *ui;
|
||||
|
||||
private slots:
|
||||
void on_playPauseButton_clicked();
|
||||
void on_stopButton_clicked();
|
||||
void on_nextButton_clicked();
|
||||
void on_previousButton_clicked();
|
||||
void on_durationLabel_clicked();
|
||||
|
||||
void MediaSliderClicked();
|
||||
void MediaSliderReleased();
|
||||
void MediaSliderHovered(int val);
|
||||
void MediaSliderMoved(int val);
|
||||
void SetSliderPosition();
|
||||
void SetPlayingState();
|
||||
void SetPausedState();
|
||||
void SetRestartState();
|
||||
void RestartMedia();
|
||||
void StopMedia();
|
||||
void PlaylistNext();
|
||||
void PlaylistPrevious();
|
||||
|
||||
void SeekTimerCallback();
|
||||
|
||||
public slots:
|
||||
void PlayMedia();
|
||||
void PauseMedia();
|
||||
|
||||
public:
|
||||
MediaControls(QWidget *parent = nullptr);
|
||||
~MediaControls();
|
||||
|
||||
OBSSource GetSource();
|
||||
void SetSource(OBSSource newSource);
|
||||
bool MediaPaused();
|
||||
};
|
34
UI/media-slider.cpp
Normal file
@ -0,0 +1,34 @@
|
||||
#include "slider-absoluteset-style.hpp"
|
||||
#include "media-slider.hpp"
|
||||
#include <QStyleFactory>
|
||||
|
||||
MediaSlider::MediaSlider(QWidget *parent) : QSlider(parent)
|
||||
{
|
||||
setMouseTracking(true);
|
||||
|
||||
QString styleName = style()->objectName();
|
||||
QStyle *style;
|
||||
style = QStyleFactory::create(styleName);
|
||||
if (!style) {
|
||||
style = new SliderAbsoluteSetStyle();
|
||||
} else {
|
||||
style = new SliderAbsoluteSetStyle(style);
|
||||
}
|
||||
|
||||
style->setParent(this);
|
||||
this->setStyle(style);
|
||||
}
|
||||
|
||||
void MediaSlider::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
int val = minimum() + ((maximum() - minimum()) * event->x()) / width();
|
||||
|
||||
if (val > maximum())
|
||||
val = maximum();
|
||||
else if (val < minimum())
|
||||
val = minimum();
|
||||
|
||||
emit mediaSliderHovered(val);
|
||||
event->accept();
|
||||
QSlider::mouseMoveEvent(event);
|
||||
}
|
17
UI/media-slider.hpp
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <QSlider>
|
||||
#include <QMouseEvent>
|
||||
|
||||
class MediaSlider : public QSlider {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MediaSlider(QWidget *parent = nullptr);
|
||||
|
||||
signals:
|
||||
void mediaSliderHovered(int value);
|
||||
|
||||
protected:
|
||||
virtual void mouseMoveEvent(QMouseEvent *event) override;
|
||||
};
|
@ -43,6 +43,7 @@
|
||||
#include "window-basic-settings.hpp"
|
||||
#include "crash-report.hpp"
|
||||
#include "platform.hpp"
|
||||
#include "obs-proxy-style.hpp"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
@ -483,6 +484,10 @@ bool OBSApp::InitGlobalConfigDefaults()
|
||||
config_set_default_bool(globalConfig, "Video", "ResetOSXVSyncOnExit",
|
||||
true);
|
||||
#endif
|
||||
|
||||
config_set_default_bool(globalConfig, "BasicWindow",
|
||||
"MediaControlsCountdownTimer", true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1082,6 +1087,7 @@ bool OBSApp::SetTheme(std::string name, std::string path)
|
||||
QString mpath = QString("file:///") + path.c_str();
|
||||
setPalette(defaultPalette);
|
||||
setStyleSheet(mpath);
|
||||
setStyle(new OBSProxyStyle);
|
||||
ParseExtraThemeData(path.c_str());
|
||||
|
||||
emit StyleChanged();
|
||||
|
77
UI/obs-proxy-style.cpp
Normal file
@ -0,0 +1,77 @@
|
||||
#include "obs-proxy-style.hpp"
|
||||
#include <QStyleOptionButton>
|
||||
|
||||
static inline uint qt_intensity(uint r, uint g, uint b)
|
||||
{
|
||||
/* 30% red, 59% green, 11% blue */
|
||||
return (77 * r + 150 * g + 28 * b) / 255;
|
||||
}
|
||||
|
||||
/* The constants in the default QT styles don't dim the icons enough in
|
||||
* disabled mode
|
||||
*
|
||||
* https://code.woboq.org/qt5/qtbase/src/widgets/styles/qcommonstyle.cpp.html#6429
|
||||
*/
|
||||
QPixmap OBSProxyStyle::generatedIconPixmap(QIcon::Mode iconMode,
|
||||
const QPixmap &pixmap,
|
||||
const QStyleOption *option) const
|
||||
{
|
||||
if (iconMode == QIcon::Disabled) {
|
||||
QImage im =
|
||||
pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
|
||||
|
||||
/* Create a colortable based on the background
|
||||
* (black -> bg -> white) */
|
||||
|
||||
QColor bg = option->palette.color(QPalette::Disabled,
|
||||
QPalette::Window);
|
||||
int red = bg.red();
|
||||
int green = bg.green();
|
||||
int blue = bg.blue();
|
||||
uchar reds[256], greens[256], blues[256];
|
||||
|
||||
for (int i = 0; i < 128; ++i) {
|
||||
reds[i] = uchar((red * (i << 1)) >> 8);
|
||||
greens[i] = uchar((green * (i << 1)) >> 8);
|
||||
blues[i] = uchar((blue * (i << 1)) >> 8);
|
||||
}
|
||||
for (int i = 0; i < 128; ++i) {
|
||||
reds[i + 128] = uchar(qMin(red + (i << 1), 255));
|
||||
greens[i + 128] = uchar(qMin(green + (i << 1), 255));
|
||||
blues[i + 128] = uchar(qMin(blue + (i << 1), 255));
|
||||
}
|
||||
|
||||
/* High intensity colors needs dark shifting in the color
|
||||
* table, while low intensity colors needs light shifting. This
|
||||
* is to increase the perceived contrast. */
|
||||
|
||||
int intensity = qt_intensity(red, green, blue);
|
||||
const int factor = 191;
|
||||
|
||||
if ((red - factor > green && red - factor > blue) ||
|
||||
(green - factor > red && green - factor > blue) ||
|
||||
(blue - factor > red && blue - factor > green))
|
||||
qMin(255, intensity + 20);
|
||||
else if (intensity <= 128)
|
||||
intensity += 100;
|
||||
|
||||
for (int y = 0; y < im.height(); ++y) {
|
||||
QRgb *scanLine = (QRgb *)im.scanLine(y);
|
||||
for (int x = 0; x < im.width(); ++x) {
|
||||
QRgb pixel = *scanLine;
|
||||
/* Calculate color table index, taking
|
||||
* intensity adjustment and a magic offset into
|
||||
* account. */
|
||||
uint ci = uint(qGray(pixel) / 3 +
|
||||
(130 - intensity / 3));
|
||||
*scanLine = qRgba(reds[ci], greens[ci],
|
||||
blues[ci], qAlpha(pixel));
|
||||
++scanLine;
|
||||
}
|
||||
}
|
||||
|
||||
return QPixmap::fromImage(im);
|
||||
}
|
||||
|
||||
return QProxyStyle::generatedIconPixmap(iconMode, pixmap, option);
|
||||
}
|
9
UI/obs-proxy-style.hpp
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <QProxyStyle>
|
||||
|
||||
class OBSProxyStyle : public QProxyStyle {
|
||||
public:
|
||||
QPixmap generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap,
|
||||
const QStyleOption *option) const override;
|
||||
};
|
@ -684,7 +684,7 @@ void OBSPropertiesView::AddColor(obs_property_t *prop, QFormLayout *layout,
|
||||
layout->addRow(label, subLayout);
|
||||
}
|
||||
|
||||
static void MakeQFont(obs_data_t *font_obj, QFont &font, bool limit = false)
|
||||
void MakeQFont(obs_data_t *font_obj, QFont &font, bool limit = false)
|
||||
{
|
||||
const char *face = obs_data_get_string(font_obj, "face");
|
||||
const char *style = obs_data_get_string(font_obj, "style");
|
||||
|
@ -528,11 +528,13 @@ void SourceTreeItem::ExpandClicked(bool checked)
|
||||
void SourceTreeItem::Select()
|
||||
{
|
||||
tree->SelectItem(sceneitem, true);
|
||||
OBSBasic::Get()->UpdateContextBar();
|
||||
}
|
||||
|
||||
void SourceTreeItem::Deselect()
|
||||
{
|
||||
tree->SelectItem(sceneitem, false);
|
||||
OBSBasic::Get()->UpdateContextBar();
|
||||
}
|
||||
|
||||
/* ========================================================================= */
|
||||
|
5
UI/visibility-checkbox.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
#include "visibility-checkbox.hpp"
|
||||
|
||||
VisibilityCheckBox::VisibilityCheckBox() {}
|
||||
|
||||
VisibilityCheckBox::VisibilityCheckBox(QWidget *parent) : QCheckBox(parent) {}
|
@ -4,4 +4,8 @@
|
||||
|
||||
class VisibilityCheckBox : public QCheckBox {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
VisibilityCheckBox();
|
||||
explicit VisibilityCheckBox(QWidget *parent);
|
||||
};
|
||||
|
@ -52,10 +52,12 @@
|
||||
#include "window-projector.hpp"
|
||||
#include "window-remux.hpp"
|
||||
#include "qt-wrappers.hpp"
|
||||
#include "context-bar-controls.hpp"
|
||||
#include "display-helpers.hpp"
|
||||
#include "volume-control.hpp"
|
||||
#include "remote-text.hpp"
|
||||
#include "ui-validation.hpp"
|
||||
#include "media-controls.hpp"
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
@ -355,6 +357,8 @@ OBSBasic::OBSBasic(QWidget *parent)
|
||||
|
||||
QPoint curPos;
|
||||
|
||||
UpdateContextBar();
|
||||
|
||||
//restore parent window geometry
|
||||
const char *geometry = config_get_string(App()->GlobalConfig(),
|
||||
"BasicWindow", "geometry");
|
||||
@ -1721,6 +1725,18 @@ void OBSBasic::OBSInit()
|
||||
GetGlobalConfig(), "BasicWindow", "ShowSourceIcons");
|
||||
ui->toggleSourceIcons->setChecked(sourceIconsVisible);
|
||||
|
||||
if (config_has_user_value(App()->GlobalConfig(), "BasicWindow",
|
||||
"ShowContextToolbars")) {
|
||||
bool visible = config_get_bool(App()->GlobalConfig(),
|
||||
"BasicWindow",
|
||||
"ShowContextToolbars");
|
||||
ui->toggleContextBar->setChecked(visible);
|
||||
ui->contextContainer->setVisible(visible);
|
||||
} else {
|
||||
ui->toggleContextBar->setChecked(true);
|
||||
ui->contextContainer->setVisible(true);
|
||||
}
|
||||
|
||||
{
|
||||
ProfileScope("OBSBasic::Load");
|
||||
disableSaving--;
|
||||
@ -1803,6 +1819,7 @@ void OBSBasic::OBSInit()
|
||||
|
||||
const char *dockStateStr = config_get_string(
|
||||
App()->GlobalConfig(), "BasicWindow", "DockState");
|
||||
|
||||
if (!dockStateStr) {
|
||||
on_resetUI_triggered();
|
||||
} else {
|
||||
@ -2314,6 +2331,17 @@ void OBSBasic::CreateHotkeys()
|
||||
this, this);
|
||||
LoadHotkeyPair(togglePreviewHotkeys, "OBSBasic.EnablePreview",
|
||||
"OBSBasic.DisablePreview");
|
||||
|
||||
contextBarHotkeys = obs_hotkey_pair_register_frontend(
|
||||
"OBSBasic.ShowContextBar", Str("Basic.Main.ShowContextBar"),
|
||||
"OBSBasic.HideContextBar", Str("Basic.Main.HideContextBar"),
|
||||
MAKE_CALLBACK(!basic.ui->contextContainer->isVisible(),
|
||||
basic.ShowContextBar, "Showing Context Bar"),
|
||||
MAKE_CALLBACK(basic.ui->contextContainer->isVisible(),
|
||||
basic.HideContextBar, "Hiding Context Bar"),
|
||||
this, this);
|
||||
LoadHotkeyPair(contextBarHotkeys, "OBSBasic.ShowContextBar",
|
||||
"OBSBasic.HideContextBar");
|
||||
#undef MAKE_CALLBACK
|
||||
|
||||
auto togglePreviewProgram = [](void *data, obs_hotkey_id,
|
||||
@ -2844,6 +2872,107 @@ void OBSBasic::RenameSources(OBSSource source, QString newName,
|
||||
obs_scene_t *scene = obs_scene_from_source(source);
|
||||
if (scene)
|
||||
OBSProjector::UpdateMultiviewProjectors();
|
||||
|
||||
UpdateContextBar();
|
||||
}
|
||||
|
||||
void OBSBasic::UpdateContextBar()
|
||||
{
|
||||
OBSSceneItem item = GetCurrentSceneItem();
|
||||
|
||||
QLayoutItem *la = ui->emptySpace->layout()->itemAt(0);
|
||||
if (la) {
|
||||
delete la->widget();
|
||||
ui->emptySpace->layout()->removeItem(la);
|
||||
}
|
||||
|
||||
if (item) {
|
||||
obs_source_t *source = obs_sceneitem_get_source(item);
|
||||
const char *id = obs_source_get_unversioned_id(source);
|
||||
uint32_t flags = obs_source_get_output_flags(source);
|
||||
|
||||
if (flags & OBS_SOURCE_CONTROLLABLE_MEDIA) {
|
||||
MediaControls *mediaControls =
|
||||
new MediaControls(ui->emptySpace);
|
||||
mediaControls->SetSource(source);
|
||||
|
||||
ui->emptySpace->layout()->addWidget(mediaControls);
|
||||
}
|
||||
|
||||
if (strcmp(id, "browser_source") == 0) {
|
||||
BrowserToolbar *c =
|
||||
new BrowserToolbar(ui->emptySpace, source);
|
||||
ui->emptySpace->layout()->addWidget(c);
|
||||
|
||||
} else if (strcmp(id, "wasapi_input_capture") == 0 ||
|
||||
strcmp(id, "wasapi_output_capture") == 0 ||
|
||||
strcmp(id, "coreaudio_input_capture") == 0 ||
|
||||
strcmp(id, "coreaudio_output_capture") == 0 ||
|
||||
strcmp(id, "pulse_input_capture") == 0 ||
|
||||
strcmp(id, "pulse_output_capture") == 0 ||
|
||||
strcmp(id, "alsa_input_capture") == 0) {
|
||||
AudioCaptureToolbar *c =
|
||||
new AudioCaptureToolbar(ui->emptySpace, source);
|
||||
c->Init();
|
||||
ui->emptySpace->layout()->addWidget(c);
|
||||
|
||||
} else if (strcmp(id, "window_capture") == 0 ||
|
||||
strcmp(id, "xcomposite_input") == 0) {
|
||||
WindowCaptureToolbar *c = new WindowCaptureToolbar(
|
||||
ui->emptySpace, source);
|
||||
c->Init();
|
||||
ui->emptySpace->layout()->addWidget(c);
|
||||
|
||||
} else if (strcmp(id, "monitor_capture") == 0 ||
|
||||
strcmp(id, "display_capture") == 0 ||
|
||||
strcmp(id, "xshm_input") == 0) {
|
||||
DisplayCaptureToolbar *c = new DisplayCaptureToolbar(
|
||||
ui->emptySpace, source);
|
||||
c->Init();
|
||||
ui->emptySpace->layout()->addWidget(c);
|
||||
|
||||
} else if (strcmp(id, "dshow_input") == 0 ||
|
||||
strcmp(id, "av_capture_input") == 0 ||
|
||||
strcmp(id, "v4l2_input") == 0) {
|
||||
DeviceCaptureToolbar *c = new DeviceCaptureToolbar(
|
||||
ui->emptySpace, source);
|
||||
c->Init();
|
||||
ui->emptySpace->layout()->addWidget(c);
|
||||
|
||||
} else if (strcmp(id, "game_capture") == 0) {
|
||||
GameCaptureToolbar *c =
|
||||
new GameCaptureToolbar(ui->emptySpace, source);
|
||||
ui->emptySpace->layout()->addWidget(c);
|
||||
|
||||
} else if (strcmp(id, "image_source") == 0) {
|
||||
ImageSourceToolbar *c =
|
||||
new ImageSourceToolbar(ui->emptySpace, source);
|
||||
ui->emptySpace->layout()->addWidget(c);
|
||||
|
||||
} else if (strcmp(id, "color_source") == 0) {
|
||||
ColorSourceToolbar *c =
|
||||
new ColorSourceToolbar(ui->emptySpace, source);
|
||||
ui->emptySpace->layout()->addWidget(c);
|
||||
|
||||
} else if (strcmp(id, "text_ft2_source") == 0 ||
|
||||
strcmp(id, "text_gdiplus") == 0) {
|
||||
TextSourceToolbar *c =
|
||||
new TextSourceToolbar(ui->emptySpace, source);
|
||||
ui->emptySpace->layout()->addWidget(c);
|
||||
}
|
||||
|
||||
const char *name = obs_source_get_name(source);
|
||||
ui->contextSourceLabel->setText(name);
|
||||
|
||||
ui->sourceFiltersButton->setEnabled(true);
|
||||
ui->sourcePropertiesButton->setEnabled(true);
|
||||
} else {
|
||||
ui->contextSourceLabel->setText(
|
||||
QTStr("ContextBar.NoSelectedSource"));
|
||||
|
||||
ui->sourceFiltersButton->setEnabled(false);
|
||||
ui->sourcePropertiesButton->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool SourceMixerHidden(obs_source_t *source)
|
||||
@ -4221,6 +4350,8 @@ void OBSBasic::on_scenes_currentItemChanged(QListWidgetItem *current,
|
||||
if (api)
|
||||
api->on_event(OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED);
|
||||
|
||||
UpdateContextBar();
|
||||
|
||||
UNUSED_PARAMETER(prev);
|
||||
}
|
||||
|
||||
@ -7146,6 +7277,23 @@ void OBSBasic::on_toggleListboxToolbars_toggled(bool visible)
|
||||
"ShowListboxToolbars", visible);
|
||||
}
|
||||
|
||||
void OBSBasic::ShowContextBar()
|
||||
{
|
||||
on_toggleContextBar_toggled(true);
|
||||
}
|
||||
|
||||
void OBSBasic::HideContextBar()
|
||||
{
|
||||
on_toggleContextBar_toggled(false);
|
||||
}
|
||||
|
||||
void OBSBasic::on_toggleContextBar_toggled(bool visible)
|
||||
{
|
||||
config_set_bool(App()->GlobalConfig(), "BasicWindow",
|
||||
"ShowContextToolbars", visible);
|
||||
this->ui->contextContainer->setVisible(visible);
|
||||
}
|
||||
|
||||
void OBSBasic::on_toggleStatusBar_toggled(bool visible)
|
||||
{
|
||||
ui->statusbar->setVisible(visible);
|
||||
@ -8125,3 +8273,13 @@ void OBSBasic::UpdateProjectorAlwaysOnTop(bool top)
|
||||
for (size_t i = 0; i < projectors.size(); i++)
|
||||
SetAlwaysOnTop(projectors[i], top);
|
||||
}
|
||||
|
||||
void OBSBasic::on_sourcePropertiesButton_clicked()
|
||||
{
|
||||
on_actionSourceProperties_triggered();
|
||||
}
|
||||
|
||||
void OBSBasic::on_sourceFiltersButton_clicked()
|
||||
{
|
||||
OpenFilters();
|
||||
}
|
||||
|
@ -379,7 +379,8 @@ private:
|
||||
QModelIndexList GetAllSelectedSourceItems();
|
||||
|
||||
obs_hotkey_pair_id streamingHotkeys, recordingHotkeys, pauseHotkeys,
|
||||
replayBufHotkeys, vcamHotkeys, togglePreviewHotkeys;
|
||||
replayBufHotkeys, vcamHotkeys, togglePreviewHotkeys,
|
||||
contextBarHotkeys;
|
||||
obs_hotkey_id forceStreamingStopHotkey;
|
||||
|
||||
void InitDefaultTransitions();
|
||||
@ -585,6 +586,8 @@ public slots:
|
||||
|
||||
void UpdatePatronJson(const QString &text, const QString &error);
|
||||
|
||||
void ShowContextBar();
|
||||
void HideContextBar();
|
||||
void PauseRecording();
|
||||
void UnpauseRecording();
|
||||
|
||||
@ -928,6 +931,7 @@ private slots:
|
||||
void on_actionAlwaysOnTop_triggered();
|
||||
|
||||
void on_toggleListboxToolbars_toggled(bool visible);
|
||||
void on_toggleContextBar_toggled(bool visible);
|
||||
void on_toggleStatusBar_toggled(bool visible);
|
||||
void on_toggleSourceIcons_toggled(bool visible);
|
||||
|
||||
@ -938,6 +942,10 @@ private slots:
|
||||
|
||||
void on_modeSwitch_clicked();
|
||||
|
||||
// Source Context Buttons
|
||||
void on_sourcePropertiesButton_clicked();
|
||||
void on_sourceFiltersButton_clicked();
|
||||
|
||||
void on_autoConfigure_triggered();
|
||||
void on_stats_triggered();
|
||||
|
||||
@ -999,6 +1007,8 @@ public slots:
|
||||
bool RecordingActive();
|
||||
bool ReplayBufferActive();
|
||||
|
||||
void UpdateContextBar();
|
||||
|
||||
public:
|
||||
explicit OBSBasic(QWidget *parent = 0);
|
||||
virtual ~OBSBasic();
|
||||
|
@ -205,6 +205,7 @@ OBSBasicProperties::~OBSBasicProperties()
|
||||
}
|
||||
obs_source_dec_showing(source);
|
||||
main->SaveProject();
|
||||
main->UpdateContextBar();
|
||||
}
|
||||
|
||||
void OBSBasicProperties::AddPreviewButton()
|
||||
|