mirror of
https://github.com/obsproject/obs-studio
synced 2024-10-24 00:21:34 +00:00
Merge pull request #1935 from obsproject/clang-format
Apply clang-format to the project
This commit is contained in:
commit
c938ea712b
106
.clang-format
Normal file
106
.clang-format
Normal file
|
@ -0,0 +1,106 @@
|
|||
# please use clang-format version 8 or later
|
||||
|
||||
Language: Cpp
|
||||
Standard: Cpp11
|
||||
AccessModifierOffset: -8
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlines: Left
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
#AllowAllArgumentsOnNextLine: false # requires clang-format 9
|
||||
#AllowAllConstructorInitializersOnNextLine: false # requires clang-format 9
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
#AllowShortLambdasOnASingleLine: Inline # requires clang-format 9
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: false
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterClass: false
|
||||
AfterControlStatement: false
|
||||
AfterEnum: false
|
||||
AfterFunction: true
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakStringLiterals: false # apparently unpredictable
|
||||
ColumnLimit: 80
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 8
|
||||
ContinuationIndentWidth: 8
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
FixNamespaceComments: false
|
||||
ForEachMacros:
|
||||
- 'json_object_foreach'
|
||||
- 'json_object_foreach_safe'
|
||||
- 'json_array_foreach'
|
||||
IncludeBlocks: Preserve
|
||||
IndentCaseLabels: false
|
||||
IndentPPDirectives: None
|
||||
IndentWidth: 8
|
||||
IndentWrappedFunctionNames: false
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBinPackProtocolList: Auto # requires clang-format 7
|
||||
ObjCBlockIndentWidth: 8
|
||||
ObjCSpaceAfterProperty: true
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
|
||||
PenaltyBreakAssignment: 10
|
||||
PenaltyBreakBeforeFirstCallParameter: 30
|
||||
PenaltyBreakComment: 10
|
||||
PenaltyBreakFirstLessLess: 0
|
||||
PenaltyBreakString: 10
|
||||
PenaltyExcessCharacter: 100
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
|
||||
PointerAlignment: Right
|
||||
ReflowComments: false
|
||||
SortIncludes: false
|
||||
SortUsingDeclarations: false
|
||||
SpaceAfterCStyleCast: false
|
||||
#SpaceAfterLogicalNot: false # requires clang-format 9
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCtorInitializerColon: true # requires clang-format 7
|
||||
SpaceBeforeInheritanceColon: true # requires clang-format 7
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: true # requires clang-format 7
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
StatementMacros: # requires clang-format 8
|
||||
- 'Q_OBJECT'
|
||||
TabWidth: 8
|
||||
#TypenameMacros: # requires clang-format 9
|
||||
# - 'DARRAY'
|
||||
UseTab: ForContinuationAndIndentation
|
|
@ -26,34 +26,34 @@ OBSAdvAudioCtrl::OBSAdvAudioCtrl(QGridLayout *, obs_source_t *source_)
|
|||
uint32_t flags = obs_source_get_flags(source);
|
||||
uint32_t mixers = obs_source_get_audio_mixers(source);
|
||||
|
||||
forceMonoContainer = new QWidget();
|
||||
mixerContainer = new QWidget();
|
||||
balanceContainer = new QWidget();
|
||||
labelL = new QLabel();
|
||||
labelR = new QLabel();
|
||||
nameLabel = new QLabel();
|
||||
volume = new QDoubleSpinBox();
|
||||
forceMono = new QCheckBox();
|
||||
balance = new BalanceSlider();
|
||||
forceMonoContainer = new QWidget();
|
||||
mixerContainer = new QWidget();
|
||||
balanceContainer = new QWidget();
|
||||
labelL = new QLabel();
|
||||
labelR = new QLabel();
|
||||
nameLabel = new QLabel();
|
||||
volume = new QDoubleSpinBox();
|
||||
forceMono = new QCheckBox();
|
||||
balance = new BalanceSlider();
|
||||
#if defined(_WIN32) || defined(__APPLE__) || HAVE_PULSEAUDIO
|
||||
monitoringType = new QComboBox();
|
||||
monitoringType = new QComboBox();
|
||||
#endif
|
||||
syncOffset = new QSpinBox();
|
||||
mixer1 = new QCheckBox();
|
||||
mixer2 = new QCheckBox();
|
||||
mixer3 = new QCheckBox();
|
||||
mixer4 = new QCheckBox();
|
||||
mixer5 = new QCheckBox();
|
||||
mixer6 = new QCheckBox();
|
||||
syncOffset = new QSpinBox();
|
||||
mixer1 = new QCheckBox();
|
||||
mixer2 = new QCheckBox();
|
||||
mixer3 = new QCheckBox();
|
||||
mixer4 = new QCheckBox();
|
||||
mixer5 = new QCheckBox();
|
||||
mixer6 = new QCheckBox();
|
||||
|
||||
volChangedSignal.Connect(handler, "volume", OBSSourceVolumeChanged,
|
||||
this);
|
||||
this);
|
||||
syncOffsetSignal.Connect(handler, "audio_sync", OBSSourceSyncChanged,
|
||||
this);
|
||||
this);
|
||||
flagsSignal.Connect(handler, "update_flags", OBSSourceFlagsChanged,
|
||||
this);
|
||||
this);
|
||||
mixersSignal.Connect(handler, "audio_mixers", OBSSourceMixersChanged,
|
||||
this);
|
||||
this);
|
||||
|
||||
hlayout = new QHBoxLayout();
|
||||
hlayout->setContentsMargins(0, 0, 0, 0);
|
||||
|
@ -87,8 +87,8 @@ OBSAdvAudioCtrl::OBSAdvAudioCtrl(QGridLayout *, obs_source_t *source_)
|
|||
forceMono->setChecked((flags & OBS_SOURCE_FLAG_FORCE_MONO) != 0);
|
||||
|
||||
forceMonoContainer->layout()->addWidget(forceMono);
|
||||
forceMonoContainer->layout()->setAlignment(forceMono,
|
||||
Qt::AlignHCenter | Qt::AlignVCenter);
|
||||
forceMonoContainer->layout()->setAlignment(
|
||||
forceMono, Qt::AlignHCenter | Qt::AlignVCenter);
|
||||
|
||||
balance->setOrientation(Qt::Horizontal);
|
||||
balance->setMinimum(0);
|
||||
|
@ -96,10 +96,10 @@ OBSAdvAudioCtrl::OBSAdvAudioCtrl(QGridLayout *, obs_source_t *source_)
|
|||
balance->setTickPosition(QSlider::TicksAbove);
|
||||
balance->setTickInterval(50);
|
||||
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
|
||||
|
||||
const char *speakers = config_get_string(main->Config(), "Audio",
|
||||
"ChannelSetup");
|
||||
const char *speakers =
|
||||
config_get_string(main->Config(), "Audio", "ChannelSetup");
|
||||
|
||||
if (strcmp(speakers, "Mono") == 0)
|
||||
balance->setEnabled(false);
|
||||
|
@ -117,28 +117,28 @@ OBSAdvAudioCtrl::OBSAdvAudioCtrl(QGridLayout *, obs_source_t *source_)
|
|||
int idx;
|
||||
#if defined(_WIN32) || defined(__APPLE__) || HAVE_PULSEAUDIO
|
||||
monitoringType->addItem(QTStr("Basic.AdvAudio.Monitoring.None"),
|
||||
(int)OBS_MONITORING_TYPE_NONE);
|
||||
(int)OBS_MONITORING_TYPE_NONE);
|
||||
monitoringType->addItem(QTStr("Basic.AdvAudio.Monitoring.MonitorOnly"),
|
||||
(int)OBS_MONITORING_TYPE_MONITOR_ONLY);
|
||||
(int)OBS_MONITORING_TYPE_MONITOR_ONLY);
|
||||
monitoringType->addItem(QTStr("Basic.AdvAudio.Monitoring.Both"),
|
||||
(int)OBS_MONITORING_TYPE_MONITOR_AND_OUTPUT);
|
||||
(int)OBS_MONITORING_TYPE_MONITOR_AND_OUTPUT);
|
||||
int mt = (int)obs_source_get_monitoring_type(source);
|
||||
idx = monitoringType->findData(mt);
|
||||
monitoringType->setCurrentIndex(idx);
|
||||
#endif
|
||||
|
||||
mixer1->setText("1");
|
||||
mixer1->setChecked(mixers & (1<<0));
|
||||
mixer1->setChecked(mixers & (1 << 0));
|
||||
mixer2->setText("2");
|
||||
mixer2->setChecked(mixers & (1<<1));
|
||||
mixer2->setChecked(mixers & (1 << 1));
|
||||
mixer3->setText("3");
|
||||
mixer3->setChecked(mixers & (1<<2));
|
||||
mixer3->setChecked(mixers & (1 << 2));
|
||||
mixer4->setText("4");
|
||||
mixer4->setChecked(mixers & (1<<3));
|
||||
mixer4->setChecked(mixers & (1 << 3));
|
||||
mixer5->setText("5");
|
||||
mixer5->setChecked(mixers & (1<<4));
|
||||
mixer5->setChecked(mixers & (1 << 4));
|
||||
mixer6->setText("6");
|
||||
mixer6->setChecked(mixers & (1<<5));
|
||||
mixer6->setChecked(mixers & (1 << 5));
|
||||
|
||||
speaker_layout sl = obs_source_get_speaker_layout(source);
|
||||
|
||||
|
@ -156,32 +156,32 @@ OBSAdvAudioCtrl::OBSAdvAudioCtrl(QGridLayout *, obs_source_t *source_)
|
|||
mixerContainer->layout()->addWidget(mixer5);
|
||||
mixerContainer->layout()->addWidget(mixer6);
|
||||
|
||||
QWidget::connect(volume, SIGNAL(valueChanged(double)),
|
||||
this, SLOT(volumeChanged(double)));
|
||||
QWidget::connect(forceMono, SIGNAL(clicked(bool)),
|
||||
this, SLOT(downmixMonoChanged(bool)));
|
||||
QWidget::connect(balance, SIGNAL(valueChanged(int)),
|
||||
this, SLOT(balanceChanged(int)));
|
||||
QWidget::connect(balance, SIGNAL(doubleClicked()),
|
||||
this, SLOT(ResetBalance()));
|
||||
QWidget::connect(syncOffset, SIGNAL(valueChanged(int)),
|
||||
this, SLOT(syncOffsetChanged(int)));
|
||||
QWidget::connect(volume, SIGNAL(valueChanged(double)), this,
|
||||
SLOT(volumeChanged(double)));
|
||||
QWidget::connect(forceMono, SIGNAL(clicked(bool)), this,
|
||||
SLOT(downmixMonoChanged(bool)));
|
||||
QWidget::connect(balance, SIGNAL(valueChanged(int)), this,
|
||||
SLOT(balanceChanged(int)));
|
||||
QWidget::connect(balance, SIGNAL(doubleClicked()), this,
|
||||
SLOT(ResetBalance()));
|
||||
QWidget::connect(syncOffset, SIGNAL(valueChanged(int)), this,
|
||||
SLOT(syncOffsetChanged(int)));
|
||||
#if defined(_WIN32) || defined(__APPLE__) || HAVE_PULSEAUDIO
|
||||
QWidget::connect(monitoringType, SIGNAL(currentIndexChanged(int)),
|
||||
this, SLOT(monitoringTypeChanged(int)));
|
||||
QWidget::connect(monitoringType, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(monitoringTypeChanged(int)));
|
||||
#endif
|
||||
QWidget::connect(mixer1, SIGNAL(clicked(bool)),
|
||||
this, SLOT(mixer1Changed(bool)));
|
||||
QWidget::connect(mixer2, SIGNAL(clicked(bool)),
|
||||
this, SLOT(mixer2Changed(bool)));
|
||||
QWidget::connect(mixer3, SIGNAL(clicked(bool)),
|
||||
this, SLOT(mixer3Changed(bool)));
|
||||
QWidget::connect(mixer4, SIGNAL(clicked(bool)),
|
||||
this, SLOT(mixer4Changed(bool)));
|
||||
QWidget::connect(mixer5, SIGNAL(clicked(bool)),
|
||||
this, SLOT(mixer5Changed(bool)));
|
||||
QWidget::connect(mixer6, SIGNAL(clicked(bool)),
|
||||
this, SLOT(mixer6Changed(bool)));
|
||||
QWidget::connect(mixer1, SIGNAL(clicked(bool)), this,
|
||||
SLOT(mixer1Changed(bool)));
|
||||
QWidget::connect(mixer2, SIGNAL(clicked(bool)), this,
|
||||
SLOT(mixer2Changed(bool)));
|
||||
QWidget::connect(mixer3, SIGNAL(clicked(bool)), this,
|
||||
SLOT(mixer3Changed(bool)));
|
||||
QWidget::connect(mixer4, SIGNAL(clicked(bool)), this,
|
||||
SLOT(mixer4Changed(bool)));
|
||||
QWidget::connect(mixer5, SIGNAL(clicked(bool)), this,
|
||||
SLOT(mixer5Changed(bool)));
|
||||
QWidget::connect(mixer6, SIGNAL(clicked(bool)), this,
|
||||
SLOT(mixer6Changed(bool)));
|
||||
|
||||
setObjectName(sourceName);
|
||||
}
|
||||
|
@ -214,7 +214,7 @@ void OBSAdvAudioCtrl::ShowAudioControl(QGridLayout *layout)
|
|||
#endif
|
||||
layout->addWidget(mixerContainer, lastRow, idx++);
|
||||
layout->layout()->setAlignment(mixerContainer,
|
||||
Qt::AlignHCenter | Qt::AlignVCenter);
|
||||
Qt::AlignHCenter | Qt::AlignVCenter);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
@ -223,30 +223,30 @@ void OBSAdvAudioCtrl::ShowAudioControl(QGridLayout *layout)
|
|||
void OBSAdvAudioCtrl::OBSSourceFlagsChanged(void *param, calldata_t *calldata)
|
||||
{
|
||||
uint32_t flags = (uint32_t)calldata_int(calldata, "flags");
|
||||
QMetaObject::invokeMethod(reinterpret_cast<OBSAdvAudioCtrl*>(param),
|
||||
"SourceFlagsChanged", Q_ARG(uint32_t, flags));
|
||||
|
||||
QMetaObject::invokeMethod(reinterpret_cast<OBSAdvAudioCtrl *>(param),
|
||||
"SourceFlagsChanged", Q_ARG(uint32_t, flags));
|
||||
}
|
||||
|
||||
void OBSAdvAudioCtrl::OBSSourceVolumeChanged(void *param, calldata_t *calldata)
|
||||
{
|
||||
float volume = (float)calldata_float(calldata, "volume");
|
||||
QMetaObject::invokeMethod(reinterpret_cast<OBSAdvAudioCtrl*>(param),
|
||||
"SourceVolumeChanged", Q_ARG(float, volume));
|
||||
QMetaObject::invokeMethod(reinterpret_cast<OBSAdvAudioCtrl *>(param),
|
||||
"SourceVolumeChanged", Q_ARG(float, volume));
|
||||
}
|
||||
|
||||
void OBSAdvAudioCtrl::OBSSourceSyncChanged(void *param, calldata_t *calldata)
|
||||
{
|
||||
int64_t offset = calldata_int(calldata, "offset");
|
||||
QMetaObject::invokeMethod(reinterpret_cast<OBSAdvAudioCtrl*>(param),
|
||||
"SourceSyncChanged", Q_ARG(int64_t, offset));
|
||||
QMetaObject::invokeMethod(reinterpret_cast<OBSAdvAudioCtrl *>(param),
|
||||
"SourceSyncChanged", Q_ARG(int64_t, offset));
|
||||
}
|
||||
|
||||
void OBSAdvAudioCtrl::OBSSourceMixersChanged(void *param, calldata_t *calldata)
|
||||
{
|
||||
uint32_t mixers = (uint32_t)calldata_int(calldata, "mixers");
|
||||
QMetaObject::invokeMethod(reinterpret_cast<OBSAdvAudioCtrl*>(param),
|
||||
"SourceMixersChanged", Q_ARG(uint32_t, mixers));
|
||||
QMetaObject::invokeMethod(reinterpret_cast<OBSAdvAudioCtrl *>(param),
|
||||
"SourceMixersChanged",
|
||||
Q_ARG(uint32_t, mixers));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
@ -279,12 +279,12 @@ void OBSAdvAudioCtrl::SourceSyncChanged(int64_t offset)
|
|||
|
||||
void OBSAdvAudioCtrl::SourceMixersChanged(uint32_t mixers)
|
||||
{
|
||||
setCheckboxState(mixer1, mixers & (1<<0));
|
||||
setCheckboxState(mixer2, mixers & (1<<1));
|
||||
setCheckboxState(mixer3, mixers & (1<<2));
|
||||
setCheckboxState(mixer4, mixers & (1<<3));
|
||||
setCheckboxState(mixer5, mixers & (1<<4));
|
||||
setCheckboxState(mixer6, mixers & (1<<5));
|
||||
setCheckboxState(mixer1, mixers & (1 << 0));
|
||||
setCheckboxState(mixer2, mixers & (1 << 1));
|
||||
setCheckboxState(mixer3, mixers & (1 << 2));
|
||||
setCheckboxState(mixer4, mixers & (1 << 3));
|
||||
setCheckboxState(mixer5, mixers & (1 << 4));
|
||||
setCheckboxState(mixer6, mixers & (1 << 5));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
@ -335,14 +335,13 @@ void OBSAdvAudioCtrl::ResetBalance()
|
|||
balance->setValue(50);
|
||||
}
|
||||
|
||||
|
||||
void OBSAdvAudioCtrl::syncOffsetChanged(int milliseconds)
|
||||
{
|
||||
int64_t cur_val = obs_source_get_sync_offset(source);
|
||||
|
||||
if (cur_val / NSEC_PER_MSEC != milliseconds)
|
||||
obs_source_set_sync_offset(source,
|
||||
int64_t(milliseconds) * NSEC_PER_MSEC);
|
||||
obs_source_set_sync_offset(source, int64_t(milliseconds) *
|
||||
NSEC_PER_MSEC);
|
||||
}
|
||||
|
||||
void OBSAdvAudioCtrl::monitoringTypeChanged(int index)
|
||||
|
@ -365,17 +364,19 @@ void OBSAdvAudioCtrl::monitoringTypeChanged(int index)
|
|||
}
|
||||
|
||||
blog(LOG_INFO, "User changed audio monitoring for source '%s' to: %s",
|
||||
obs_source_get_name(source), type);
|
||||
obs_source_get_name(source), type);
|
||||
}
|
||||
|
||||
static inline void setMixer(obs_source_t *source, const int mixerIdx,
|
||||
const bool checked)
|
||||
const bool checked)
|
||||
{
|
||||
uint32_t mixers = obs_source_get_audio_mixers(source);
|
||||
uint32_t new_mixers = mixers;
|
||||
|
||||
if (checked) new_mixers |= (1<<mixerIdx);
|
||||
else new_mixers &= ~(1<<mixerIdx);
|
||||
if (checked)
|
||||
new_mixers |= (1 << mixerIdx);
|
||||
else
|
||||
new_mixers &= ~(1 << mixerIdx);
|
||||
|
||||
obs_source_set_audio_mixers(source, new_mixers);
|
||||
}
|
||||
|
|
|
@ -16,31 +16,31 @@ class OBSAdvAudioCtrl : public QObject {
|
|||
Q_OBJECT
|
||||
|
||||
private:
|
||||
OBSSource source;
|
||||
OBSSource source;
|
||||
|
||||
QPointer<QWidget> forceMonoContainer;
|
||||
QPointer<QWidget> mixerContainer;
|
||||
QPointer<QWidget> balanceContainer;
|
||||
QPointer<QWidget> forceMonoContainer;
|
||||
QPointer<QWidget> mixerContainer;
|
||||
QPointer<QWidget> balanceContainer;
|
||||
|
||||
QPointer<QLabel> nameLabel;
|
||||
QPointer<QLabel> nameLabel;
|
||||
QPointer<QDoubleSpinBox> volume;
|
||||
QPointer<QCheckBox> forceMono;
|
||||
QPointer<BalanceSlider>balance;
|
||||
QPointer<QLabel> labelL;
|
||||
QPointer<QLabel> labelR;
|
||||
QPointer<QSpinBox> syncOffset;
|
||||
QPointer<QComboBox> monitoringType;
|
||||
QPointer<QCheckBox> mixer1;
|
||||
QPointer<QCheckBox> mixer2;
|
||||
QPointer<QCheckBox> mixer3;
|
||||
QPointer<QCheckBox> mixer4;
|
||||
QPointer<QCheckBox> mixer5;
|
||||
QPointer<QCheckBox> mixer6;
|
||||
QPointer<QCheckBox> forceMono;
|
||||
QPointer<BalanceSlider> balance;
|
||||
QPointer<QLabel> labelL;
|
||||
QPointer<QLabel> labelR;
|
||||
QPointer<QSpinBox> syncOffset;
|
||||
QPointer<QComboBox> monitoringType;
|
||||
QPointer<QCheckBox> mixer1;
|
||||
QPointer<QCheckBox> mixer2;
|
||||
QPointer<QCheckBox> mixer3;
|
||||
QPointer<QCheckBox> mixer4;
|
||||
QPointer<QCheckBox> mixer5;
|
||||
QPointer<QCheckBox> mixer6;
|
||||
|
||||
OBSSignal volChangedSignal;
|
||||
OBSSignal syncOffsetSignal;
|
||||
OBSSignal flagsSignal;
|
||||
OBSSignal mixersSignal;
|
||||
OBSSignal volChangedSignal;
|
||||
OBSSignal syncOffsetSignal;
|
||||
OBSSignal flagsSignal;
|
||||
OBSSignal mixersSignal;
|
||||
|
||||
static void OBSSourceFlagsChanged(void *param, calldata_t *calldata);
|
||||
static void OBSSourceVolumeChanged(void *param, calldata_t *calldata);
|
||||
|
@ -51,7 +51,7 @@ public:
|
|||
OBSAdvAudioCtrl(QGridLayout *layout, obs_source_t *source_);
|
||||
virtual ~OBSAdvAudioCtrl();
|
||||
|
||||
inline obs_source_t *GetSource() const {return source;}
|
||||
inline obs_source_t *GetSource() const { return source; }
|
||||
void ShowAudioControl(QGridLayout *layout);
|
||||
|
||||
public slots:
|
||||
|
|
|
@ -11,14 +11,13 @@ using namespace std;
|
|||
Q_DECLARE_METATYPE(OBSScene);
|
||||
Q_DECLARE_METATYPE(OBSSource);
|
||||
|
||||
template <typename T>
|
||||
static T GetOBSRef(QListWidgetItem *item)
|
||||
template<typename T> static T GetOBSRef(QListWidgetItem *item)
|
||||
{
|
||||
return item->data(static_cast<int>(QtDataRole::OBSRef)).value<T>();
|
||||
}
|
||||
|
||||
void EnumProfiles(function<bool (const char *, const char *)> &&cb);
|
||||
void EnumSceneCollections(function<bool (const char *, const char *)> &&cb);
|
||||
void EnumProfiles(function<bool(const char *, const char *)> &&cb);
|
||||
void EnumSceneCollections(function<bool(const char *, const char *)> &&cb);
|
||||
|
||||
extern volatile bool streaming_active;
|
||||
extern volatile bool recording_active;
|
||||
|
@ -30,18 +29,18 @@ template<typename T> struct OBSStudioCallback {
|
|||
T callback;
|
||||
void *private_data;
|
||||
|
||||
inline OBSStudioCallback(T cb, void *p) :
|
||||
callback(cb), private_data(p)
|
||||
{}
|
||||
inline OBSStudioCallback(T cb, void *p) : callback(cb), private_data(p)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> inline size_t GetCallbackIdx(
|
||||
vector<OBSStudioCallback<T>> &callbacks,
|
||||
T callback, void *private_data)
|
||||
template<typename T>
|
||||
inline size_t GetCallbackIdx(vector<OBSStudioCallback<T>> &callbacks,
|
||||
T callback, void *private_data)
|
||||
{
|
||||
for (size_t i = 0; i < callbacks.size(); i++) {
|
||||
OBSStudioCallback<T> curCB = callbacks[i];
|
||||
if (curCB.callback == callback &&
|
||||
if (curCB.callback == callback &&
|
||||
curCB.private_data == private_data)
|
||||
return i;
|
||||
}
|
||||
|
@ -59,21 +58,21 @@ struct OBSStudioAPI : obs_frontend_callbacks {
|
|||
|
||||
void *obs_frontend_get_main_window(void) override
|
||||
{
|
||||
return (void*)main;
|
||||
return (void *)main;
|
||||
}
|
||||
|
||||
void *obs_frontend_get_main_window_handle(void) override
|
||||
{
|
||||
return (void*)main->winId();
|
||||
return (void *)main->winId();
|
||||
}
|
||||
|
||||
void *obs_frontend_get_system_tray(void) override
|
||||
{
|
||||
return (void*)main->trayIcon.data();
|
||||
return (void *)main->trayIcon.data();
|
||||
}
|
||||
|
||||
void obs_frontend_get_scenes(
|
||||
struct obs_frontend_source_list *sources) override
|
||||
struct obs_frontend_source_list *sources) override
|
||||
{
|
||||
for (int i = 0; i < main->ui->scenes->count(); i++) {
|
||||
QListWidgetItem *item = main->ui->scenes->item(i);
|
||||
|
@ -101,23 +100,23 @@ struct OBSStudioAPI : obs_frontend_callbacks {
|
|||
void obs_frontend_set_current_scene(obs_source_t *scene) override
|
||||
{
|
||||
if (main->IsPreviewProgramMode()) {
|
||||
QMetaObject::invokeMethod(main, "TransitionToScene",
|
||||
WaitConnection(),
|
||||
Q_ARG(OBSSource, OBSSource(scene)));
|
||||
QMetaObject::invokeMethod(
|
||||
main, "TransitionToScene", WaitConnection(),
|
||||
Q_ARG(OBSSource, OBSSource(scene)));
|
||||
} else {
|
||||
QMetaObject::invokeMethod(main, "SetCurrentScene",
|
||||
WaitConnection(),
|
||||
Q_ARG(OBSSource, OBSSource(scene)),
|
||||
Q_ARG(bool, false));
|
||||
QMetaObject::invokeMethod(
|
||||
main, "SetCurrentScene", WaitConnection(),
|
||||
Q_ARG(OBSSource, OBSSource(scene)),
|
||||
Q_ARG(bool, false));
|
||||
}
|
||||
}
|
||||
|
||||
void obs_frontend_get_transitions(
|
||||
struct obs_frontend_source_list *sources) override
|
||||
struct obs_frontend_source_list *sources) override
|
||||
{
|
||||
for (int i = 0; i < main->ui->transitions->count(); i++) {
|
||||
OBSSource tr = main->ui->transitions->itemData(i)
|
||||
.value<OBSSource>();
|
||||
.value<OBSSource>();
|
||||
|
||||
obs_source_addref(tr);
|
||||
da_push_back(sources->sources, &tr);
|
||||
|
@ -132,11 +131,12 @@ struct OBSStudioAPI : obs_frontend_callbacks {
|
|||
return tr;
|
||||
}
|
||||
|
||||
void obs_frontend_set_current_transition(
|
||||
obs_source_t *transition) override
|
||||
void
|
||||
obs_frontend_set_current_transition(obs_source_t *transition) override
|
||||
{
|
||||
QMetaObject::invokeMethod(main, "SetTransition",
|
||||
Q_ARG(OBSSource, OBSSource(transition)));
|
||||
Q_ARG(OBSSource,
|
||||
OBSSource(transition)));
|
||||
}
|
||||
|
||||
int obs_frontend_get_transition_duration(void) override
|
||||
|
@ -146,15 +146,14 @@ struct OBSStudioAPI : obs_frontend_callbacks {
|
|||
|
||||
void obs_frontend_set_transition_duration(int duration) override
|
||||
{
|
||||
QMetaObject::invokeMethod(main->ui->transitionDuration, "setValue",
|
||||
Q_ARG(int, duration));
|
||||
QMetaObject::invokeMethod(main->ui->transitionDuration,
|
||||
"setValue", Q_ARG(int, duration));
|
||||
}
|
||||
|
||||
void obs_frontend_get_scene_collections(
|
||||
std::vector<std::string> &strings) override
|
||||
std::vector<std::string> &strings) override
|
||||
{
|
||||
auto addCollection = [&](const char *name, const char *)
|
||||
{
|
||||
auto addCollection = [&](const char *name, const char *) {
|
||||
strings.emplace_back(name);
|
||||
return true;
|
||||
};
|
||||
|
@ -164,15 +163,15 @@ struct OBSStudioAPI : obs_frontend_callbacks {
|
|||
|
||||
char *obs_frontend_get_current_scene_collection(void) override
|
||||
{
|
||||
const char *cur_name = config_get_string(App()->GlobalConfig(),
|
||||
"Basic", "SceneCollection");
|
||||
const char *cur_name = config_get_string(
|
||||
App()->GlobalConfig(), "Basic", "SceneCollection");
|
||||
return bstrdup(cur_name);
|
||||
}
|
||||
|
||||
void obs_frontend_set_current_scene_collection(
|
||||
const char *collection) override
|
||||
const char *collection) override
|
||||
{
|
||||
QList<QAction*> menuActions =
|
||||
QList<QAction *> menuActions =
|
||||
main->ui->sceneCollectionMenu->actions();
|
||||
QString qstrCollection = QT_UTF8(collection);
|
||||
|
||||
|
@ -189,24 +188,21 @@ struct OBSStudioAPI : obs_frontend_callbacks {
|
|||
}
|
||||
}
|
||||
|
||||
bool obs_frontend_add_scene_collection(
|
||||
const char *name) override
|
||||
bool obs_frontend_add_scene_collection(const char *name) override
|
||||
{
|
||||
bool success = false;
|
||||
QMetaObject::invokeMethod(main,
|
||||
"AddSceneCollection",
|
||||
WaitConnection(),
|
||||
Q_RETURN_ARG(bool, success),
|
||||
Q_ARG(bool, true),
|
||||
Q_ARG(QString, QT_UTF8(name)));
|
||||
QMetaObject::invokeMethod(main, "AddSceneCollection",
|
||||
WaitConnection(),
|
||||
Q_RETURN_ARG(bool, success),
|
||||
Q_ARG(bool, true),
|
||||
Q_ARG(QString, QT_UTF8(name)));
|
||||
return success;
|
||||
}
|
||||
|
||||
void obs_frontend_get_profiles(
|
||||
std::vector<std::string> &strings) override
|
||||
void
|
||||
obs_frontend_get_profiles(std::vector<std::string> &strings) override
|
||||
{
|
||||
auto addProfile = [&](const char *name, const char *)
|
||||
{
|
||||
auto addProfile = [&](const char *name, const char *) {
|
||||
strings.emplace_back(name);
|
||||
return true;
|
||||
};
|
||||
|
@ -217,14 +213,13 @@ struct OBSStudioAPI : obs_frontend_callbacks {
|
|||
char *obs_frontend_get_current_profile(void) override
|
||||
{
|
||||
const char *name = config_get_string(App()->GlobalConfig(),
|
||||
"Basic", "Profile");
|
||||
"Basic", "Profile");
|
||||
return bstrdup(name);
|
||||
}
|
||||
|
||||
void obs_frontend_set_current_profile(const char *profile) override
|
||||
{
|
||||
QList<QAction*> menuActions =
|
||||
main->ui->profileMenu->actions();
|
||||
QList<QAction *> menuActions = main->ui->profileMenu->actions();
|
||||
QString qstrProfile = QT_UTF8(profile);
|
||||
|
||||
for (int i = 0; i < menuActions.count(); i++) {
|
||||
|
@ -293,16 +288,16 @@ struct OBSStudioAPI : obs_frontend_callbacks {
|
|||
void *obs_frontend_add_tools_menu_qaction(const char *name) override
|
||||
{
|
||||
main->ui->menuTools->setEnabled(true);
|
||||
return (void*)main->ui->menuTools->addAction(QT_UTF8(name));
|
||||
return (void *)main->ui->menuTools->addAction(QT_UTF8(name));
|
||||
}
|
||||
|
||||
void obs_frontend_add_tools_menu_item(const char *name,
|
||||
obs_frontend_cb callback, void *private_data) override
|
||||
obs_frontend_cb callback,
|
||||
void *private_data) override
|
||||
{
|
||||
main->ui->menuTools->setEnabled(true);
|
||||
|
||||
auto func = [private_data, callback] ()
|
||||
{
|
||||
auto func = [private_data, callback]() {
|
||||
callback(private_data);
|
||||
};
|
||||
|
||||
|
@ -312,11 +307,11 @@ struct OBSStudioAPI : obs_frontend_callbacks {
|
|||
|
||||
void *obs_frontend_add_dock(void *dock) override
|
||||
{
|
||||
return (void*)main->AddDockWidget((QDockWidget *)dock);
|
||||
return (void *)main->AddDockWidget((QDockWidget *)dock);
|
||||
}
|
||||
|
||||
void obs_frontend_add_event_callback(obs_frontend_event_cb callback,
|
||||
void *private_data) override
|
||||
void *private_data) override
|
||||
{
|
||||
size_t idx = GetCallbackIdx(callbacks, callback, private_data);
|
||||
if (idx == (size_t)-1)
|
||||
|
@ -324,7 +319,7 @@ struct OBSStudioAPI : obs_frontend_callbacks {
|
|||
}
|
||||
|
||||
void obs_frontend_remove_event_callback(obs_frontend_event_cb callback,
|
||||
void *private_data) override
|
||||
void *private_data) override
|
||||
{
|
||||
size_t idx = GetCallbackIdx(callbacks, callback, private_data);
|
||||
if (idx == (size_t)-1)
|
||||
|
@ -364,10 +359,7 @@ struct OBSStudioAPI : obs_frontend_callbacks {
|
|||
return App()->GlobalConfig();
|
||||
}
|
||||
|
||||
void obs_frontend_save(void) override
|
||||
{
|
||||
main->SaveProject();
|
||||
}
|
||||
void obs_frontend_save(void) override { main->SaveProject(); }
|
||||
|
||||
void obs_frontend_defer_save_begin(void) override
|
||||
{
|
||||
|
@ -380,19 +372,19 @@ struct OBSStudioAPI : obs_frontend_callbacks {
|
|||
}
|
||||
|
||||
void obs_frontend_add_save_callback(obs_frontend_save_cb callback,
|
||||
void *private_data) override
|
||||
void *private_data) override
|
||||
{
|
||||
size_t idx = GetCallbackIdx(saveCallbacks, callback,
|
||||
private_data);
|
||||
size_t idx =
|
||||
GetCallbackIdx(saveCallbacks, callback, private_data);
|
||||
if (idx == (size_t)-1)
|
||||
saveCallbacks.emplace_back(callback, private_data);
|
||||
}
|
||||
|
||||
void obs_frontend_remove_save_callback(obs_frontend_save_cb callback,
|
||||
void *private_data) override
|
||||
void *private_data) override
|
||||
{
|
||||
size_t idx = GetCallbackIdx(saveCallbacks, callback,
|
||||
private_data);
|
||||
size_t idx =
|
||||
GetCallbackIdx(saveCallbacks, callback, private_data);
|
||||
if (idx == (size_t)-1)
|
||||
return;
|
||||
|
||||
|
@ -400,19 +392,19 @@ struct OBSStudioAPI : obs_frontend_callbacks {
|
|||
}
|
||||
|
||||
void obs_frontend_add_preload_callback(obs_frontend_save_cb callback,
|
||||
void *private_data) override
|
||||
void *private_data) override
|
||||
{
|
||||
size_t idx = GetCallbackIdx(preloadCallbacks, callback,
|
||||
private_data);
|
||||
private_data);
|
||||
if (idx == (size_t)-1)
|
||||
preloadCallbacks.emplace_back(callback, private_data);
|
||||
}
|
||||
|
||||
void obs_frontend_remove_preload_callback(obs_frontend_save_cb callback,
|
||||
void *private_data) override
|
||||
void *private_data) override
|
||||
{
|
||||
size_t idx = GetCallbackIdx(preloadCallbacks, callback,
|
||||
private_data);
|
||||
private_data);
|
||||
if (idx == (size_t)-1)
|
||||
return;
|
||||
|
||||
|
@ -420,7 +412,7 @@ struct OBSStudioAPI : obs_frontend_callbacks {
|
|||
}
|
||||
|
||||
void obs_frontend_push_ui_translation(
|
||||
obs_frontend_translate_ui_cb translate) override
|
||||
obs_frontend_translate_ui_cb translate) override
|
||||
{
|
||||
App()->PushUITranslation(translate);
|
||||
}
|
||||
|
@ -483,12 +475,14 @@ struct OBSStudioAPI : obs_frontend_callbacks {
|
|||
return source;
|
||||
}
|
||||
|
||||
void obs_frontend_set_current_preview_scene(obs_source_t *scene) override
|
||||
void
|
||||
obs_frontend_set_current_preview_scene(obs_source_t *scene) override
|
||||
{
|
||||
if (main->IsPreviewProgramMode()) {
|
||||
QMetaObject::invokeMethod(main, "SetCurrentScene",
|
||||
Q_ARG(OBSSource, OBSSource(scene)),
|
||||
Q_ARG(bool, false));
|
||||
Q_ARG(OBSSource,
|
||||
OBSSource(scene)),
|
||||
Q_ARG(bool, false));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ static const char *EncoderName(const char *id)
|
|||
return NullToEmpty(obs_encoder_get_display_name(id));
|
||||
}
|
||||
|
||||
static map<int, const char*> bitrateMap;
|
||||
static map<int, const char *> bitrateMap;
|
||||
static once_flag populateBitrateMap;
|
||||
|
||||
static void HandleIntProperty(obs_property_t *prop, const char *id)
|
||||
|
@ -48,10 +48,11 @@ static void HandleListProperty(obs_property_t *prop, const char *id)
|
|||
{
|
||||
obs_combo_format format = obs_property_list_format(prop);
|
||||
if (format != OBS_COMBO_FORMAT_INT) {
|
||||
blog(LOG_ERROR, "Encoder '%s' (%s) returned bitrate "
|
||||
"OBS_PROPERTY_LIST property of unhandled "
|
||||
"format %d",
|
||||
EncoderName(id), id, static_cast<int>(format));
|
||||
blog(LOG_ERROR,
|
||||
"Encoder '%s' (%s) returned bitrate "
|
||||
"OBS_PROPERTY_LIST property of unhandled "
|
||||
"format %d",
|
||||
EncoderName(id), id, static_cast<int>(format));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -60,38 +61,35 @@ static void HandleListProperty(obs_property_t *prop, const char *id)
|
|||
if (obs_property_list_item_disabled(prop, i))
|
||||
continue;
|
||||
|
||||
int bitrate = static_cast<int>(
|
||||
obs_property_list_item_int(prop, i));
|
||||
int bitrate =
|
||||
static_cast<int>(obs_property_list_item_int(prop, i));
|
||||
bitrateMap[bitrate] = id;
|
||||
}
|
||||
}
|
||||
|
||||
static void HandleSampleRate(obs_property_t* prop, const char *id)
|
||||
static void HandleSampleRate(obs_property_t *prop, const char *id)
|
||||
{
|
||||
auto ReleaseData = [](obs_data_t *data)
|
||||
{
|
||||
obs_data_release(data);
|
||||
};
|
||||
auto ReleaseData = [](obs_data_t *data) { obs_data_release(data); };
|
||||
std::unique_ptr<obs_data_t, decltype(ReleaseData)> data{
|
||||
obs_encoder_defaults(id),
|
||||
ReleaseData};
|
||||
obs_encoder_defaults(id), ReleaseData};
|
||||
|
||||
if (!data) {
|
||||
blog(LOG_ERROR, "Failed to get defaults for encoder '%s' (%s) "
|
||||
"while populating bitrate map",
|
||||
EncoderName(id), id);
|
||||
blog(LOG_ERROR,
|
||||
"Failed to get defaults for encoder '%s' (%s) "
|
||||
"while populating bitrate map",
|
||||
EncoderName(id), id);
|
||||
return;
|
||||
}
|
||||
|
||||
auto main = reinterpret_cast<OBSMainWindow*>(App()->GetMainWindow());
|
||||
auto main = reinterpret_cast<OBSMainWindow *>(App()->GetMainWindow());
|
||||
if (!main) {
|
||||
blog(LOG_ERROR, "Failed to get main window while populating "
|
||||
"bitrate map");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t sampleRate = config_get_uint(main->Config(), "Audio",
|
||||
"SampleRate");
|
||||
uint32_t sampleRate =
|
||||
config_get_uint(main->Config(), "Audio", "SampleRate");
|
||||
|
||||
obs_data_set_int(data.get(), "samplerate", sampleRate);
|
||||
|
||||
|
@ -100,23 +98,22 @@ static void HandleSampleRate(obs_property_t* prop, const char *id)
|
|||
|
||||
static void HandleEncoderProperties(const char *id)
|
||||
{
|
||||
auto DestroyProperties = [](obs_properties_t *props)
|
||||
{
|
||||
auto DestroyProperties = [](obs_properties_t *props) {
|
||||
obs_properties_destroy(props);
|
||||
};
|
||||
std::unique_ptr<obs_properties_t, decltype(DestroyProperties)> props{
|
||||
obs_get_encoder_properties(id),
|
||||
DestroyProperties};
|
||||
obs_get_encoder_properties(id), DestroyProperties};
|
||||
|
||||
if (!props) {
|
||||
blog(LOG_ERROR, "Failed to get properties for encoder "
|
||||
"'%s' (%s)",
|
||||
EncoderName(id), id);
|
||||
blog(LOG_ERROR,
|
||||
"Failed to get properties for encoder "
|
||||
"'%s' (%s)",
|
||||
EncoderName(id), id);
|
||||
return;
|
||||
}
|
||||
|
||||
obs_property_t *samplerate = obs_properties_get(props.get(),
|
||||
"samplerate");
|
||||
obs_property_t *samplerate =
|
||||
obs_properties_get(props.get(), "samplerate");
|
||||
if (samplerate)
|
||||
HandleSampleRate(samplerate, id);
|
||||
|
||||
|
@ -130,12 +127,14 @@ static void HandleEncoderProperties(const char *id)
|
|||
case OBS_PROPERTY_LIST:
|
||||
return HandleListProperty(bitrate, id);
|
||||
|
||||
default: break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
blog(LOG_ERROR, "Encoder '%s' (%s) returned bitrate property "
|
||||
"of unhandled type %d", EncoderName(id), id,
|
||||
static_cast<int>(type));
|
||||
blog(LOG_ERROR,
|
||||
"Encoder '%s' (%s) returned bitrate property "
|
||||
"of unhandled type %d",
|
||||
EncoderName(id), id, static_cast<int>(type));
|
||||
}
|
||||
|
||||
static const char *GetCodec(const char *id)
|
||||
|
@ -146,8 +145,7 @@ static const char *GetCodec(const char *id)
|
|||
static const string aac_ = "AAC";
|
||||
static void PopulateBitrateMap()
|
||||
{
|
||||
call_once(populateBitrateMap, []()
|
||||
{
|
||||
call_once(populateBitrateMap, []() {
|
||||
struct obs_audio_info aoi;
|
||||
obs_get_audio_info(&aoi);
|
||||
uint32_t output_channels = get_audio_channels(aoi.speakers);
|
||||
|
@ -156,13 +154,12 @@ static void PopulateBitrateMap()
|
|||
|
||||
const char *id = nullptr;
|
||||
for (size_t i = 0; obs_enum_encoder_types(i, &id); i++) {
|
||||
auto Compare = [=](const string &val)
|
||||
{
|
||||
auto Compare = [=](const string &val) {
|
||||
return val == NullToEmpty(id);
|
||||
};
|
||||
|
||||
if (find_if(begin(encoders), end(encoders), Compare) !=
|
||||
end(encoders))
|
||||
end(encoders))
|
||||
continue;
|
||||
|
||||
if (aac_ != GetCodec(id))
|
||||
|
@ -198,11 +195,11 @@ static void PopulateBitrateMap()
|
|||
<< entry.second << ')';
|
||||
|
||||
blog(LOG_DEBUG, "AAC encoder bitrate mapping:%s",
|
||||
ss.str().c_str());
|
||||
ss.str().c_str());
|
||||
});
|
||||
}
|
||||
|
||||
const map<int, const char*> &GetAACEncoderBitrateMap()
|
||||
const map<int, const char *> &GetAACEncoderBitrateMap()
|
||||
{
|
||||
PopulateBitrateMap();
|
||||
return bitrateMap;
|
||||
|
|
|
@ -4,6 +4,6 @@
|
|||
|
||||
#include <map>
|
||||
|
||||
const std::map<int, const char*> &GetAACEncoderBitrateMap();
|
||||
const std::map<int, const char *> &GetAACEncoderBitrateMap();
|
||||
const char *GetAACEncoderForBitrate(int bitrate);
|
||||
int FindClosestAvailableAACBitrate(int bitrate);
|
||||
|
|
|
@ -43,7 +43,8 @@ void Auth::Load()
|
|||
{
|
||||
OBSBasic *main = OBSBasic::Get();
|
||||
const char *typeStr = config_get_string(main->Config(), "Auth", "Type");
|
||||
if (!typeStr) typeStr = "";
|
||||
if (!typeStr)
|
||||
typeStr = "";
|
||||
|
||||
main->auth = Create(typeStr);
|
||||
if (main->auth) {
|
||||
|
|
|
@ -8,8 +8,8 @@ class Auth : public QObject {
|
|||
Q_OBJECT
|
||||
|
||||
protected:
|
||||
virtual void SaveInternal()=0;
|
||||
virtual bool LoadInternal()=0;
|
||||
virtual void SaveInternal() = 0;
|
||||
virtual bool LoadInternal() = 0;
|
||||
|
||||
bool firstLoad = true;
|
||||
|
||||
|
@ -19,13 +19,14 @@ protected:
|
|||
|
||||
ErrorInfo(std::string message_, std::string error_)
|
||||
: message(message_), error(error_)
|
||||
{}
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
enum class Type {
|
||||
None,
|
||||
OAuth_StreamKey
|
||||
OAuth_StreamKey,
|
||||
};
|
||||
|
||||
struct Def {
|
||||
|
@ -33,13 +34,13 @@ public:
|
|||
Type type;
|
||||
};
|
||||
|
||||
typedef std::function<std::shared_ptr<Auth> ()> create_cb;
|
||||
typedef std::function<std::shared_ptr<Auth>()> create_cb;
|
||||
|
||||
inline Auth(const Def &d) : def(d) {}
|
||||
virtual ~Auth() {}
|
||||
|
||||
inline Type type() const {return def.type;}
|
||||
inline const char *service() const {return def.service.c_str();}
|
||||
inline Type type() const { return def.type; }
|
||||
inline const char *service() const { return def.service.c_str(); }
|
||||
|
||||
virtual void LoadUI() {}
|
||||
|
||||
|
|
|
@ -26,24 +26,16 @@ extern QCefCookieManager *panel_cookies;
|
|||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#define MIXER_AUTH_URL \
|
||||
"https://obsproject.com/app-auth/mixer?action=redirect"
|
||||
#define MIXER_TOKEN_URL \
|
||||
"https://obsproject.com/app-auth/mixer-token"
|
||||
#define MIXER_AUTH_URL "https://obsproject.com/app-auth/mixer?action=redirect"
|
||||
#define MIXER_TOKEN_URL "https://obsproject.com/app-auth/mixer-token"
|
||||
|
||||
#define MIXER_SCOPE_VERSION 1
|
||||
|
||||
static Auth::Def mixerDef = {
|
||||
"Mixer",
|
||||
Auth::Type::OAuth_StreamKey
|
||||
};
|
||||
static Auth::Def mixerDef = {"Mixer", Auth::Type::OAuth_StreamKey};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
MixerAuth::MixerAuth(const Def &d)
|
||||
: OAuthStreamKey(d)
|
||||
{
|
||||
}
|
||||
MixerAuth::MixerAuth(const Def &d) : OAuthStreamKey(d) {}
|
||||
|
||||
bool MixerAuth::GetChannelInfo(bool allow_retry)
|
||||
try {
|
||||
|
@ -71,23 +63,16 @@ try {
|
|||
bool success;
|
||||
|
||||
if (id.empty()) {
|
||||
auto func = [&] () {
|
||||
auto func = [&]() {
|
||||
success = GetRemoteFile(
|
||||
"https://mixer.com/api/v1/users/current",
|
||||
output,
|
||||
error,
|
||||
nullptr,
|
||||
"application/json",
|
||||
nullptr,
|
||||
headers,
|
||||
nullptr,
|
||||
5);
|
||||
"https://mixer.com/api/v1/users/current",
|
||||
output, error, nullptr, "application/json",
|
||||
nullptr, headers, nullptr, 5);
|
||||
};
|
||||
|
||||
ExecThreadedWithoutBlocking(
|
||||
func,
|
||||
QTStr("Auth.LoadingChannel.Title"),
|
||||
QTStr("Auth.LoadingChannel.Text").arg(service()));
|
||||
func, QTStr("Auth.LoadingChannel.Title"),
|
||||
QTStr("Auth.LoadingChannel.Text").arg(service()));
|
||||
if (!success || output.empty())
|
||||
throw ErrorInfo("Failed to get user info from remote",
|
||||
error);
|
||||
|
@ -98,11 +83,12 @@ try {
|
|||
|
||||
error = json["error"].string_value();
|
||||
if (!error.empty())
|
||||
throw ErrorInfo(error,
|
||||
json["error_description"].string_value());
|
||||
throw ErrorInfo(
|
||||
error,
|
||||
json["error_description"].string_value());
|
||||
|
||||
id = std::to_string(json["channel"]["id"].int_value());
|
||||
name = json["channel"]["token"].string_value();
|
||||
id = std::to_string(json["channel"]["id"].int_value());
|
||||
name = json["channel"]["token"].string_value();
|
||||
}
|
||||
|
||||
/* ------------------ */
|
||||
|
@ -114,23 +100,15 @@ try {
|
|||
|
||||
output.clear();
|
||||
|
||||
auto func = [&] () {
|
||||
success = GetRemoteFile(
|
||||
url.c_str(),
|
||||
output,
|
||||
error,
|
||||
nullptr,
|
||||
"application/json",
|
||||
nullptr,
|
||||
headers,
|
||||
nullptr,
|
||||
5);
|
||||
auto func = [&]() {
|
||||
success = GetRemoteFile(url.c_str(), output, error, nullptr,
|
||||
"application/json", nullptr, headers,
|
||||
nullptr, 5);
|
||||
};
|
||||
|
||||
ExecThreadedWithoutBlocking(
|
||||
func,
|
||||
QTStr("Auth.LoadingChannel.Title"),
|
||||
QTStr("Auth.LoadingChannel.Text").arg(service()));
|
||||
func, QTStr("Auth.LoadingChannel.Title"),
|
||||
QTStr("Auth.LoadingChannel.Text").arg(service()));
|
||||
if (!success || output.empty())
|
||||
throw ErrorInfo("Failed to get stream key from remote", error);
|
||||
|
||||
|
@ -140,7 +118,8 @@ try {
|
|||
|
||||
error = json["error"].string_value();
|
||||
if (!error.empty())
|
||||
throw ErrorInfo(error, json["error_description"].string_value());
|
||||
throw ErrorInfo(error,
|
||||
json["error_description"].string_value());
|
||||
|
||||
std::string key_suffix = json["streamKey"].string_value();
|
||||
|
||||
|
@ -161,14 +140,13 @@ try {
|
|||
} catch (ErrorInfo info) {
|
||||
QString title = QTStr("Auth.ChannelFailure.Title");
|
||||
QString text = QTStr("Auth.ChannelFailure.Text")
|
||||
.arg(service(), info.message.c_str(), info.error.c_str());
|
||||
.arg(service(), info.message.c_str(),
|
||||
info.error.c_str());
|
||||
|
||||
QMessageBox::warning(OBSBasic::Get(), title, text);
|
||||
|
||||
blog(LOG_WARNING, "%s: %s: %s",
|
||||
__FUNCTION__,
|
||||
info.message.c_str(),
|
||||
info.error.c_str());
|
||||
blog(LOG_WARNING, "%s: %s: %s", __FUNCTION__, info.message.c_str(),
|
||||
info.error.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -179,15 +157,13 @@ void MixerAuth::SaveInternal()
|
|||
config_set_string(main->Config(), service(), "Id", id.c_str());
|
||||
if (uiLoaded) {
|
||||
config_set_string(main->Config(), service(), "DockState",
|
||||
main->saveState().toBase64().constData());
|
||||
main->saveState().toBase64().constData());
|
||||
}
|
||||
OAuthStreamKey::SaveInternal();
|
||||
}
|
||||
|
||||
static inline std::string get_config_str(
|
||||
OBSBasic *main,
|
||||
const char *section,
|
||||
const char *name)
|
||||
static inline std::string get_config_str(OBSBasic *main, const char *section,
|
||||
const char *name)
|
||||
{
|
||||
const char *val = config_get_string(main->Config(), section, name);
|
||||
return val ? val : "";
|
||||
|
@ -252,8 +228,8 @@ void MixerAuth::LoadUI()
|
|||
if (firstLoad) {
|
||||
chat->setVisible(true);
|
||||
} else {
|
||||
const char *dockStateStr = config_get_string(main->Config(),
|
||||
service(), "DockState");
|
||||
const char *dockStateStr = config_get_string(
|
||||
main->Config(), service(), "DockState");
|
||||
QByteArray dockState =
|
||||
QByteArray::fromBase64(QByteArray(dockStateStr));
|
||||
main->restoreState(dockState);
|
||||
|
@ -301,7 +277,7 @@ std::shared_ptr<Auth> MixerAuth::Login(QWidget *parent)
|
|||
deobfuscate_str(&client_id[0], MIXER_HASH);
|
||||
|
||||
if (!auth->GetToken(MIXER_TOKEN_URL, client_id, MIXER_SCOPE_VERSION,
|
||||
QT_TO_UTF8(login.GetCode()))) {
|
||||
QT_TO_UTF8(login.GetCode()))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -328,9 +304,6 @@ static void DeleteCookies()
|
|||
|
||||
void RegisterMixerAuth()
|
||||
{
|
||||
OAuth::RegisterOAuth(
|
||||
mixerDef,
|
||||
CreateMixerAuth,
|
||||
MixerAuth::Login,
|
||||
DeleteCookies);
|
||||
OAuth::RegisterOAuth(mixerDef, CreateMixerAuth, MixerAuth::Login,
|
||||
DeleteCookies);
|
||||
}
|
||||
|
|
|
@ -23,8 +23,7 @@ extern QCefCookieManager *panel_cookies;
|
|||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
OAuthLogin::OAuthLogin(QWidget *parent, const std::string &url, bool token)
|
||||
: QDialog (parent),
|
||||
get_token (token)
|
||||
: QDialog(parent), get_token(token)
|
||||
{
|
||||
if (!cef) {
|
||||
return;
|
||||
|
@ -46,14 +45,13 @@ OAuthLogin::OAuthLogin(QWidget *parent, const std::string &url, bool token)
|
|||
return;
|
||||
}
|
||||
|
||||
connect(cefWidget, SIGNAL(titleChanged(const QString &)),
|
||||
this, SLOT(setWindowTitle(const QString &)));
|
||||
connect(cefWidget, SIGNAL(urlChanged(const QString &)),
|
||||
this, SLOT(urlChanged(const QString &)));
|
||||
connect(cefWidget, SIGNAL(titleChanged(const QString &)), this,
|
||||
SLOT(setWindowTitle(const QString &)));
|
||||
connect(cefWidget, SIGNAL(urlChanged(const QString &)), this,
|
||||
SLOT(urlChanged(const QString &)));
|
||||
|
||||
QPushButton *close = new QPushButton(QTStr("Cancel"));
|
||||
connect(close, &QAbstractButton::clicked,
|
||||
this, &QDialog::reject);
|
||||
connect(close, &QAbstractButton::clicked, this, &QDialog::reject);
|
||||
|
||||
QHBoxLayout *bottomLayout = new QHBoxLayout();
|
||||
bottomLayout->addStretch();
|
||||
|
@ -111,7 +109,7 @@ struct OAuthInfo {
|
|||
static std::vector<OAuthInfo> loginCBs;
|
||||
|
||||
void OAuth::RegisterOAuth(const Def &d, create_cb create, login_cb login,
|
||||
delete_cookies_cb delete_cookies)
|
||||
delete_cookies_cb delete_cookies)
|
||||
{
|
||||
OAuthInfo info = {d, login, delete_cookies};
|
||||
loginCBs.push_back(info);
|
||||
|
@ -142,16 +140,14 @@ void OAuth::SaveInternal()
|
|||
{
|
||||
OBSBasic *main = OBSBasic::Get();
|
||||
config_set_string(main->Config(), service(), "RefreshToken",
|
||||
refresh_token.c_str());
|
||||
refresh_token.c_str());
|
||||
config_set_string(main->Config(), service(), "Token", token.c_str());
|
||||
config_set_uint(main->Config(), service(), "ExpireTime", expire_time);
|
||||
config_set_int(main->Config(), service(), "ScopeVer", currentScopeVer);
|
||||
}
|
||||
|
||||
static inline std::string get_config_str(
|
||||
OBSBasic *main,
|
||||
const char *section,
|
||||
const char *name)
|
||||
static inline std::string get_config_str(OBSBasic *main, const char *section,
|
||||
const char *name)
|
||||
{
|
||||
const char *val = config_get_string(main->Config(), section, name);
|
||||
return val ? val : "";
|
||||
|
@ -163,11 +159,9 @@ bool OAuth::LoadInternal()
|
|||
refresh_token = get_config_str(main, service(), "RefreshToken");
|
||||
token = get_config_str(main, service(), "Token");
|
||||
expire_time = config_get_uint(main->Config(), service(), "ExpireTime");
|
||||
currentScopeVer = (int)config_get_int(main->Config(), service(),
|
||||
"ScopeVer");
|
||||
return implicit
|
||||
? !token.empty()
|
||||
: !refresh_token.empty();
|
||||
currentScopeVer =
|
||||
(int)config_get_int(main->Config(), service(), "ScopeVer");
|
||||
return implicit ? !token.empty() : !refresh_token.empty();
|
||||
}
|
||||
|
||||
bool OAuth::TokenExpired()
|
||||
|
@ -180,7 +174,7 @@ bool OAuth::TokenExpired()
|
|||
}
|
||||
|
||||
bool OAuth::GetToken(const char *url, const std::string &client_id,
|
||||
int scope_ver, const std::string &auth_code, bool retry)
|
||||
int scope_ver, const std::string &auth_code, bool retry)
|
||||
try {
|
||||
std::string output;
|
||||
std::string error;
|
||||
|
@ -191,8 +185,8 @@ try {
|
|||
return true;
|
||||
} else {
|
||||
QString title = QTStr("Auth.InvalidScope.Title");
|
||||
QString text = QTStr("Auth.InvalidScope.Text")
|
||||
.arg(service());
|
||||
QString text =
|
||||
QTStr("Auth.InvalidScope.Text").arg(service());
|
||||
|
||||
QMessageBox::warning(OBSBasic::Get(), title, text);
|
||||
}
|
||||
|
@ -216,23 +210,15 @@ try {
|
|||
|
||||
bool success = false;
|
||||
|
||||
auto func = [&] () {
|
||||
success = GetRemoteFile(
|
||||
url,
|
||||
output,
|
||||
error,
|
||||
nullptr,
|
||||
"application/x-www-form-urlencoded",
|
||||
post_data.c_str(),
|
||||
std::vector<std::string>(),
|
||||
nullptr,
|
||||
5);
|
||||
auto func = [&]() {
|
||||
success = GetRemoteFile(url, output, error, nullptr,
|
||||
"application/x-www-form-urlencoded",
|
||||
post_data.c_str(),
|
||||
std::vector<std::string>(), nullptr, 5);
|
||||
};
|
||||
|
||||
ExecThreadedWithoutBlocking(
|
||||
func,
|
||||
QTStr("Auth.Authing.Title"),
|
||||
QTStr("Auth.Authing.Text").arg(service()));
|
||||
ExecThreadedWithoutBlocking(func, QTStr("Auth.Authing.Title"),
|
||||
QTStr("Auth.Authing.Text").arg(service()));
|
||||
if (!success || output.empty())
|
||||
throw ErrorInfo("Failed to get token from remote", error);
|
||||
|
||||
|
@ -250,13 +236,14 @@ try {
|
|||
}
|
||||
}
|
||||
if (!error.empty())
|
||||
throw ErrorInfo(error, json["error_description"].string_value());
|
||||
throw ErrorInfo(error,
|
||||
json["error_description"].string_value());
|
||||
|
||||
/* -------------------------- */
|
||||
/* success! */
|
||||
|
||||
expire_time = (uint64_t)time(nullptr) + json["expires_in"].int_value();
|
||||
token = json["access_token"].string_value();
|
||||
token = json["access_token"].string_value();
|
||||
if (token.empty())
|
||||
throw ErrorInfo("Failed to get token from remote", error);
|
||||
|
||||
|
@ -264,7 +251,8 @@ try {
|
|||
refresh_token = json["refresh_token"].string_value();
|
||||
if (refresh_token.empty())
|
||||
throw ErrorInfo("Failed to get refresh token from "
|
||||
"remote", error);
|
||||
"remote",
|
||||
error);
|
||||
|
||||
currentScopeVer = scope_ver;
|
||||
}
|
||||
|
@ -275,15 +263,14 @@ try {
|
|||
if (!retry) {
|
||||
QString title = QTStr("Auth.AuthFailure.Title");
|
||||
QString text = QTStr("Auth.AuthFailure.Text")
|
||||
.arg(service(), info.message.c_str(), info.error.c_str());
|
||||
.arg(service(), info.message.c_str(),
|
||||
info.error.c_str());
|
||||
|
||||
QMessageBox::warning(OBSBasic::Get(), title, text);
|
||||
}
|
||||
|
||||
blog(LOG_WARNING, "%s: %s: %s",
|
||||
__FUNCTION__,
|
||||
info.message.c_str(),
|
||||
info.error.c_str());
|
||||
blog(LOG_WARNING, "%s: %s: %s", __FUNCTION__, info.message.c_str(),
|
||||
info.error.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -301,7 +288,7 @@ void OAuthStreamKey::OnStreamConfig()
|
|||
|
||||
if (bwtest && strcmp(this->service(), "Twitch") == 0)
|
||||
obs_data_set_string(settings, "key",
|
||||
(key_ + "?bandwidthtest=true").c_str());
|
||||
(key_ + "?bandwidthtest=true").c_str());
|
||||
else
|
||||
obs_data_set_string(settings, "key", key_.c_str());
|
||||
|
||||
|
|
|
@ -20,8 +20,8 @@ public:
|
|||
OAuthLogin(QWidget *parent, const std::string &url, bool token);
|
||||
~OAuthLogin();
|
||||
|
||||
inline QString GetCode() const {return code;}
|
||||
inline bool LoadFail() const {return fail;}
|
||||
inline QString GetCode() const { return code; }
|
||||
inline bool LoadFail() const { return fail; }
|
||||
|
||||
virtual int exec() override;
|
||||
|
||||
|
@ -35,15 +35,16 @@ class OAuth : public Auth {
|
|||
public:
|
||||
inline OAuth(const Def &d) : Auth(d) {}
|
||||
|
||||
typedef std::function<std::shared_ptr<Auth> (QWidget *)> login_cb;
|
||||
typedef std::function<std::shared_ptr<Auth>(QWidget *)> login_cb;
|
||||
typedef std::function<void()> delete_cookies_cb;
|
||||
|
||||
static std::shared_ptr<Auth> Login(QWidget *parent,
|
||||
const std::string &service);
|
||||
const std::string &service);
|
||||
static void DeleteCookies(const std::string &service);
|
||||
|
||||
static void RegisterOAuth(const Def &d, create_cb create,
|
||||
login_cb login, delete_cookies_cb delete_cookies);
|
||||
login_cb login,
|
||||
delete_cookies_cb delete_cookies);
|
||||
|
||||
protected:
|
||||
std::string refresh_token;
|
||||
|
@ -55,12 +56,12 @@ protected:
|
|||
virtual void SaveInternal() override;
|
||||
virtual bool LoadInternal() override;
|
||||
|
||||
virtual bool RetryLogin()=0;
|
||||
virtual bool RetryLogin() = 0;
|
||||
bool TokenExpired();
|
||||
bool GetToken(const char *url, const std::string &client_id,
|
||||
int scope_ver,
|
||||
const std::string &auth_code = std::string(),
|
||||
bool retry = false);
|
||||
int scope_ver,
|
||||
const std::string &auth_code = std::string(),
|
||||
bool retry = false);
|
||||
};
|
||||
|
||||
class OAuthStreamKey : public OAuth {
|
||||
|
@ -72,7 +73,7 @@ protected:
|
|||
public:
|
||||
inline OAuthStreamKey(const Def &d) : OAuth(d) {}
|
||||
|
||||
inline const std::string &key() const {return key_;}
|
||||
inline const std::string &key() const { return key_; }
|
||||
|
||||
virtual void OnStreamConfig() override;
|
||||
};
|
||||
|
|
|
@ -22,23 +22,17 @@ extern QCefCookieManager *panel_cookies;
|
|||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#define RESTREAM_AUTH_URL "https://obsproject.com/app-auth/restream?action=redirect"
|
||||
#define RESTREAM_AUTH_URL \
|
||||
"https://obsproject.com/app-auth/restream?action=redirect"
|
||||
#define RESTREAM_TOKEN_URL "https://obsproject.com/app-auth/restream-token"
|
||||
#define RESTREAM_STREAMKEY_URL "https://api.restream.io/v2/user/streamKey"
|
||||
#define RESTREAM_SCOPE_VERSION 1
|
||||
|
||||
|
||||
static Auth::Def restreamDef = {
|
||||
"Restream",
|
||||
Auth::Type::OAuth_StreamKey
|
||||
};
|
||||
static Auth::Def restreamDef = {"Restream", Auth::Type::OAuth_StreamKey};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
RestreamAuth::RestreamAuth(const Def &d)
|
||||
: OAuthStreamKey(d)
|
||||
{
|
||||
}
|
||||
RestreamAuth::RestreamAuth(const Def &d) : OAuthStreamKey(d) {}
|
||||
|
||||
bool RestreamAuth::GetChannelInfo()
|
||||
try {
|
||||
|
@ -65,23 +59,15 @@ try {
|
|||
Json json;
|
||||
bool success;
|
||||
|
||||
auto func = [&] () {
|
||||
success = GetRemoteFile(
|
||||
RESTREAM_STREAMKEY_URL,
|
||||
output,
|
||||
error,
|
||||
nullptr,
|
||||
"application/json",
|
||||
nullptr,
|
||||
headers,
|
||||
nullptr,
|
||||
5);
|
||||
auto func = [&]() {
|
||||
success = GetRemoteFile(RESTREAM_STREAMKEY_URL, output, error,
|
||||
nullptr, "application/json", nullptr,
|
||||
headers, nullptr, 5);
|
||||
};
|
||||
|
||||
ExecThreadedWithoutBlocking(
|
||||
func,
|
||||
QTStr("Auth.LoadingChannel.Title"),
|
||||
QTStr("Auth.LoadingChannel.Text").arg(service()));
|
||||
func, QTStr("Auth.LoadingChannel.Title"),
|
||||
QTStr("Auth.LoadingChannel.Text").arg(service()));
|
||||
if (!success || output.empty())
|
||||
throw ErrorInfo("Failed to get stream key from remote", error);
|
||||
|
||||
|
@ -91,7 +77,8 @@ try {
|
|||
|
||||
error = json["error"].string_value();
|
||||
if (!error.empty())
|
||||
throw ErrorInfo(error, json["error_description"].string_value());
|
||||
throw ErrorInfo(error,
|
||||
json["error_description"].string_value());
|
||||
|
||||
key_ = json["streamKey"].string_value();
|
||||
|
||||
|
@ -99,14 +86,13 @@ try {
|
|||
} catch (ErrorInfo info) {
|
||||
QString title = QTStr("Auth.ChannelFailure.Title");
|
||||
QString text = QTStr("Auth.ChannelFailure.Text")
|
||||
.arg(service(), info.message.c_str(), info.error.c_str());
|
||||
.arg(service(), info.message.c_str(),
|
||||
info.error.c_str());
|
||||
|
||||
QMessageBox::warning(OBSBasic::Get(), title, text);
|
||||
|
||||
blog(LOG_WARNING, "%s: %s: %s",
|
||||
__FUNCTION__,
|
||||
info.message.c_str(),
|
||||
info.error.c_str());
|
||||
blog(LOG_WARNING, "%s: %s: %s", __FUNCTION__, info.message.c_str(),
|
||||
info.error.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -114,14 +100,12 @@ void RestreamAuth::SaveInternal()
|
|||
{
|
||||
OBSBasic *main = OBSBasic::Get();
|
||||
config_set_string(main->Config(), service(), "DockState",
|
||||
main->saveState().toBase64().constData());
|
||||
main->saveState().toBase64().constData());
|
||||
OAuthStreamKey::SaveInternal();
|
||||
}
|
||||
|
||||
static inline std::string get_config_str(
|
||||
OBSBasic *main,
|
||||
const char *section,
|
||||
const char *name)
|
||||
static inline std::string get_config_str(OBSBasic *main, const char *section,
|
||||
const char *name)
|
||||
{
|
||||
const char *val = config_get_string(main->Config(), section, name);
|
||||
return val ? val : "";
|
||||
|
@ -201,10 +185,9 @@ void RestreamAuth::LoadUI()
|
|||
if (firstLoad) {
|
||||
chat->setVisible(true);
|
||||
info->setVisible(true);
|
||||
}
|
||||
else {
|
||||
const char *dockStateStr = config_get_string(main->Config(),
|
||||
service(), "DockState");
|
||||
} else {
|
||||
const char *dockStateStr = config_get_string(
|
||||
main->Config(), service(), "DockState");
|
||||
QByteArray dockState =
|
||||
QByteArray::fromBase64(QByteArray(dockStateStr));
|
||||
main->restoreState(dockState);
|
||||
|
@ -227,8 +210,7 @@ bool RestreamAuth::RetryLogin()
|
|||
std::string client_id = RESTREAM_CLIENTID;
|
||||
deobfuscate_str(&client_id[0], RESTREAM_HASH);
|
||||
|
||||
return GetToken(RESTREAM_TOKEN_URL, client_id,
|
||||
RESTREAM_SCOPE_VERSION,
|
||||
return GetToken(RESTREAM_TOKEN_URL, client_id, RESTREAM_SCOPE_VERSION,
|
||||
QT_TO_UTF8(login.GetCode()), true);
|
||||
}
|
||||
|
||||
|
@ -248,8 +230,8 @@ std::shared_ptr<Auth> RestreamAuth::Login(QWidget *parent)
|
|||
deobfuscate_str(&client_id[0], RESTREAM_HASH);
|
||||
|
||||
if (!auth->GetToken(RESTREAM_TOKEN_URL, client_id,
|
||||
RESTREAM_SCOPE_VERSION,
|
||||
QT_TO_UTF8(login.GetCode()))) {
|
||||
RESTREAM_SCOPE_VERSION,
|
||||
QT_TO_UTF8(login.GetCode()))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -275,9 +257,6 @@ static void DeleteCookies()
|
|||
|
||||
void RegisterRestreamAuth()
|
||||
{
|
||||
OAuth::RegisterOAuth(
|
||||
restreamDef,
|
||||
CreateRestreamAuth,
|
||||
RestreamAuth::Login,
|
||||
DeleteCookies);
|
||||
OAuth::RegisterOAuth(restreamDef, CreateRestreamAuth,
|
||||
RestreamAuth::Login, DeleteCookies);
|
||||
}
|
||||
|
|
|
@ -24,35 +24,28 @@ extern QCefCookieManager *panel_cookies;
|
|||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#define TWITCH_AUTH_URL \
|
||||
"https://obsproject.com/app-auth/twitch?action=redirect"
|
||||
#define TWITCH_TOKEN_URL \
|
||||
"https://obsproject.com/app-auth/twitch-token"
|
||||
#define ACCEPT_HEADER \
|
||||
"Accept: application/vnd.twitchtv.v5+json"
|
||||
#define TWITCH_AUTH_URL "https://obsproject.com/app-auth/twitch?action=redirect"
|
||||
#define TWITCH_TOKEN_URL "https://obsproject.com/app-auth/twitch-token"
|
||||
#define ACCEPT_HEADER "Accept: application/vnd.twitchtv.v5+json"
|
||||
|
||||
#define TWITCH_SCOPE_VERSION 1
|
||||
|
||||
static Auth::Def twitchDef = {
|
||||
"Twitch",
|
||||
Auth::Type::OAuth_StreamKey
|
||||
};
|
||||
static Auth::Def twitchDef = {"Twitch", Auth::Type::OAuth_StreamKey};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
TwitchAuth::TwitchAuth(const Def &d)
|
||||
: OAuthStreamKey(d)
|
||||
TwitchAuth::TwitchAuth(const Def &d) : OAuthStreamKey(d)
|
||||
{
|
||||
if (!cef)
|
||||
return;
|
||||
|
||||
cef->add_popup_whitelist_url(
|
||||
"https://twitch.tv/popout/frankerfacez/chat?ffz-settings",
|
||||
this);
|
||||
"https://twitch.tv/popout/frankerfacez/chat?ffz-settings",
|
||||
this);
|
||||
uiLoadTimer.setSingleShot(true);
|
||||
uiLoadTimer.setInterval(500);
|
||||
connect(&uiLoadTimer, &QTimer::timeout,
|
||||
this, &TwitchAuth::TryLoadSecondaryUIPanes);
|
||||
connect(&uiLoadTimer, &QTimer::timeout, this,
|
||||
&TwitchAuth::TryLoadSecondaryUIPanes);
|
||||
}
|
||||
|
||||
bool TwitchAuth::GetChannelInfo()
|
||||
|
@ -82,33 +75,25 @@ try {
|
|||
|
||||
bool success = false;
|
||||
|
||||
auto func = [&] () {
|
||||
success = GetRemoteFile(
|
||||
"https://api.twitch.tv/kraken/channel",
|
||||
output,
|
||||
error,
|
||||
&error_code,
|
||||
"application/json",
|
||||
nullptr,
|
||||
headers,
|
||||
nullptr,
|
||||
5);
|
||||
auto func = [&]() {
|
||||
success = GetRemoteFile("https://api.twitch.tv/kraken/channel",
|
||||
output, error, &error_code,
|
||||
"application/json", nullptr, headers,
|
||||
nullptr, 5);
|
||||
};
|
||||
|
||||
ExecThreadedWithoutBlocking(
|
||||
func,
|
||||
QTStr("Auth.LoadingChannel.Title"),
|
||||
QTStr("Auth.LoadingChannel.Text").arg(service()));
|
||||
func, QTStr("Auth.LoadingChannel.Title"),
|
||||
QTStr("Auth.LoadingChannel.Text").arg(service()));
|
||||
if (error_code == 403) {
|
||||
OBSMessageBox::warning(OBSBasic::Get(),
|
||||
Str("TwitchAuth.TwoFactorFail.Title"),
|
||||
Str("TwitchAuth.TwoFactorFail.Text"),
|
||||
true);
|
||||
blog(LOG_WARNING, "%s: %s",
|
||||
__FUNCTION__,
|
||||
"Got 403 from Twitch, user probably does not "
|
||||
"have two-factor authentication enabled on "
|
||||
"their account");
|
||||
Str("TwitchAuth.TwoFactorFail.Title"),
|
||||
Str("TwitchAuth.TwoFactorFail.Text"),
|
||||
true);
|
||||
blog(LOG_WARNING, "%s: %s", __FUNCTION__,
|
||||
"Got 403 from Twitch, user probably does not "
|
||||
"have two-factor authentication enabled on "
|
||||
"their account");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -125,10 +110,10 @@ try {
|
|||
if (RetryLogin()) {
|
||||
return GetChannelInfo();
|
||||
}
|
||||
throw ErrorInfo(error,
|
||||
json["message"].string_value());
|
||||
throw ErrorInfo(error, json["message"].string_value());
|
||||
}
|
||||
throw ErrorInfo(error, json["error_description"].string_value());
|
||||
throw ErrorInfo(error,
|
||||
json["error_description"].string_value());
|
||||
}
|
||||
|
||||
name = json["name"].string_value();
|
||||
|
@ -138,14 +123,13 @@ try {
|
|||
} catch (ErrorInfo info) {
|
||||
QString title = QTStr("Auth.ChannelFailure.Title");
|
||||
QString text = QTStr("Auth.ChannelFailure.Text")
|
||||
.arg(service(), info.message.c_str(), info.error.c_str());
|
||||
.arg(service(), info.message.c_str(),
|
||||
info.error.c_str());
|
||||
|
||||
QMessageBox::warning(OBSBasic::Get(), title, text);
|
||||
|
||||
blog(LOG_WARNING, "%s: %s: %s",
|
||||
__FUNCTION__,
|
||||
info.message.c_str(),
|
||||
info.error.c_str());
|
||||
blog(LOG_WARNING, "%s: %s: %s", __FUNCTION__, info.message.c_str(),
|
||||
info.error.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -155,15 +139,13 @@ void TwitchAuth::SaveInternal()
|
|||
config_set_string(main->Config(), service(), "Name", name.c_str());
|
||||
if (uiLoaded) {
|
||||
config_set_string(main->Config(), service(), "DockState",
|
||||
main->saveState().toBase64().constData());
|
||||
main->saveState().toBase64().constData());
|
||||
}
|
||||
OAuthStreamKey::SaveInternal();
|
||||
}
|
||||
|
||||
static inline std::string get_config_str(
|
||||
OBSBasic *main,
|
||||
const char *section,
|
||||
const char *name)
|
||||
static inline std::string get_config_str(OBSBasic *main, const char *section,
|
||||
const char *name)
|
||||
{
|
||||
const char *val = config_get_string(main->Config(), section, name);
|
||||
return val ? val : "";
|
||||
|
@ -266,8 +248,8 @@ void TwitchAuth::LoadUI()
|
|||
if (firstLoad) {
|
||||
chat->setVisible(true);
|
||||
} else {
|
||||
const char *dockStateStr = config_get_string(main->Config(),
|
||||
service(), "DockState");
|
||||
const char *dockStateStr = config_get_string(
|
||||
main->Config(), service(), "DockState");
|
||||
QByteArray dockState =
|
||||
QByteArray::fromBase64(QByteArray(dockStateStr));
|
||||
main->restoreState(dockState);
|
||||
|
@ -367,8 +349,8 @@ void TwitchAuth::LoadSecondaryUIPanes()
|
|||
QSize statSize = stat->frameSize();
|
||||
|
||||
info->move(pos.x() + 50, pos.y() + 50);
|
||||
stat->move(pos.x() + size.width() / 2 - statSize.width() / 2,
|
||||
pos.y() + size.height() / 2 - statSize.height() / 2);
|
||||
stat->move(pos.x() + size.width() / 2 - statSize.width() / 2,
|
||||
pos.y() + size.height() / 2 - statSize.height() / 2);
|
||||
feed->move(pos.x() + 100, pos.y() + 100);
|
||||
|
||||
if (firstLoad) {
|
||||
|
@ -376,15 +358,15 @@ void TwitchAuth::LoadSecondaryUIPanes()
|
|||
stat->setVisible(false);
|
||||
feed->setVisible(false);
|
||||
} else {
|
||||
uint32_t lastVersion = config_get_int(App()->GlobalConfig(), "General",
|
||||
"LastVersion");
|
||||
uint32_t lastVersion = config_get_int(App()->GlobalConfig(),
|
||||
"General", "LastVersion");
|
||||
|
||||
if (lastVersion <= MAKE_SEMANTIC_VERSION(23, 0, 2)) {
|
||||
feed->setVisible(false);
|
||||
}
|
||||
|
||||
const char *dockStateStr = config_get_string(main->Config(),
|
||||
service(), "DockState");
|
||||
const char *dockStateStr = config_get_string(
|
||||
main->Config(), service(), "DockState");
|
||||
QByteArray dockState =
|
||||
QByteArray::fromBase64(QByteArray(dockStateStr));
|
||||
main->restoreState(dockState);
|
||||
|
@ -405,21 +387,21 @@ void TwitchAuth::TryLoadSecondaryUIPanes()
|
|||
{
|
||||
QPointer<TwitchAuth> this_ = this;
|
||||
|
||||
auto cb = [this_] (bool found)
|
||||
{
|
||||
auto cb = [this_](bool found) {
|
||||
if (!this_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
QMetaObject::invokeMethod(&this_->uiLoadTimer,
|
||||
"start");
|
||||
QMetaObject::invokeMethod(&this_->uiLoadTimer, "start");
|
||||
} else {
|
||||
QMetaObject::invokeMethod(this_, "LoadSecondaryUIPanes");
|
||||
QMetaObject::invokeMethod(this_,
|
||||
"LoadSecondaryUIPanes");
|
||||
}
|
||||
};
|
||||
|
||||
panel_cookies->CheckForCookie("https://www.twitch.tv", "auth-token", cb);
|
||||
panel_cookies->CheckForCookie("https://www.twitch.tv", "auth-token",
|
||||
cb);
|
||||
}
|
||||
|
||||
bool TwitchAuth::RetryLogin()
|
||||
|
@ -429,7 +411,8 @@ bool TwitchAuth::RetryLogin()
|
|||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<TwitchAuth> auth = std::make_shared<TwitchAuth>(twitchDef);
|
||||
std::shared_ptr<TwitchAuth> auth =
|
||||
std::make_shared<TwitchAuth>(twitchDef);
|
||||
std::string client_id = TWITCH_CLIENTID;
|
||||
deobfuscate_str(&client_id[0], TWITCH_HASH);
|
||||
|
||||
|
@ -444,13 +427,14 @@ std::shared_ptr<Auth> TwitchAuth::Login(QWidget *parent)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<TwitchAuth> auth = std::make_shared<TwitchAuth>(twitchDef);
|
||||
std::shared_ptr<TwitchAuth> auth =
|
||||
std::make_shared<TwitchAuth>(twitchDef);
|
||||
|
||||
std::string client_id = TWITCH_CLIENTID;
|
||||
deobfuscate_str(&client_id[0], TWITCH_HASH);
|
||||
|
||||
if (!auth->GetToken(TWITCH_TOKEN_URL, client_id, TWITCH_SCOPE_VERSION,
|
||||
QT_TO_UTF8(login.GetCode()))) {
|
||||
QT_TO_UTF8(login.GetCode()))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -475,9 +459,6 @@ static void DeleteCookies()
|
|||
|
||||
void RegisterTwitchAuth()
|
||||
{
|
||||
OAuth::RegisterOAuth(
|
||||
twitchDef,
|
||||
CreateTwitchAuth,
|
||||
TwitchAuth::Login,
|
||||
DeleteCookies);
|
||||
OAuth::RegisterOAuth(twitchDef, CreateTwitchAuth, TwitchAuth::Login,
|
||||
DeleteCookies);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include <QMouseEvent>
|
||||
|
||||
class ClickableLabel : public QLabel {
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
inline ClickableLabel(QWidget *parent = 0) : QLabel(parent) {}
|
||||
|
|
|
@ -32,10 +32,10 @@ OBSCrashReport::OBSCrashReport(QWidget *parent, const char *text)
|
|||
|
||||
setLayout(mainLayout);
|
||||
|
||||
QWidget::connect(copyButton, SIGNAL(clicked()),
|
||||
this, SLOT(CopyClicked()));
|
||||
QWidget::connect(exitButton, SIGNAL(clicked()),
|
||||
this, SLOT(ExitClicked()));
|
||||
QWidget::connect(copyButton, SIGNAL(clicked()), this,
|
||||
SLOT(CopyClicked()));
|
||||
QWidget::connect(exitButton, SIGNAL(clicked()), this,
|
||||
SLOT(ExitClicked()));
|
||||
|
||||
resize(800, 600);
|
||||
setWindowTitle("Oops, OBS has crashed!");
|
||||
|
|
|
@ -21,15 +21,15 @@
|
|||
#define SUPPORTS_FRACTIONAL_SCALING
|
||||
#endif
|
||||
|
||||
static inline void GetScaleAndCenterPos(
|
||||
int baseCX, int baseCY, int windowCX, int windowCY,
|
||||
int &x, int &y, float &scale)
|
||||
static inline void GetScaleAndCenterPos(int baseCX, int baseCY, int windowCX,
|
||||
int windowCY, int &x, int &y,
|
||||
float &scale)
|
||||
{
|
||||
double windowAspect, baseAspect;
|
||||
int newCX, newCY;
|
||||
|
||||
windowAspect = double(windowCX) / double(windowCY);
|
||||
baseAspect = double(baseCX) / double(baseCY);
|
||||
baseAspect = double(baseCX) / double(baseCY);
|
||||
|
||||
if (windowAspect > baseAspect) {
|
||||
scale = float(windowCY) / float(baseCY);
|
||||
|
@ -41,16 +41,16 @@ static inline void GetScaleAndCenterPos(
|
|||
newCY = int(float(windowCX) / baseAspect);
|
||||
}
|
||||
|
||||
x = windowCX/2 - newCX/2;
|
||||
y = windowCY/2 - newCY/2;
|
||||
x = windowCX / 2 - newCX / 2;
|
||||
y = windowCY / 2 - newCY / 2;
|
||||
}
|
||||
|
||||
static inline void GetCenterPosFromFixedScale(
|
||||
int baseCX, int baseCY, int windowCX, int windowCY,
|
||||
int &x, int &y, float scale)
|
||||
static inline void GetCenterPosFromFixedScale(int baseCX, int baseCY,
|
||||
int windowCX, int windowCY,
|
||||
int &x, int &y, float scale)
|
||||
{
|
||||
x = (float(windowCX) - float(baseCX)*scale) / 2.0f;
|
||||
y = (float(windowCY) - float(baseCY)*scale) / 2.0f;
|
||||
x = (float(windowCX) - float(baseCX) * scale) / 2.0f;
|
||||
y = (float(windowCY) - float(baseCY) * scale) / 2.0f;
|
||||
}
|
||||
|
||||
static inline QSize GetPixelSize(QWidget *widget)
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
|
||||
DoubleSlider::DoubleSlider(QWidget *parent) : SliderIgnoreScroll(parent)
|
||||
{
|
||||
connect(this, SIGNAL(valueChanged(int)),
|
||||
this, SLOT(intValChanged(int)));
|
||||
connect(this, SIGNAL(valueChanged(int)), this,
|
||||
SLOT(intValChanged(int)));
|
||||
}
|
||||
|
||||
void DoubleSlider::setDoubleConstraints(double newMin, double newMax,
|
||||
double newStep, double val)
|
||||
double newStep, double val)
|
||||
{
|
||||
minVal = newMin;
|
||||
maxVal = newMax;
|
||||
|
@ -26,7 +26,7 @@ void DoubleSlider::setDoubleConstraints(double newMin, double newMax,
|
|||
|
||||
void DoubleSlider::intValChanged(int val)
|
||||
{
|
||||
emit doubleValChanged((minVal/minStep + val) * minStep);
|
||||
emit doubleValChanged((minVal / minStep + val) * minStep);
|
||||
}
|
||||
|
||||
void DoubleSlider::setDoubleVal(double val)
|
||||
|
|
|
@ -11,8 +11,8 @@ class DoubleSlider : public SliderIgnoreScroll {
|
|||
public:
|
||||
DoubleSlider(QWidget *parent = nullptr);
|
||||
|
||||
void setDoubleConstraints(double newMin, double newMax,
|
||||
double newStep, double val);
|
||||
void setDoubleConstraints(double newMin, double newMax, double newStep,
|
||||
double val);
|
||||
|
||||
signals:
|
||||
void doubleValChanged(double val);
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
#include <QListWidget>
|
||||
|
||||
class FocusList : public QListWidget
|
||||
{
|
||||
class FocusList : public QListWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
#include "decklink-ui-main.h"
|
||||
|
||||
DecklinkOutputUI::DecklinkOutputUI(QWidget *parent)
|
||||
: QDialog(parent),
|
||||
ui(new Ui_Output)
|
||||
: QDialog(parent), ui(new Ui_Output)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
|
@ -20,8 +19,10 @@ DecklinkOutputUI::DecklinkOutputUI(QWidget *parent)
|
|||
connect(ui->startOutput, SIGNAL(released()), this, SLOT(StartOutput()));
|
||||
connect(ui->stopOutput, SIGNAL(released()), this, SLOT(StopOutput()));
|
||||
|
||||
connect(ui->startPreviewOutput, SIGNAL(released()), this, SLOT(StartPreviewOutput()));
|
||||
connect(ui->stopPreviewOutput, SIGNAL(released()), this, SLOT(StopPreviewOutput()));
|
||||
connect(ui->startPreviewOutput, SIGNAL(released()), this,
|
||||
SLOT(StartPreviewOutput()));
|
||||
connect(ui->stopPreviewOutput, SIGNAL(released()), this,
|
||||
SLOT(StopPreviewOutput()));
|
||||
}
|
||||
|
||||
void DecklinkOutputUI::ShowHideDialog()
|
||||
|
@ -43,25 +44,26 @@ void DecklinkOutputUI::SetupPropertiesView()
|
|||
if (data)
|
||||
obs_data_apply(settings, data);
|
||||
|
||||
propertiesView = new OBSPropertiesView(settings,
|
||||
"decklink_output",
|
||||
(PropertiesReloadCallback) obs_get_output_properties,
|
||||
170);
|
||||
propertiesView = new OBSPropertiesView(
|
||||
settings, "decklink_output",
|
||||
(PropertiesReloadCallback)obs_get_output_properties, 170);
|
||||
|
||||
ui->propertiesLayout->addWidget(propertiesView);
|
||||
obs_data_release(settings);
|
||||
|
||||
connect(propertiesView, SIGNAL(Changed()), this, SLOT(PropertiesChanged()));
|
||||
connect(propertiesView, SIGNAL(Changed()), this,
|
||||
SLOT(PropertiesChanged()));
|
||||
}
|
||||
|
||||
void DecklinkOutputUI::SaveSettings()
|
||||
{
|
||||
BPtr<char> modulePath = obs_module_get_config_path(obs_current_module(), "");
|
||||
BPtr<char> modulePath =
|
||||
obs_module_get_config_path(obs_current_module(), "");
|
||||
|
||||
os_mkdirs(modulePath);
|
||||
|
||||
BPtr<char> path = obs_module_get_config_path(obs_current_module(),
|
||||
"decklinkOutputProps.json");
|
||||
BPtr<char> path = obs_module_get_config_path(
|
||||
obs_current_module(), "decklinkOutputProps.json");
|
||||
|
||||
obs_data_t *settings = propertiesView->GetSettings();
|
||||
if (settings)
|
||||
|
@ -79,15 +81,15 @@ void DecklinkOutputUI::SetupPreviewPropertiesView()
|
|||
if (data)
|
||||
obs_data_apply(settings, data);
|
||||
|
||||
previewPropertiesView = new OBSPropertiesView(settings,
|
||||
"decklink_output",
|
||||
(PropertiesReloadCallback) obs_get_output_properties,
|
||||
170);
|
||||
previewPropertiesView = new OBSPropertiesView(
|
||||
settings, "decklink_output",
|
||||
(PropertiesReloadCallback)obs_get_output_properties, 170);
|
||||
|
||||
ui->previewPropertiesLayout->addWidget(previewPropertiesView);
|
||||
obs_data_release(settings);
|
||||
|
||||
connect(previewPropertiesView, SIGNAL(Changed()), this, SLOT(PreviewPropertiesChanged()));
|
||||
connect(previewPropertiesView, SIGNAL(Changed()), this,
|
||||
SLOT(PreviewPropertiesChanged()));
|
||||
}
|
||||
|
||||
void DecklinkOutputUI::SavePreviewSettings()
|
||||
|
@ -96,15 +98,14 @@ void DecklinkOutputUI::SavePreviewSettings()
|
|||
|
||||
os_mkdirs(modulePath);
|
||||
|
||||
char *path = obs_module_get_config_path(obs_current_module(),
|
||||
"decklinkPreviewOutputProps.json");
|
||||
char *path = obs_module_get_config_path(
|
||||
obs_current_module(), "decklinkPreviewOutputProps.json");
|
||||
|
||||
obs_data_t *settings = previewPropertiesView->GetSettings();
|
||||
if (settings)
|
||||
obs_data_save_json_safe(settings, path, "tmp", "bak");
|
||||
}
|
||||
|
||||
|
||||
void DecklinkOutputUI::StartOutput()
|
||||
{
|
||||
SaveSettings();
|
||||
|
@ -121,7 +122,6 @@ void DecklinkOutputUI::PropertiesChanged()
|
|||
SaveSettings();
|
||||
}
|
||||
|
||||
|
||||
void DecklinkOutputUI::StartPreviewOutput()
|
||||
{
|
||||
SavePreviewSettings();
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include "../../UI/properties-view.hpp"
|
||||
|
||||
class DecklinkOutputUI : public QDialog {
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
private:
|
||||
OBSPropertiesView *propertiesView;
|
||||
OBSPropertiesView *previewPropertiesView;
|
||||
|
|
|
@ -37,8 +37,8 @@ static struct preview_output context = {0};
|
|||
|
||||
OBSData load_settings()
|
||||
{
|
||||
BPtr<char> path = obs_module_get_config_path(obs_current_module(),
|
||||
"decklinkOutputProps.json");
|
||||
BPtr<char> path = obs_module_get_config_path(
|
||||
obs_current_module(), "decklinkOutputProps.json");
|
||||
BPtr<char> jsonData = os_quick_read_utf8_file(path);
|
||||
if (!!jsonData) {
|
||||
obs_data_t *data = obs_data_create_from_json(jsonData);
|
||||
|
@ -58,7 +58,8 @@ void output_start()
|
|||
|
||||
if (settings != nullptr) {
|
||||
output = obs_output_create("decklink_output",
|
||||
"decklink_output", settings, NULL);
|
||||
"decklink_output", settings,
|
||||
NULL);
|
||||
|
||||
obs_output_start(output);
|
||||
obs_data_release(settings);
|
||||
|
@ -77,11 +78,10 @@ void output_stop()
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
OBSData load_preview_settings()
|
||||
{
|
||||
BPtr<char> path = obs_module_get_config_path(obs_current_module(),
|
||||
"decklinkPreviewOutputProps.json");
|
||||
BPtr<char> path = obs_module_get_config_path(
|
||||
obs_current_module(), "decklinkPreviewOutputProps.json");
|
||||
BPtr<char> jsonData = os_quick_read_utf8_file(path);
|
||||
if (!!jsonData) {
|
||||
obs_data_t *data = obs_data_create_from_json(jsonData);
|
||||
|
@ -103,8 +103,9 @@ void preview_output_start()
|
|||
OBSData settings = load_preview_settings();
|
||||
|
||||
if (settings != nullptr) {
|
||||
context.output = obs_output_create("decklink_output",
|
||||
"decklink_preview_output", settings, NULL);
|
||||
context.output = obs_output_create(
|
||||
"decklink_output", "decklink_preview_output",
|
||||
settings, NULL);
|
||||
|
||||
obs_get_video_info(&context.ovi);
|
||||
|
||||
|
@ -112,11 +113,14 @@ void preview_output_start()
|
|||
uint32_t height = context.ovi.base_height;
|
||||
|
||||
obs_enter_graphics();
|
||||
context.texrender = gs_texrender_create(GS_BGRA, GS_ZS_NONE);
|
||||
context.stagesurface = gs_stagesurface_create(width, height, GS_BGRA);
|
||||
context.texrender =
|
||||
gs_texrender_create(GS_BGRA, GS_ZS_NONE);
|
||||
context.stagesurface =
|
||||
gs_stagesurface_create(width, height, GS_BGRA);
|
||||
obs_leave_graphics();
|
||||
|
||||
const video_output_info *mainVOI = video_output_get_info(obs_get_video());
|
||||
const video_output_info *mainVOI =
|
||||
video_output_get_info(obs_get_video());
|
||||
|
||||
video_output_info vi = {0};
|
||||
vi.format = VIDEO_FORMAT_BGRA;
|
||||
|
@ -131,15 +135,21 @@ void preview_output_start()
|
|||
|
||||
video_output_open(&context.video_queue, &vi);
|
||||
|
||||
obs_frontend_add_event_callback(on_preview_scene_changed, &context);
|
||||
obs_frontend_add_event_callback(
|
||||
on_preview_scene_changed, &context);
|
||||
if (obs_frontend_preview_program_mode_active()) {
|
||||
context.current_source = obs_frontend_get_current_preview_scene();
|
||||
context.current_source =
|
||||
obs_frontend_get_current_preview_scene();
|
||||
} else {
|
||||
context.current_source = obs_frontend_get_current_scene();
|
||||
context.current_source =
|
||||
obs_frontend_get_current_scene();
|
||||
}
|
||||
obs_add_main_render_callback(render_preview_source, &context);
|
||||
obs_add_main_render_callback(render_preview_source,
|
||||
&context);
|
||||
|
||||
obs_output_set_media(context.output, context.video_queue, obs_get_audio());
|
||||
obs_output_set_media(context.output,
|
||||
context.video_queue,
|
||||
obs_get_audio());
|
||||
obs_output_start(context.output);
|
||||
|
||||
preview_output_running = true;
|
||||
|
@ -153,8 +163,10 @@ void preview_output_stop()
|
|||
obs_output_stop(context.output);
|
||||
video_output_stop(context.video_queue);
|
||||
|
||||
obs_remove_main_render_callback(render_preview_source, &context);
|
||||
obs_frontend_remove_event_callback(on_preview_scene_changed, &context);
|
||||
obs_remove_main_render_callback(render_preview_source,
|
||||
&context);
|
||||
obs_frontend_remove_event_callback(on_preview_scene_changed,
|
||||
&context);
|
||||
|
||||
obs_source_release(context.current_source);
|
||||
|
||||
|
@ -171,33 +183,34 @@ void preview_output_stop()
|
|||
|
||||
void on_preview_scene_changed(enum obs_frontend_event event, void *param)
|
||||
{
|
||||
auto ctx = (struct preview_output*)param;
|
||||
auto ctx = (struct preview_output *)param;
|
||||
switch (event) {
|
||||
case OBS_FRONTEND_EVENT_STUDIO_MODE_ENABLED:
|
||||
case OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED:
|
||||
obs_source_release(ctx->current_source);
|
||||
ctx->current_source = obs_frontend_get_current_preview_scene();
|
||||
break;
|
||||
case OBS_FRONTEND_EVENT_STUDIO_MODE_DISABLED:
|
||||
case OBS_FRONTEND_EVENT_STUDIO_MODE_ENABLED:
|
||||
case OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED:
|
||||
obs_source_release(ctx->current_source);
|
||||
ctx->current_source = obs_frontend_get_current_preview_scene();
|
||||
break;
|
||||
case OBS_FRONTEND_EVENT_STUDIO_MODE_DISABLED:
|
||||
obs_source_release(ctx->current_source);
|
||||
ctx->current_source = obs_frontend_get_current_scene();
|
||||
break;
|
||||
case OBS_FRONTEND_EVENT_SCENE_CHANGED:
|
||||
if (!obs_frontend_preview_program_mode_active()) {
|
||||
obs_source_release(ctx->current_source);
|
||||
ctx->current_source = obs_frontend_get_current_scene();
|
||||
break;
|
||||
case OBS_FRONTEND_EVENT_SCENE_CHANGED:
|
||||
if (!obs_frontend_preview_program_mode_active()) {
|
||||
obs_source_release(ctx->current_source);
|
||||
ctx->current_source = obs_frontend_get_current_scene();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void render_preview_source(void *param, uint32_t cx, uint32_t cy)
|
||||
{
|
||||
auto ctx = (struct preview_output*)param;
|
||||
auto ctx = (struct preview_output *)param;
|
||||
|
||||
if (!ctx->current_source) return;
|
||||
if (!ctx->current_source)
|
||||
return;
|
||||
|
||||
uint32_t width = obs_source_get_base_width(ctx->current_source);
|
||||
uint32_t height = obs_source_get_base_height(ctx->current_source);
|
||||
|
@ -209,7 +222,8 @@ void render_preview_source(void *param, uint32_t cx, uint32_t cy)
|
|||
vec4_zero(&background);
|
||||
|
||||
gs_clear(GS_CLEAR_COLOR, &background, 0.0f, 0);
|
||||
gs_ortho(0.0f, (float)width, 0.0f, (float)height, -100.0f, 100.0f);
|
||||
gs_ortho(0.0f, (float)width, 0.0f, (float)height, -100.0f,
|
||||
100.0f);
|
||||
|
||||
gs_blend_state_push();
|
||||
gs_blend_function(GS_BLEND_ONE, GS_BLEND_ZERO);
|
||||
|
@ -220,18 +234,25 @@ void render_preview_source(void *param, uint32_t cx, uint32_t cy)
|
|||
gs_texrender_end(ctx->texrender);
|
||||
|
||||
struct video_frame output_frame;
|
||||
if (video_output_lock_frame(ctx->video_queue, &output_frame, 1, os_gettime_ns()))
|
||||
{
|
||||
gs_stage_texture(ctx->stagesurface, gs_texrender_get_texture(ctx->texrender));
|
||||
if (video_output_lock_frame(ctx->video_queue, &output_frame, 1,
|
||||
os_gettime_ns())) {
|
||||
gs_stage_texture(
|
||||
ctx->stagesurface,
|
||||
gs_texrender_get_texture(ctx->texrender));
|
||||
|
||||
if (gs_stagesurface_map(ctx->stagesurface, &ctx->video_data, &ctx->video_linesize)) {
|
||||
if (gs_stagesurface_map(ctx->stagesurface,
|
||||
&ctx->video_data,
|
||||
&ctx->video_linesize)) {
|
||||
uint32_t linesize = output_frame.linesize[0];
|
||||
for (uint32_t i = 0; i < ctx->ovi.base_height; i++) {
|
||||
for (uint32_t i = 0; i < ctx->ovi.base_height;
|
||||
i++) {
|
||||
uint32_t dst_offset = linesize * i;
|
||||
uint32_t src_offset = ctx->video_linesize * i;
|
||||
memcpy(output_frame.data[0] + dst_offset,
|
||||
ctx->video_data + src_offset,
|
||||
linesize);
|
||||
uint32_t src_offset =
|
||||
ctx->video_linesize * i;
|
||||
memcpy(output_frame.data[0] +
|
||||
dst_offset,
|
||||
ctx->video_data + src_offset,
|
||||
linesize);
|
||||
}
|
||||
|
||||
gs_stagesurface_unmap(ctx->stagesurface);
|
||||
|
@ -245,18 +266,16 @@ void render_preview_source(void *param, uint32_t cx, uint32_t cy)
|
|||
|
||||
void addOutputUI(void)
|
||||
{
|
||||
QAction *action = (QAction*)obs_frontend_add_tools_menu_qaction(
|
||||
obs_module_text("Decklink Output"));
|
||||
QAction *action = (QAction *)obs_frontend_add_tools_menu_qaction(
|
||||
obs_module_text("Decklink Output"));
|
||||
|
||||
QMainWindow *window = (QMainWindow*)obs_frontend_get_main_window();
|
||||
QMainWindow *window = (QMainWindow *)obs_frontend_get_main_window();
|
||||
|
||||
obs_frontend_push_ui_translation(obs_module_get_string);
|
||||
doUI = new DecklinkOutputUI(window);
|
||||
obs_frontend_pop_ui_translation();
|
||||
|
||||
auto cb = []() {
|
||||
doUI->ShowHideDialog();
|
||||
};
|
||||
auto cb = []() { doUI->ShowHideDialog(); };
|
||||
|
||||
action->connect(action, &QAction::triggered, cb);
|
||||
}
|
||||
|
@ -271,7 +290,8 @@ static void OBSEvent(enum obs_frontend_event event, void *)
|
|||
|
||||
OBSData previewSettings = load_preview_settings();
|
||||
|
||||
if (previewSettings && obs_data_get_bool(previewSettings, "auto_start"))
|
||||
if (previewSettings &&
|
||||
obs_data_get_bool(previewSettings, "auto_start"))
|
||||
preview_output_start();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
static Display* xdisplay = 0;
|
||||
static Display *xdisplay = 0;
|
||||
|
||||
Display *disp()
|
||||
{
|
||||
|
@ -39,31 +39,22 @@ void cleanupDisplay()
|
|||
static bool ewmhIsSupported()
|
||||
{
|
||||
Display *display = disp();
|
||||
Atom netSupportingWmCheck = XInternAtom(display,
|
||||
"_NET_SUPPORTING_WM_CHECK", true);
|
||||
Atom netSupportingWmCheck =
|
||||
XInternAtom(display, "_NET_SUPPORTING_WM_CHECK", true);
|
||||
Atom actualType;
|
||||
int format = 0;
|
||||
unsigned long num = 0, bytes = 0;
|
||||
unsigned char *data = NULL;
|
||||
Window ewmh_window = 0;
|
||||
|
||||
int status = XGetWindowProperty(
|
||||
display,
|
||||
DefaultRootWindow(display),
|
||||
netSupportingWmCheck,
|
||||
0L,
|
||||
1L,
|
||||
false,
|
||||
XA_WINDOW,
|
||||
&actualType,
|
||||
&format,
|
||||
&num,
|
||||
&bytes,
|
||||
&data);
|
||||
int status = XGetWindowProperty(display, DefaultRootWindow(display),
|
||||
netSupportingWmCheck, 0L, 1L, false,
|
||||
XA_WINDOW, &actualType, &format, &num,
|
||||
&bytes, &data);
|
||||
|
||||
if (status == Success) {
|
||||
if (num > 0) {
|
||||
ewmh_window = ((Window*)data)[0];
|
||||
ewmh_window = ((Window *)data)[0];
|
||||
}
|
||||
if (data) {
|
||||
XFree(data);
|
||||
|
@ -72,21 +63,12 @@ static bool ewmhIsSupported()
|
|||
}
|
||||
|
||||
if (ewmh_window) {
|
||||
status = XGetWindowProperty(
|
||||
display,
|
||||
ewmh_window,
|
||||
netSupportingWmCheck,
|
||||
0L,
|
||||
1L,
|
||||
false,
|
||||
XA_WINDOW,
|
||||
&actualType,
|
||||
&format,
|
||||
&num,
|
||||
&bytes,
|
||||
&data);
|
||||
status = XGetWindowProperty(display, ewmh_window,
|
||||
netSupportingWmCheck, 0L, 1L, false,
|
||||
XA_WINDOW, &actualType, &format,
|
||||
&num, &bytes, &data);
|
||||
if (status != Success || num == 0 ||
|
||||
ewmh_window != ((Window*)data)[0]) {
|
||||
ewmh_window != ((Window *)data)[0]) {
|
||||
ewmh_window = 0;
|
||||
}
|
||||
if (status == Success && data) {
|
||||
|
@ -111,24 +93,15 @@ static std::vector<Window> getTopLevelWindows()
|
|||
Atom actualType;
|
||||
int format;
|
||||
unsigned long num, bytes;
|
||||
Window* data = 0;
|
||||
Window *data = 0;
|
||||
|
||||
for (int i = 0; i < ScreenCount(disp()); ++i) {
|
||||
Window rootWin = RootWindow(disp(), i);
|
||||
|
||||
int status = XGetWindowProperty(
|
||||
disp(),
|
||||
rootWin,
|
||||
netClList,
|
||||
0L,
|
||||
~0L,
|
||||
false,
|
||||
AnyPropertyType,
|
||||
&actualType,
|
||||
&format,
|
||||
&num,
|
||||
&bytes,
|
||||
(uint8_t**)&data);
|
||||
int status = XGetWindowProperty(disp(), rootWin, netClList, 0L,
|
||||
~0L, false, AnyPropertyType,
|
||||
&actualType, &format, &num,
|
||||
&bytes, (uint8_t **)&data);
|
||||
|
||||
if (status != Success) {
|
||||
continue;
|
||||
|
@ -147,11 +120,10 @@ static std::string GetWindowTitle(size_t i)
|
|||
{
|
||||
Window w = getTopLevelWindows().at(i);
|
||||
std::string windowTitle;
|
||||
char* name;
|
||||
char *name;
|
||||
|
||||
int status = XFetchName(disp(), w, &name);
|
||||
if (status >= Success && name != nullptr)
|
||||
{
|
||||
if (status >= Success && name != nullptr) {
|
||||
std::string str(name);
|
||||
windowTitle = str;
|
||||
}
|
||||
|
@ -165,7 +137,7 @@ void GetWindowList(vector<string> &windows)
|
|||
{
|
||||
windows.resize(0);
|
||||
|
||||
for (size_t i = 0; i < getTopLevelWindows().size(); ++i){
|
||||
for (size_t i = 0; i < getTopLevelWindows().size(); ++i) {
|
||||
if (GetWindowTitle(i) != "")
|
||||
windows.emplace_back(GetWindowTitle(i));
|
||||
}
|
||||
|
@ -181,24 +153,14 @@ void GetCurrentWindowTitle(string &title)
|
|||
Atom actualType;
|
||||
int format;
|
||||
unsigned long num, bytes;
|
||||
Window* data = 0;
|
||||
char* name;
|
||||
Window *data = 0;
|
||||
char *name;
|
||||
|
||||
Window rootWin = RootWindow(disp(), 0);
|
||||
|
||||
XGetWindowProperty(
|
||||
disp(),
|
||||
rootWin,
|
||||
active,
|
||||
0L,
|
||||
~0L,
|
||||
false,
|
||||
AnyPropertyType,
|
||||
&actualType,
|
||||
&format,
|
||||
&num,
|
||||
&bytes,
|
||||
(uint8_t**)&data);
|
||||
XGetWindowProperty(disp(), rootWin, active, 0L, ~0L, false,
|
||||
AnyPropertyType, &actualType, &format, &num, &bytes,
|
||||
(uint8_t **)&data);
|
||||
|
||||
int status = XFetchName(disp(), data[0], &name);
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ static bool WindowValid(HWND window)
|
|||
return false;
|
||||
|
||||
GetClientRect(window, &rect);
|
||||
styles = GetWindowLongPtr(window, GWL_STYLE);
|
||||
styles = GetWindowLongPtr(window, GWL_STYLE);
|
||||
ex_styles = GetWindowLongPtr(window, GWL_EXSTYLE);
|
||||
|
||||
if (ex_styles & WS_EX_TOOLWINDOW)
|
||||
|
|
|
@ -69,23 +69,19 @@ struct SwitcherData {
|
|||
}
|
||||
}
|
||||
|
||||
inline ~SwitcherData()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
inline ~SwitcherData() { Stop(); }
|
||||
};
|
||||
|
||||
static SwitcherData *switcher = nullptr;
|
||||
|
||||
static inline QString MakeSwitchName(const QString &scene,
|
||||
const QString &window)
|
||||
const QString &window)
|
||||
{
|
||||
return QStringLiteral("[") + scene + QStringLiteral("]: ") + window;
|
||||
}
|
||||
|
||||
SceneSwitcher::SceneSwitcher(QWidget *parent)
|
||||
: QDialog(parent),
|
||||
ui(new Ui_SceneSwitcher)
|
||||
: QDialog(parent), ui(new Ui_SceneSwitcher)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
|
@ -95,7 +91,7 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
|
|||
|
||||
switcher->Prune();
|
||||
|
||||
BPtr<char*> scenes = obs_frontend_get_scene_names();
|
||||
BPtr<char *> scenes = obs_frontend_get_scene_names();
|
||||
char **temp = scenes;
|
||||
while (*temp) {
|
||||
const char *name = *temp;
|
||||
|
@ -110,7 +106,7 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
|
|||
ui->noMatchDontSwitch->setChecked(true);
|
||||
|
||||
ui->noMatchSwitchScene->setCurrentText(
|
||||
GetWeakSourceName(switcher->nonMatchingScene).c_str());
|
||||
GetWeakSourceName(switcher->nonMatchingScene).c_str());
|
||||
ui->checkInterval->setValue(switcher->interval);
|
||||
|
||||
vector<string> windows;
|
||||
|
@ -121,11 +117,10 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
|
|||
|
||||
for (auto &s : switcher->switches) {
|
||||
string sceneName = GetWeakSourceName(s.scene);
|
||||
QString text = MakeSwitchName(sceneName.c_str(),
|
||||
s.window.c_str());
|
||||
QString text =
|
||||
MakeSwitchName(sceneName.c_str(), s.window.c_str());
|
||||
|
||||
QListWidgetItem *item = new QListWidgetItem(text,
|
||||
ui->switches);
|
||||
QListWidgetItem *item = new QListWidgetItem(text, ui->switches);
|
||||
item->setData(Qt::UserRole, s.window.c_str());
|
||||
}
|
||||
|
||||
|
@ -137,7 +132,7 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
|
|||
loading = false;
|
||||
}
|
||||
|
||||
void SceneSwitcher::closeEvent(QCloseEvent*)
|
||||
void SceneSwitcher::closeEvent(QCloseEvent *)
|
||||
{
|
||||
obs_frontend_save();
|
||||
}
|
||||
|
@ -149,8 +144,7 @@ int SceneSwitcher::FindByData(const QString &window)
|
|||
|
||||
for (int i = 0; i < count; i++) {
|
||||
QListWidgetItem *item = ui->switches->item(i);
|
||||
QString itemWindow =
|
||||
item->data(Qt::UserRole).toString();
|
||||
QString itemWindow = item->data(Qt::UserRole).toString();
|
||||
|
||||
if (itemWindow == window) {
|
||||
idx = i;
|
||||
|
@ -206,16 +200,16 @@ void SceneSwitcher::on_add_clicked()
|
|||
if (idx == -1) {
|
||||
try {
|
||||
lock_guard<mutex> lock(switcher->m);
|
||||
switcher->switches.emplace_back(source,
|
||||
windowName.toUtf8().constData());
|
||||
switcher->switches.emplace_back(
|
||||
source, windowName.toUtf8().constData());
|
||||
|
||||
QListWidgetItem *item = new QListWidgetItem(text,
|
||||
ui->switches);
|
||||
QListWidgetItem *item =
|
||||
new QListWidgetItem(text, ui->switches);
|
||||
item->setData(Qt::UserRole, v);
|
||||
} catch (const regex_error &) {
|
||||
QMessageBox::warning(this,
|
||||
obs_module_text("InvalidRegex.Title"),
|
||||
obs_module_text("InvalidRegex.Text"));
|
||||
QMessageBox::warning(
|
||||
this, obs_module_text("InvalidRegex.Title"),
|
||||
obs_module_text("InvalidRegex.Text"));
|
||||
}
|
||||
} else {
|
||||
QListWidgetItem *item = ui->switches->item(idx);
|
||||
|
@ -274,8 +268,7 @@ void SceneSwitcher::on_startAtLaunch_toggled(bool value)
|
|||
|
||||
void SceneSwitcher::UpdateNonMatchingScene(const QString &name)
|
||||
{
|
||||
obs_source_t *scene = obs_get_source_by_name(
|
||||
name.toUtf8().constData());
|
||||
obs_source_t *scene = obs_get_source_by_name(name.toUtf8().constData());
|
||||
obs_weak_source_t *ws = obs_source_get_weak_source(scene);
|
||||
|
||||
switcher->nonMatchingScene = ws;
|
||||
|
@ -303,8 +296,7 @@ void SceneSwitcher::on_noMatchSwitch_clicked()
|
|||
UpdateNonMatchingScene(ui->noMatchSwitchScene->currentText());
|
||||
}
|
||||
|
||||
void SceneSwitcher::on_noMatchSwitchScene_currentTextChanged(
|
||||
const QString &text)
|
||||
void SceneSwitcher::on_noMatchSwitchScene_currentTextChanged(const QString &text)
|
||||
{
|
||||
if (loading)
|
||||
return;
|
||||
|
@ -357,13 +349,13 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
|
|||
for (SceneSwitch &s : switcher->switches) {
|
||||
obs_data_t *array_obj = obs_data_create();
|
||||
|
||||
obs_source_t *source = obs_weak_source_get_source(
|
||||
s.scene);
|
||||
obs_source_t *source =
|
||||
obs_weak_source_get_source(s.scene);
|
||||
if (source) {
|
||||
const char *n = obs_source_get_name(source);
|
||||
obs_data_set_string(array_obj, "scene", n);
|
||||
obs_data_set_string(array_obj, "window_title",
|
||||
s.window.c_str());
|
||||
s.window.c_str());
|
||||
obs_data_array_push_back(array, array_obj);
|
||||
obs_source_release(source);
|
||||
}
|
||||
|
@ -376,9 +368,9 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
|
|||
|
||||
obs_data_set_int(obj, "interval", switcher->interval);
|
||||
obs_data_set_string(obj, "non_matching_scene",
|
||||
nonMatchingSceneName.c_str());
|
||||
nonMatchingSceneName.c_str());
|
||||
obs_data_set_bool(obj, "switch_if_not_matching",
|
||||
switcher->switchIfNotMatching);
|
||||
switcher->switchIfNotMatching);
|
||||
obs_data_set_bool(obj, "active", switcher->th.joinable());
|
||||
obs_data_set_array(obj, "switches", array);
|
||||
|
||||
|
@ -389,8 +381,8 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
|
|||
} else {
|
||||
switcher->m.lock();
|
||||
|
||||
obs_data_t *obj = obs_data_get_obj(save_data,
|
||||
"auto-scene-switcher");
|
||||
obs_data_t *obj =
|
||||
obs_data_get_obj(save_data, "auto-scene-switcher");
|
||||
obs_data_array_t *array = obs_data_get_array(obj, "switches");
|
||||
size_t count = obs_data_array_count(array);
|
||||
|
||||
|
@ -420,8 +412,7 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
|
|||
obs_data_get_string(array_obj, "window_title");
|
||||
|
||||
switcher->switches.emplace_back(
|
||||
GetWeakSourceByName(scene),
|
||||
window);
|
||||
GetWeakSourceByName(scene), window);
|
||||
|
||||
obs_data_release(array_obj);
|
||||
}
|
||||
|
@ -476,18 +467,18 @@ void SwitcherData::Thread()
|
|||
for (SceneSwitch &s : switches) {
|
||||
try {
|
||||
bool matches = regex_match(
|
||||
title, s.re);
|
||||
title, s.re);
|
||||
if (matches) {
|
||||
match = true;
|
||||
scene = s.scene;
|
||||
break;
|
||||
}
|
||||
} catch (const regex_error &) {}
|
||||
} catch (const regex_error &) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!match && switchIfNotMatching &&
|
||||
nonMatchingScene) {
|
||||
if (!match && switchIfNotMatching && nonMatchingScene) {
|
||||
match = true;
|
||||
scene = nonMatchingScene;
|
||||
}
|
||||
|
@ -513,7 +504,7 @@ void SwitcherData::Thread()
|
|||
void SwitcherData::Start()
|
||||
{
|
||||
if (!switcher->th.joinable())
|
||||
switcher->th = thread([] () {switcher->Thread();});
|
||||
switcher->th = thread([]() { switcher->Thread(); });
|
||||
}
|
||||
|
||||
void SwitcherData::Stop()
|
||||
|
@ -542,17 +533,16 @@ static void OBSEvent(enum obs_frontend_event event, void *)
|
|||
|
||||
extern "C" void InitSceneSwitcher()
|
||||
{
|
||||
QAction *action = (QAction*)obs_frontend_add_tools_menu_qaction(
|
||||
obs_module_text("SceneSwitcher"));
|
||||
QAction *action = (QAction *)obs_frontend_add_tools_menu_qaction(
|
||||
obs_module_text("SceneSwitcher"));
|
||||
|
||||
switcher = new SwitcherData;
|
||||
|
||||
auto cb = [] ()
|
||||
{
|
||||
auto cb = []() {
|
||||
obs_frontend_push_ui_translation(obs_module_get_string);
|
||||
|
||||
QMainWindow *window =
|
||||
(QMainWindow*)obs_frontend_get_main_window();
|
||||
(QMainWindow *)obs_frontend_get_main_window();
|
||||
|
||||
SceneSwitcher ss(window);
|
||||
ss.exec();
|
||||
|
|
|
@ -1,33 +1,24 @@
|
|||
#include "captions-handler.hpp"
|
||||
|
||||
captions_handler::captions_handler(
|
||||
captions_cb callback,
|
||||
enum audio_format format,
|
||||
uint32_t sample_rate)
|
||||
captions_handler::captions_handler(captions_cb callback,
|
||||
enum audio_format format,
|
||||
uint32_t sample_rate)
|
||||
: cb(callback)
|
||||
{
|
||||
if (!reset_resampler(format, sample_rate))
|
||||
throw CAPTIONS_ERROR_GENERIC_FAIL;
|
||||
}
|
||||
|
||||
bool captions_handler::reset_resampler(
|
||||
enum audio_format format,
|
||||
uint32_t sample_rate)
|
||||
bool captions_handler::reset_resampler(enum audio_format format,
|
||||
uint32_t sample_rate)
|
||||
try {
|
||||
obs_audio_info ai;
|
||||
if (!obs_get_audio_info(&ai))
|
||||
throw std::string("Failed to get OBS audio info");
|
||||
|
||||
resample_info src = {
|
||||
ai.samples_per_sec,
|
||||
AUDIO_FORMAT_FLOAT_PLANAR,
|
||||
ai.speakers
|
||||
};
|
||||
resample_info dst = {
|
||||
sample_rate,
|
||||
format,
|
||||
SPEAKERS_MONO
|
||||
};
|
||||
resample_info src = {ai.samples_per_sec, AUDIO_FORMAT_FLOAT_PLANAR,
|
||||
ai.speakers};
|
||||
resample_info dst = {sample_rate, format, SPEAKERS_MONO};
|
||||
|
||||
if (!resampler.reset(dst, src))
|
||||
throw std::string("Failed to create audio resampler");
|
||||
|
@ -46,9 +37,9 @@ void captions_handler::push_audio(const audio_data *audio)
|
|||
uint64_t ts_offset;
|
||||
bool success;
|
||||
|
||||
success = audio_resampler_resample(resampler,
|
||||
out, &frames, &ts_offset,
|
||||
(const uint8_t *const *)audio->data, audio->frames);
|
||||
success = audio_resampler_resample(resampler, out, &frames, &ts_offset,
|
||||
(const uint8_t *const *)audio->data,
|
||||
audio->frames);
|
||||
if (success)
|
||||
pcm_data(out[0], frames);
|
||||
}
|
||||
|
|
|
@ -9,10 +9,7 @@ class resampler_obj {
|
|||
audio_resampler_t *resampler = nullptr;
|
||||
|
||||
public:
|
||||
inline ~resampler_obj()
|
||||
{
|
||||
audio_resampler_destroy(resampler);
|
||||
}
|
||||
inline ~resampler_obj() { audio_resampler_destroy(resampler); }
|
||||
|
||||
inline bool reset(const resample_info &dst, const resample_info &src)
|
||||
{
|
||||
|
@ -21,15 +18,15 @@ public:
|
|||
return !!resampler;
|
||||
}
|
||||
|
||||
inline operator audio_resampler_t*() {return resampler;}
|
||||
inline operator audio_resampler_t *() { return resampler; }
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
typedef std::function<void (const std::string &)> captions_cb;
|
||||
typedef std::function<void(const std::string &)> captions_cb;
|
||||
|
||||
#define captions_error(s) std::string(obs_module_text("Captions.Error." ## s))
|
||||
#define CAPTIONS_ERROR_GENERIC_FAIL captions_error("GenericFail")
|
||||
#define captions_error(s) std::string(obs_module_text("Captions.Error."##s))
|
||||
#define CAPTIONS_ERROR_GENERIC_FAIL captions_error("GenericFail")
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
|
@ -38,22 +35,17 @@ class captions_handler {
|
|||
resampler_obj resampler;
|
||||
|
||||
protected:
|
||||
inline void callback(const std::string &text)
|
||||
{
|
||||
cb(text);
|
||||
}
|
||||
inline void callback(const std::string &text) { cb(text); }
|
||||
|
||||
virtual void pcm_data(const void *data, size_t frames)=0;
|
||||
virtual void pcm_data(const void *data, size_t frames) = 0;
|
||||
|
||||
/* always resamples to 1 channel */
|
||||
bool reset_resampler(enum audio_format format, uint32_t sample_rate);
|
||||
|
||||
public:
|
||||
/* throw std::string for errors shown to users */
|
||||
captions_handler(
|
||||
captions_cb callback,
|
||||
enum audio_format format,
|
||||
uint32_t sample_rate);
|
||||
captions_handler(captions_cb callback, enum audio_format format,
|
||||
uint32_t sample_rate);
|
||||
virtual ~captions_handler() {}
|
||||
|
||||
void push_audio(const audio_data *audio);
|
||||
|
@ -62,6 +54,6 @@ public:
|
|||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
struct captions_handler_info {
|
||||
std::string (*name)(void);
|
||||
std::string (*name)(void);
|
||||
captions_handler *(*create)(captions_cb cb, const std::string &lang);
|
||||
};
|
||||
|
|
|
@ -8,16 +8,17 @@
|
|||
using namespace std;
|
||||
|
||||
#if 0
|
||||
#define debugfunc(format, ...) blog(LOG_DEBUG, "[Captions] %s(" format ")", \
|
||||
__FUNCTION__, ##__VA_ARGS__)
|
||||
#define debugfunc(format, ...) \
|
||||
blog(LOG_DEBUG, "[Captions] %s(" format ")", __FUNCTION__, \
|
||||
##__VA_ARGS__)
|
||||
#else
|
||||
#define debugfunc(format, ...)
|
||||
#endif
|
||||
|
||||
CaptionStream::CaptionStream(DWORD samplerate_, mssapi_captions *handler_) :
|
||||
handler(handler_),
|
||||
samplerate(samplerate_),
|
||||
event(CreateEvent(nullptr, false, false, nullptr))
|
||||
CaptionStream::CaptionStream(DWORD samplerate_, mssapi_captions *handler_)
|
||||
: handler(handler_),
|
||||
samplerate(samplerate_),
|
||||
event(CreateEvent(nullptr, false, false, nullptr))
|
||||
{
|
||||
buf_info.ulMsMinNotification = 50;
|
||||
buf_info.ulMsBufferSize = 500;
|
||||
|
@ -66,15 +67,15 @@ STDMETHODIMP CaptionStream::QueryInterface(REFIID riid, void **ppv)
|
|||
|
||||
} else if (riid == IID_IStream) {
|
||||
AddRef();
|
||||
*ppv = (IStream*)this;
|
||||
*ppv = (IStream *)this;
|
||||
|
||||
} else if (riid == IID_ISpStreamFormat) {
|
||||
AddRef();
|
||||
*ppv = (ISpStreamFormat*)this;
|
||||
*ppv = (ISpStreamFormat *)this;
|
||||
|
||||
} else if (riid == IID_ISpAudio) {
|
||||
AddRef();
|
||||
*ppv = (ISpAudio*)this;
|
||||
*ppv = (ISpAudio *)this;
|
||||
|
||||
} else {
|
||||
*ppv = nullptr;
|
||||
|
@ -134,8 +135,7 @@ STDMETHODIMP CaptionStream::Read(void *data, ULONG bytes, ULONG *read_bytes)
|
|||
return hr;
|
||||
}
|
||||
|
||||
STDMETHODIMP CaptionStream::Write(const void *, ULONG bytes,
|
||||
ULONG*)
|
||||
STDMETHODIMP CaptionStream::Write(const void *, ULONG bytes, ULONG *)
|
||||
{
|
||||
debugfunc("data, %lu, written_bytes", bytes);
|
||||
UNUSED_PARAMETER(bytes);
|
||||
|
@ -146,7 +146,7 @@ STDMETHODIMP CaptionStream::Write(const void *, ULONG bytes,
|
|||
// IStream methods
|
||||
|
||||
STDMETHODIMP CaptionStream::Seek(LARGE_INTEGER move, DWORD origin,
|
||||
ULARGE_INTEGER *new_pos)
|
||||
ULARGE_INTEGER *new_pos)
|
||||
{
|
||||
debugfunc("%lld, %lx, new_pos", move, origin);
|
||||
UNUSED_PARAMETER(move);
|
||||
|
@ -170,8 +170,8 @@ STDMETHODIMP CaptionStream::SetSize(ULARGE_INTEGER new_size)
|
|||
}
|
||||
|
||||
STDMETHODIMP CaptionStream::CopyTo(IStream *stream, ULARGE_INTEGER bytes,
|
||||
ULARGE_INTEGER *read_bytes,
|
||||
ULARGE_INTEGER *written_bytes)
|
||||
ULARGE_INTEGER *read_bytes,
|
||||
ULARGE_INTEGER *written_bytes)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
|
@ -213,7 +213,7 @@ STDMETHODIMP CaptionStream::Revert(void)
|
|||
}
|
||||
|
||||
STDMETHODIMP CaptionStream::LockRegion(ULARGE_INTEGER offset,
|
||||
ULARGE_INTEGER size, DWORD type)
|
||||
ULARGE_INTEGER size, DWORD type)
|
||||
{
|
||||
debugfunc("%llu, %llu, %ld", offset, size, type);
|
||||
UNUSED_PARAMETER(offset);
|
||||
|
@ -224,7 +224,7 @@ STDMETHODIMP CaptionStream::LockRegion(ULARGE_INTEGER offset,
|
|||
}
|
||||
|
||||
STDMETHODIMP CaptionStream::UnlockRegion(ULARGE_INTEGER offset,
|
||||
ULARGE_INTEGER size, DWORD type)
|
||||
ULARGE_INTEGER size, DWORD type)
|
||||
{
|
||||
debugfunc("%llu, %llu, %ld", offset, size, type);
|
||||
UNUSED_PARAMETER(offset);
|
||||
|
@ -250,7 +250,7 @@ STDMETHODIMP CaptionStream::Stat(STATSTG *stg, DWORD flag)
|
|||
|
||||
if (flag == STATFLAG_DEFAULT) {
|
||||
size_t byte_size = (wcslen(stat_name) + 1) * sizeof(wchar_t);
|
||||
stg->pwcsName = (wchar_t*)CoTaskMemAlloc(byte_size);
|
||||
stg->pwcsName = (wchar_t *)CoTaskMemAlloc(byte_size);
|
||||
memcpy(stg->pwcsName, stat_name, byte_size);
|
||||
}
|
||||
|
||||
|
@ -267,7 +267,7 @@ STDMETHODIMP CaptionStream::Clone(IStream **stream)
|
|||
// ISpStreamFormat methods
|
||||
|
||||
STDMETHODIMP CaptionStream::GetFormat(GUID *guid,
|
||||
WAVEFORMATEX **co_mem_wfex_out)
|
||||
WAVEFORMATEX **co_mem_wfex_out)
|
||||
{
|
||||
debugfunc("guid, co_mem_wfex_out");
|
||||
|
||||
|
@ -282,7 +282,7 @@ STDMETHODIMP CaptionStream::GetFormat(GUID *guid,
|
|||
void *wfex = CoTaskMemAlloc(sizeof(format));
|
||||
memcpy(wfex, &format, sizeof(format));
|
||||
|
||||
*co_mem_wfex_out = (WAVEFORMATEX*)wfex;
|
||||
*co_mem_wfex_out = (WAVEFORMATEX *)wfex;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -296,7 +296,7 @@ STDMETHODIMP CaptionStream::SetState(SPAUDIOSTATE state_, ULONGLONG)
|
|||
}
|
||||
|
||||
STDMETHODIMP CaptionStream::SetFormat(REFGUID guid_ref,
|
||||
const WAVEFORMATEX *wfex)
|
||||
const WAVEFORMATEX *wfex)
|
||||
{
|
||||
debugfunc("guid, wfex");
|
||||
if (!wfex)
|
||||
|
@ -306,7 +306,7 @@ STDMETHODIMP CaptionStream::SetFormat(REFGUID guid_ref,
|
|||
lock_guard<mutex> lock(m);
|
||||
memcpy(&format, wfex, sizeof(format));
|
||||
if (!handler->reset_resampler(AUDIO_FORMAT_16BIT,
|
||||
wfex->nSamplesPerSec))
|
||||
wfex->nSamplesPerSec))
|
||||
return E_FAIL;
|
||||
|
||||
/* 50 msec */
|
||||
|
@ -354,7 +354,7 @@ STDMETHODIMP CaptionStream::GetBufferInfo(SPAUDIOBUFFERINFO *buf_info_)
|
|||
}
|
||||
|
||||
STDMETHODIMP CaptionStream::GetDefaultFormat(GUID *format,
|
||||
WAVEFORMATEX **co_mem_wfex_out)
|
||||
WAVEFORMATEX **co_mem_wfex_out)
|
||||
{
|
||||
debugfunc("format, co_mem_wfex_out");
|
||||
|
||||
|
@ -365,7 +365,7 @@ STDMETHODIMP CaptionStream::GetDefaultFormat(GUID *format,
|
|||
memcpy(wfex, &format, sizeof(format));
|
||||
|
||||
*format = SPDFID_WaveFormatEx;
|
||||
*co_mem_wfex_out = (WAVEFORMATEX*)wfex;
|
||||
*co_mem_wfex_out = (WAVEFORMATEX *)wfex;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,10 +13,11 @@
|
|||
|
||||
class CircleBuf {
|
||||
circlebuf buf = {};
|
||||
|
||||
public:
|
||||
inline ~CircleBuf() {circlebuf_free(&buf);}
|
||||
inline operator circlebuf*() {return &buf;}
|
||||
inline circlebuf *operator->() {return &buf;}
|
||||
inline ~CircleBuf() { circlebuf_free(&buf); }
|
||||
inline operator circlebuf *() { return &buf; }
|
||||
inline circlebuf *operator->() { return &buf; }
|
||||
};
|
||||
|
||||
class mssapi_captions;
|
||||
|
@ -54,38 +55,38 @@ public:
|
|||
|
||||
// ISequentialStream methods
|
||||
STDMETHODIMP Read(void *data, ULONG bytes, ULONG *read_bytes) override;
|
||||
STDMETHODIMP Write(const void *data, ULONG bytes, ULONG *written_bytes)
|
||||
override;
|
||||
STDMETHODIMP Write(const void *data, ULONG bytes,
|
||||
ULONG *written_bytes) override;
|
||||
|
||||
// IStream methods
|
||||
STDMETHODIMP Seek(LARGE_INTEGER move, DWORD origin,
|
||||
ULARGE_INTEGER *new_pos) override;
|
||||
ULARGE_INTEGER *new_pos) override;
|
||||
STDMETHODIMP SetSize(ULARGE_INTEGER new_size) override;
|
||||
STDMETHODIMP CopyTo(IStream *stream, ULARGE_INTEGER bytes,
|
||||
ULARGE_INTEGER *read_bytes,
|
||||
ULARGE_INTEGER *written_bytes) override;
|
||||
ULARGE_INTEGER *read_bytes,
|
||||
ULARGE_INTEGER *written_bytes) override;
|
||||
STDMETHODIMP Commit(DWORD commit_flags) override;
|
||||
STDMETHODIMP Revert(void) override;
|
||||
STDMETHODIMP LockRegion(ULARGE_INTEGER offset, ULARGE_INTEGER size,
|
||||
DWORD type) override;
|
||||
DWORD type) override;
|
||||
STDMETHODIMP UnlockRegion(ULARGE_INTEGER offset, ULARGE_INTEGER size,
|
||||
DWORD type) override;
|
||||
DWORD type) override;
|
||||
STDMETHODIMP Stat(STATSTG *stg, DWORD flags) override;
|
||||
STDMETHODIMP Clone(IStream **stream) override;
|
||||
|
||||
// ISpStreamFormat methods
|
||||
STDMETHODIMP GetFormat(GUID *guid, WAVEFORMATEX **co_mem_wfex_out)
|
||||
override;
|
||||
STDMETHODIMP GetFormat(GUID *guid,
|
||||
WAVEFORMATEX **co_mem_wfex_out) override;
|
||||
|
||||
// ISpAudio methods
|
||||
STDMETHODIMP SetState(SPAUDIOSTATE state, ULONGLONG reserved) override;
|
||||
STDMETHODIMP SetFormat(REFGUID guid_ref, const WAVEFORMATEX *wfex)
|
||||
override;
|
||||
STDMETHODIMP SetFormat(REFGUID guid_ref,
|
||||
const WAVEFORMATEX *wfex) override;
|
||||
STDMETHODIMP GetStatus(SPAUDIOSTATUS *status) override;
|
||||
STDMETHODIMP SetBufferInfo(const SPAUDIOBUFFERINFO *buf_info) override;
|
||||
STDMETHODIMP GetBufferInfo(SPAUDIOBUFFERINFO *buf_info) override;
|
||||
STDMETHODIMP GetDefaultFormat(GUID *format,
|
||||
WAVEFORMATEX **co_mem_wfex_out) override;
|
||||
WAVEFORMATEX **co_mem_wfex_out) override;
|
||||
STDMETHODIMP_(HANDLE) EventHandle(void) override;
|
||||
STDMETHODIMP GetVolumeLevel(ULONG *level) override;
|
||||
STDMETHODIMP SetVolumeLevel(ULONG level) override;
|
||||
|
|
|
@ -1,16 +1,13 @@
|
|||
#include "captions-mssapi.hpp"
|
||||
|
||||
#define do_log(type, format, ...) blog(type, "[Captions] " format, \
|
||||
##__VA_ARGS__)
|
||||
#define do_log(type, format, ...) \
|
||||
blog(type, "[Captions] " format, ##__VA_ARGS__)
|
||||
|
||||
#define error(format, ...) do_log(LOG_ERROR, format, ##__VA_ARGS__)
|
||||
#define debug(format, ...) do_log(LOG_DEBUG, format, ##__VA_ARGS__)
|
||||
|
||||
mssapi_captions::mssapi_captions(
|
||||
captions_cb callback,
|
||||
const std::string &lang) try
|
||||
: captions_handler(callback, AUDIO_FORMAT_16BIT, 16000)
|
||||
{
|
||||
mssapi_captions::mssapi_captions(captions_cb callback, const std::string &lang)
|
||||
try : captions_handler(callback, AUDIO_FORMAT_16BIT, 16000) {
|
||||
HRESULT hr;
|
||||
|
||||
std::wstring wlang;
|
||||
|
@ -33,7 +30,7 @@ mssapi_captions::mssapi_captions(
|
|||
throw HRError("SpFindBestToken failed", hr);
|
||||
|
||||
hr = CoCreateInstance(CLSID_SpInprocRecognizer, nullptr, CLSCTX_ALL,
|
||||
__uuidof(ISpRecognizer), (void**)&recognizer);
|
||||
__uuidof(ISpRecognizer), (void **)&recognizer);
|
||||
if (FAILED(hr))
|
||||
throw HRError("CoCreateInstance for recognizer failed", hr);
|
||||
|
||||
|
@ -50,7 +47,7 @@ mssapi_captions::mssapi_captions(
|
|||
throw HRError("CreateRecoContext failed", hr);
|
||||
|
||||
ULONGLONG interest = SPFEI(SPEI_RECOGNITION) |
|
||||
SPFEI(SPEI_END_SR_STREAM);
|
||||
SPFEI(SPEI_END_SR_STREAM);
|
||||
hr = context->SetInterest(interest, interest);
|
||||
if (FAILED(hr))
|
||||
throw HRError("SetInterest failed", hr);
|
||||
|
@ -80,7 +77,7 @@ mssapi_captions::mssapi_captions(
|
|||
throw HRError("LoadDictation failed", hr);
|
||||
|
||||
try {
|
||||
t = std::thread([this] () {main_thread();});
|
||||
t = std::thread([this]() { main_thread(); });
|
||||
} catch (...) {
|
||||
throw "Failed to create thread";
|
||||
}
|
||||
|
@ -133,8 +130,8 @@ try {
|
|||
ISpRecoResult *result = event.RecoResult();
|
||||
|
||||
CoTaskMemPtr<wchar_t> text;
|
||||
hr = result->GetText((ULONG)-1, (ULONG)-1,
|
||||
true, &text, nullptr);
|
||||
hr = result->GetText((ULONG)-1, (ULONG)-1, true,
|
||||
&text, nullptr);
|
||||
if (FAILED(hr))
|
||||
continue;
|
||||
|
||||
|
@ -168,12 +165,7 @@ void mssapi_captions::pcm_data(const void *data, size_t frames)
|
|||
}
|
||||
|
||||
captions_handler_info mssapi_info = {
|
||||
[] () -> std::string
|
||||
{
|
||||
return "Microsoft Speech-to-Text";
|
||||
},
|
||||
[] (captions_cb cb, const std::string &lang) -> captions_handler *
|
||||
{
|
||||
[]() -> std::string { return "Microsoft Speech-to-Text"; },
|
||||
[](captions_cb cb, const std::string &lang) -> captions_handler * {
|
||||
return new mssapi_captions(cb, lang);
|
||||
}
|
||||
};
|
||||
}};
|
||||
|
|
|
@ -27,16 +27,16 @@
|
|||
class mssapi_captions : public captions_handler {
|
||||
friend class CaptionStream;
|
||||
|
||||
ComPtr<CaptionStream> audio;
|
||||
ComPtr<CaptionStream> audio;
|
||||
ComPtr<ISpObjectToken> token;
|
||||
ComPtr<ISpRecoGrammar> grammar;
|
||||
ComPtr<ISpRecognizer> recognizer;
|
||||
ComPtr<ISpRecognizer> recognizer;
|
||||
ComPtr<ISpRecoContext> context;
|
||||
|
||||
HANDLE notify;
|
||||
WinHandle stop;
|
||||
std::thread t;
|
||||
bool started = false;
|
||||
HANDLE notify;
|
||||
WinHandle stop;
|
||||
std::thread t;
|
||||
bool started = false;
|
||||
|
||||
void main_thread();
|
||||
|
||||
|
|
|
@ -31,8 +31,8 @@
|
|||
|
||||
#include "captions-mssapi.hpp"
|
||||
|
||||
#define do_log(type, format, ...) blog(type, "[Captions] " format, \
|
||||
##__VA_ARGS__)
|
||||
#define do_log(type, format, ...) \
|
||||
blog(type, "[Captions] " format, ##__VA_ARGS__)
|
||||
|
||||
#define warn(format, ...) do_log(LOG_WARNING, format, ##__VA_ARGS__)
|
||||
#define debug(format, ...) do_log(LOG_DEBUG, format, ##__VA_ARGS__)
|
||||
|
@ -48,10 +48,10 @@ struct obs_captions {
|
|||
unique_ptr<captions_handler> handler;
|
||||
LANGID lang_id = GetUserDefaultUILanguage();
|
||||
|
||||
std::unordered_map<std::string, captions_handler_info&> handler_types;
|
||||
std::unordered_map<std::string, captions_handler_info &> handler_types;
|
||||
|
||||
inline void register_handler(const char *id,
|
||||
captions_handler_info &info)
|
||||
captions_handler_info &info)
|
||||
{
|
||||
handler_types.emplace(id, info);
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ struct obs_captions {
|
|||
void stop();
|
||||
|
||||
obs_captions();
|
||||
inline ~obs_captions() {stop();}
|
||||
inline ~obs_captions() { stop(); }
|
||||
};
|
||||
|
||||
static obs_captions *captions = nullptr;
|
||||
|
@ -74,9 +74,9 @@ struct locale_info {
|
|||
inline locale_info() {}
|
||||
inline locale_info(const locale_info &) = delete;
|
||||
inline locale_info(locale_info &&li)
|
||||
: name(std::move(li.name)),
|
||||
id(li.id)
|
||||
{}
|
||||
: name(std::move(li.name)), id(li.id)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
static void get_valid_locale_names(vector<locale_info> &names);
|
||||
|
@ -84,16 +84,14 @@ static bool valid_lang(LANGID id);
|
|||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
CaptionsDialog::CaptionsDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui_CaptionsDialog)
|
||||
CaptionsDialog::CaptionsDialog(QWidget *parent)
|
||||
: QDialog(parent), ui(new Ui_CaptionsDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
|
||||
auto cb = [this] (obs_source_t *source)
|
||||
{
|
||||
auto cb = [this](obs_source_t *source) {
|
||||
uint32_t caps = obs_source_get_output_flags(source);
|
||||
QString name = obs_source_get_name(source);
|
||||
|
||||
|
@ -111,8 +109,11 @@ CaptionsDialog::CaptionsDialog(QWidget *parent) :
|
|||
ui->source->blockSignals(true);
|
||||
ui->source->addItem(QStringLiteral(""));
|
||||
ui->source->setCurrentIndex(0);
|
||||
obs_enum_sources([] (void *data, obs_source_t *source) {
|
||||
return (*static_cast<cb_t*>(data))(source);}, &cb);
|
||||
obs_enum_sources(
|
||||
[](void *data, obs_source_t *source) {
|
||||
return (*static_cast<cb_t *>(data))(source);
|
||||
},
|
||||
&cb);
|
||||
ui->source->blockSignals(false);
|
||||
|
||||
for (auto &ht : captions->handler_types) {
|
||||
|
@ -232,8 +233,8 @@ static void caption_text(const std::string &text)
|
|||
}
|
||||
}
|
||||
|
||||
static void audio_capture(void*, obs_source_t*,
|
||||
const struct audio_data *audio, bool)
|
||||
static void audio_capture(void *, obs_source_t *,
|
||||
const struct audio_data *audio, bool)
|
||||
{
|
||||
captions->handler->push_audio(audio);
|
||||
}
|
||||
|
@ -245,14 +246,13 @@ void obs_captions::start()
|
|||
|
||||
auto pair = handler_types.find(handler_id);
|
||||
if (pair == handler_types.end()) {
|
||||
warn("Failed to find handler '%s'",
|
||||
handler_id.c_str());
|
||||
warn("Failed to find handler '%s'", handler_id.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!LCIDToLocaleName(lang_id, wname, 256, 0)) {
|
||||
warn("Failed to get locale name: %d",
|
||||
(int)GetLastError());
|
||||
(int)GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -271,24 +271,24 @@ void obs_captions::start()
|
|||
}
|
||||
|
||||
try {
|
||||
captions_handler *h = pair->second.create(caption_text,
|
||||
lang_name);
|
||||
captions_handler *h =
|
||||
pair->second.create(caption_text, lang_name);
|
||||
handler.reset(h);
|
||||
|
||||
OBSSource s = OBSGetStrongRef(source);
|
||||
obs_source_add_audio_capture_callback(s,
|
||||
audio_capture, nullptr);
|
||||
obs_source_add_audio_capture_callback(s, audio_capture,
|
||||
nullptr);
|
||||
|
||||
} catch (std::string text) {
|
||||
QWidget *window =
|
||||
(QWidget*)obs_frontend_get_main_window();
|
||||
(QWidget *)obs_frontend_get_main_window();
|
||||
|
||||
warn("Failed to create handler: %s", text.c_str());
|
||||
|
||||
QMessageBox::warning(window,
|
||||
QMessageBox::warning(
|
||||
window,
|
||||
obs_module_text("Captions.Error.GenericFail"),
|
||||
text.c_str());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -297,8 +297,8 @@ void obs_captions::stop()
|
|||
{
|
||||
OBSSource s = OBSGetStrongRef(source);
|
||||
if (s)
|
||||
obs_source_remove_audio_capture_callback(s,
|
||||
audio_capture, nullptr);
|
||||
obs_source_remove_audio_capture_callback(s, audio_capture,
|
||||
nullptr);
|
||||
handler.reset();
|
||||
}
|
||||
|
||||
|
@ -332,42 +332,18 @@ static void get_valid_locale_names(vector<locale_info> &locales)
|
|||
char locale_name[256];
|
||||
|
||||
static const LANGID default_locales[] = {
|
||||
0x0409,
|
||||
0x0401,
|
||||
0x0402,
|
||||
0x0403,
|
||||
0x0404,
|
||||
0x0405,
|
||||
0x0406,
|
||||
0x0407,
|
||||
0x0408,
|
||||
0x040a,
|
||||
0x040b,
|
||||
0x040c,
|
||||
0x040d,
|
||||
0x040e,
|
||||
0x040f,
|
||||
0x0410,
|
||||
0x0411,
|
||||
0x0412,
|
||||
0x0413,
|
||||
0x0414,
|
||||
0x0415,
|
||||
0x0416,
|
||||
0x0417,
|
||||
0x0418,
|
||||
0x0419,
|
||||
0x041a,
|
||||
0
|
||||
};
|
||||
0x0409, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406,
|
||||
0x0407, 0x0408, 0x040a, 0x040b, 0x040c, 0x040d, 0x040e,
|
||||
0x040f, 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415,
|
||||
0x0416, 0x0417, 0x0418, 0x0419, 0x041a, 0};
|
||||
|
||||
/* ---------------------------------- */
|
||||
|
||||
LANGID def_id = GetUserDefaultUILanguage();
|
||||
LANGID id = def_id;
|
||||
if (valid_lang(id) && get_locale_name(id, locale_name)) {
|
||||
dstr_copy(cur.name, obs_module_text(
|
||||
"Captions.CurrentSystemLanguage"));
|
||||
dstr_copy(cur.name,
|
||||
obs_module_text("Captions.CurrentSystemLanguage"));
|
||||
dstr_replace(cur.name, "%1", locale_name);
|
||||
cur.id = id;
|
||||
|
||||
|
@ -381,8 +357,7 @@ static void get_valid_locale_names(vector<locale_info> &locales)
|
|||
while (*locale) {
|
||||
id = *locale;
|
||||
|
||||
if (id != def_id &&
|
||||
valid_lang(id) &&
|
||||
if (id != def_id && valid_lang(id) &&
|
||||
get_locale_name(id, locale_name)) {
|
||||
|
||||
dstr_copy(cur.name, locale_name);
|
||||
|
@ -418,17 +393,17 @@ static void obs_event(enum obs_frontend_event event, void *)
|
|||
FreeCaptions();
|
||||
}
|
||||
|
||||
static void save_caption_data(obs_data_t *save_data, bool saving, void*)
|
||||
static void save_caption_data(obs_data_t *save_data, bool saving, void *)
|
||||
{
|
||||
if (saving) {
|
||||
obs_data_t *obj = obs_data_create();
|
||||
|
||||
obs_data_set_string(obj, "source",
|
||||
captions->source_name.c_str());
|
||||
captions->source_name.c_str());
|
||||
obs_data_set_bool(obj, "enabled", !!captions->handler);
|
||||
obs_data_set_int(obj, "lang_id", captions->lang_id);
|
||||
obs_data_set_string(obj, "provider",
|
||||
captions->handler_id.c_str());
|
||||
captions->handler_id.c_str());
|
||||
|
||||
obs_data_set_obj(save_data, "captions", obj);
|
||||
obs_data_release(obj);
|
||||
|
@ -440,15 +415,15 @@ static void save_caption_data(obs_data_t *save_data, bool saving, void*)
|
|||
obj = obs_data_create();
|
||||
|
||||
obs_data_set_default_int(obj, "lang_id",
|
||||
GetUserDefaultUILanguage());
|
||||
GetUserDefaultUILanguage());
|
||||
obs_data_set_default_string(obj, "provider", DEFAULT_HANDLER);
|
||||
|
||||
bool enabled = obs_data_get_bool(obj, "enabled");
|
||||
captions->source_name = obs_data_get_string(obj, "source");
|
||||
captions->lang_id = (int)obs_data_get_int(obj, "lang_id");
|
||||
captions->handler_id = obs_data_get_string(obj, "provider");
|
||||
captions->source = GetWeakSourceByName(
|
||||
captions->source_name.c_str());
|
||||
captions->source =
|
||||
GetWeakSourceByName(captions->source_name.c_str());
|
||||
obs_data_release(obj);
|
||||
|
||||
if (enabled)
|
||||
|
@ -458,17 +433,15 @@ static void save_caption_data(obs_data_t *save_data, bool saving, void*)
|
|||
|
||||
extern "C" void InitCaptions()
|
||||
{
|
||||
QAction *action = (QAction*)obs_frontend_add_tools_menu_qaction(
|
||||
obs_module_text("Captions"));
|
||||
QAction *action = (QAction *)obs_frontend_add_tools_menu_qaction(
|
||||
obs_module_text("Captions"));
|
||||
|
||||
captions = new obs_captions;
|
||||
|
||||
auto cb = [] ()
|
||||
{
|
||||
auto cb = []() {
|
||||
obs_frontend_push_ui_translation(obs_module_get_string);
|
||||
|
||||
QWidget *window =
|
||||
(QWidget*)obs_frontend_get_main_window();
|
||||
QWidget *window = (QWidget *)obs_frontend_get_main_window();
|
||||
|
||||
CaptionsDialog dialog(window);
|
||||
dialog.exec();
|
||||
|
|
|
@ -13,19 +13,18 @@ using namespace std;
|
|||
OutputTimer *ot;
|
||||
|
||||
OutputTimer::OutputTimer(QWidget *parent)
|
||||
: QDialog(parent),
|
||||
ui(new Ui_OutputTimer)
|
||||
: QDialog(parent), ui(new Ui_OutputTimer)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
|
||||
QObject::connect(ui->outputTimerStream, SIGNAL(clicked()), this,
|
||||
SLOT(StreamingTimerButton()));
|
||||
SLOT(StreamingTimerButton()));
|
||||
QObject::connect(ui->outputTimerRecord, SIGNAL(clicked()), this,
|
||||
SLOT(RecordingTimerButton()));
|
||||
SLOT(RecordingTimerButton()));
|
||||
QObject::connect(ui->buttonBox->button(QDialogButtonBox::Close),
|
||||
SIGNAL(clicked()), this, SLOT(hide()));
|
||||
SIGNAL(clicked()), this, SLOT(hide()));
|
||||
|
||||
streamingTimer = new QTimer(this);
|
||||
streamingTimerDisplay = new QTimer(this);
|
||||
|
@ -34,7 +33,7 @@ OutputTimer::OutputTimer(QWidget *parent)
|
|||
recordingTimerDisplay = new QTimer(this);
|
||||
}
|
||||
|
||||
void OutputTimer::closeEvent(QCloseEvent*)
|
||||
void OutputTimer::closeEvent(QCloseEvent *)
|
||||
{
|
||||
obs_frontend_save();
|
||||
}
|
||||
|
@ -78,9 +77,7 @@ void OutputTimer::StreamTimerStart()
|
|||
int minutes = ui->streamingTimerMinutes->value();
|
||||
int seconds = ui->streamingTimerSeconds->value();
|
||||
|
||||
int total = (((hours * 3600) +
|
||||
(minutes * 60)) +
|
||||
seconds) * 1000;
|
||||
int total = (((hours * 3600) + (minutes * 60)) + seconds) * 1000;
|
||||
|
||||
if (total == 0)
|
||||
total = 1000;
|
||||
|
@ -89,10 +86,10 @@ void OutputTimer::StreamTimerStart()
|
|||
streamingTimer->setSingleShot(true);
|
||||
|
||||
QObject::connect(streamingTimer, SIGNAL(timeout()),
|
||||
SLOT(EventStopStreaming()));
|
||||
SLOT(EventStopStreaming()));
|
||||
|
||||
QObject::connect(streamingTimerDisplay, SIGNAL(timeout()), this,
|
||||
SLOT(UpdateStreamTimerDisplay()));
|
||||
SLOT(UpdateStreamTimerDisplay()));
|
||||
|
||||
streamingTimer->start();
|
||||
streamingTimerDisplay->start(1000);
|
||||
|
@ -112,9 +109,7 @@ void OutputTimer::RecordTimerStart()
|
|||
int minutes = ui->recordingTimerMinutes->value();
|
||||
int seconds = ui->recordingTimerSeconds->value();
|
||||
|
||||
int total = (((hours * 3600) +
|
||||
(minutes * 60)) +
|
||||
seconds) * 1000;
|
||||
int total = (((hours * 3600) + (minutes * 60)) + seconds) * 1000;
|
||||
|
||||
if (total == 0)
|
||||
total = 1000;
|
||||
|
@ -123,10 +118,10 @@ void OutputTimer::RecordTimerStart()
|
|||
recordingTimer->setSingleShot(true);
|
||||
|
||||
QObject::connect(recordingTimer, SIGNAL(timeout()),
|
||||
SLOT(EventStopRecording()));
|
||||
SLOT(EventStopRecording()));
|
||||
|
||||
QObject::connect(recordingTimerDisplay, SIGNAL(timeout()), this,
|
||||
SLOT(UpdateRecordTimerDisplay()));
|
||||
SLOT(UpdateRecordTimerDisplay()));
|
||||
|
||||
recordingTimer->start();
|
||||
recordingTimerDisplay->start(1000);
|
||||
|
@ -226,60 +221,57 @@ static void SaveOutputTimer(obs_data_t *save_data, bool saving, void *)
|
|||
obs_data_t *obj = obs_data_create();
|
||||
|
||||
obs_data_set_int(obj, "streamTimerHours",
|
||||
ot->ui->streamingTimerHours->value());
|
||||
ot->ui->streamingTimerHours->value());
|
||||
obs_data_set_int(obj, "streamTimerMinutes",
|
||||
ot->ui->streamingTimerMinutes->value());
|
||||
ot->ui->streamingTimerMinutes->value());
|
||||
obs_data_set_int(obj, "streamTimerSeconds",
|
||||
ot->ui->streamingTimerSeconds->value());
|
||||
ot->ui->streamingTimerSeconds->value());
|
||||
|
||||
obs_data_set_int(obj, "recordTimerHours",
|
||||
ot->ui->recordingTimerHours->value());
|
||||
ot->ui->recordingTimerHours->value());
|
||||
obs_data_set_int(obj, "recordTimerMinutes",
|
||||
ot->ui->recordingTimerMinutes->value());
|
||||
ot->ui->recordingTimerMinutes->value());
|
||||
obs_data_set_int(obj, "recordTimerSeconds",
|
||||
ot->ui->recordingTimerSeconds->value());
|
||||
ot->ui->recordingTimerSeconds->value());
|
||||
|
||||
obs_data_set_bool(obj, "autoStartStreamTimer",
|
||||
ot->ui->autoStartStreamTimer->isChecked());
|
||||
ot->ui->autoStartStreamTimer->isChecked());
|
||||
obs_data_set_bool(obj, "autoStartRecordTimer",
|
||||
ot->ui->autoStartRecordTimer->isChecked());
|
||||
ot->ui->autoStartRecordTimer->isChecked());
|
||||
|
||||
obs_data_set_obj(save_data, "output-timer", obj);
|
||||
|
||||
obs_data_release(obj);
|
||||
} else {
|
||||
obs_data_t *obj = obs_data_get_obj(save_data,
|
||||
"output-timer");
|
||||
obs_data_t *obj = obs_data_get_obj(save_data, "output-timer");
|
||||
|
||||
if (!obj)
|
||||
obj = obs_data_create();
|
||||
|
||||
ot->ui->streamingTimerHours->setValue(
|
||||
obs_data_get_int(obj, "streamTimerHours"));
|
||||
obs_data_get_int(obj, "streamTimerHours"));
|
||||
ot->ui->streamingTimerMinutes->setValue(
|
||||
obs_data_get_int(obj, "streamTimerMinutes"));
|
||||
obs_data_get_int(obj, "streamTimerMinutes"));
|
||||
ot->ui->streamingTimerSeconds->setValue(
|
||||
obs_data_get_int(obj, "streamTimerSeconds"));
|
||||
obs_data_get_int(obj, "streamTimerSeconds"));
|
||||
|
||||
ot->ui->recordingTimerHours->setValue(
|
||||
obs_data_get_int(obj, "recordTimerHours"));
|
||||
obs_data_get_int(obj, "recordTimerHours"));
|
||||
ot->ui->recordingTimerMinutes->setValue(
|
||||
obs_data_get_int(obj, "recordTimerMinutes"));
|
||||
obs_data_get_int(obj, "recordTimerMinutes"));
|
||||
ot->ui->recordingTimerSeconds->setValue(
|
||||
obs_data_get_int(obj, "recordTimerSeconds"));
|
||||
obs_data_get_int(obj, "recordTimerSeconds"));
|
||||
|
||||
ot->ui->autoStartStreamTimer->setChecked(
|
||||
obs_data_get_bool(obj, "autoStartStreamTimer"));
|
||||
obs_data_get_bool(obj, "autoStartStreamTimer"));
|
||||
ot->ui->autoStartRecordTimer->setChecked(
|
||||
obs_data_get_bool(obj, "autoStartRecordTimer"));
|
||||
obs_data_get_bool(obj, "autoStartRecordTimer"));
|
||||
|
||||
obs_data_release(obj);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void FreeOutputTimer()
|
||||
{
|
||||
}
|
||||
extern "C" void FreeOutputTimer() {}
|
||||
|
||||
static void OBSEvent(enum obs_frontend_event event, void *)
|
||||
{
|
||||
|
@ -299,19 +291,16 @@ static void OBSEvent(enum obs_frontend_event event, void *)
|
|||
|
||||
extern "C" void InitOutputTimer()
|
||||
{
|
||||
QAction *action = (QAction*)obs_frontend_add_tools_menu_qaction(
|
||||
obs_module_text("OutputTimer"));
|
||||
QAction *action = (QAction *)obs_frontend_add_tools_menu_qaction(
|
||||
obs_module_text("OutputTimer"));
|
||||
|
||||
obs_frontend_push_ui_translation(obs_module_get_string);
|
||||
|
||||
QMainWindow *window = (QMainWindow*)obs_frontend_get_main_window();
|
||||
QMainWindow *window = (QMainWindow *)obs_frontend_get_main_window();
|
||||
|
||||
ot = new OutputTimer(window);
|
||||
|
||||
auto cb = [] ()
|
||||
{
|
||||
ot->ShowHideDialog();
|
||||
};
|
||||
auto cb = []() { ot->ShowHideDialog(); };
|
||||
|
||||
obs_frontend_pop_ui_translation();
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
|
||||
/* ----------------------------------------------------------------- */
|
||||
|
||||
using OBSScript = OBSObj<obs_script_t*, obs_script_destroy>;
|
||||
using OBSScript = OBSObj<obs_script_t *, obs_script_destroy>;
|
||||
|
||||
struct ScriptData {
|
||||
std::vector<OBSScript> scripts;
|
||||
|
@ -92,11 +92,10 @@ ScriptLogWindow::ScriptLogWindow() : QWidget(nullptr)
|
|||
|
||||
QHBoxLayout *buttonLayout = new QHBoxLayout();
|
||||
QPushButton *clearButton = new QPushButton(tr("Clear"));
|
||||
connect(clearButton, &QPushButton::clicked,
|
||||
this, &ScriptLogWindow::ClearWindow);
|
||||
connect(clearButton, &QPushButton::clicked, this,
|
||||
&ScriptLogWindow::ClearWindow);
|
||||
QPushButton *closeButton = new QPushButton(tr("Close"));
|
||||
connect(closeButton, &QPushButton::clicked,
|
||||
this, &QDialog::hide);
|
||||
connect(closeButton, &QPushButton::clicked, this, &QDialog::hide);
|
||||
|
||||
buttonLayout->addStretch();
|
||||
buttonLayout->addWidget(clearButton);
|
||||
|
@ -112,8 +111,8 @@ ScriptLogWindow::ScriptLogWindow() : QWidget(nullptr)
|
|||
resize(600, 400);
|
||||
|
||||
config_t *global_config = obs_frontend_get_global_config();
|
||||
const char *geom = config_get_string(global_config,
|
||||
"ScriptLogWindow", "geometry");
|
||||
const char *geom =
|
||||
config_get_string(global_config, "ScriptLogWindow", "geometry");
|
||||
if (geom != nullptr) {
|
||||
QByteArray ba = QByteArray::fromBase64(QByteArray(geom));
|
||||
restoreGeometry(ba);
|
||||
|
@ -121,16 +120,15 @@ ScriptLogWindow::ScriptLogWindow() : QWidget(nullptr)
|
|||
|
||||
setWindowTitle(obs_module_text("ScriptLogWindow"));
|
||||
|
||||
connect(edit->verticalScrollBar(), &QAbstractSlider::sliderMoved,
|
||||
this, &ScriptLogWindow::ScrollChanged);
|
||||
connect(edit->verticalScrollBar(), &QAbstractSlider::sliderMoved, this,
|
||||
&ScriptLogWindow::ScrollChanged);
|
||||
}
|
||||
|
||||
ScriptLogWindow::~ScriptLogWindow()
|
||||
{
|
||||
config_t *global_config = obs_frontend_get_global_config();
|
||||
config_set_string(global_config,
|
||||
"ScriptLogWindow", "geometry",
|
||||
saveGeometry().toBase64().constData());
|
||||
config_set_string(global_config, "ScriptLogWindow", "geometry",
|
||||
saveGeometry().toBase64().constData());
|
||||
}
|
||||
|
||||
void ScriptLogWindow::ScrollChanged(int val)
|
||||
|
@ -180,17 +178,15 @@ void ScriptLogWindow::Clear()
|
|||
|
||||
/* ----------------------------------------------------------------- */
|
||||
|
||||
ScriptsTool::ScriptsTool()
|
||||
: QWidget (nullptr),
|
||||
ui (new Ui_ScriptsTool)
|
||||
ScriptsTool::ScriptsTool() : QWidget(nullptr), ui(new Ui_ScriptsTool)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
RefreshLists();
|
||||
|
||||
#if PYTHON_UI
|
||||
config_t *config = obs_frontend_get_global_config();
|
||||
const char *path = config_get_string(config, "Python",
|
||||
"Path" ARCH_NAME);
|
||||
const char *path =
|
||||
config_get_string(config, "Python", "Path" ARCH_NAME);
|
||||
ui->pythonPath->setText(path);
|
||||
ui->pythonPathLabel->setText(obs_module_text(PYTHONPATH_LABEL_TEXT));
|
||||
#else
|
||||
|
@ -201,7 +197,7 @@ ScriptsTool::ScriptsTool()
|
|||
delete propertiesView;
|
||||
propertiesView = new QWidget();
|
||||
propertiesView->setSizePolicy(QSizePolicy::Expanding,
|
||||
QSizePolicy::Expanding);
|
||||
QSizePolicy::Expanding);
|
||||
ui->propertiesLayout->addWidget(propertiesView);
|
||||
}
|
||||
|
||||
|
@ -217,8 +213,8 @@ void ScriptsTool::RemoveScript(const char *path)
|
|||
|
||||
const char *script_path = obs_script_get_path(script);
|
||||
if (strcmp(script_path, path) == 0) {
|
||||
scriptData->scripts.erase(
|
||||
scriptData->scripts.begin() + i);
|
||||
scriptData->scripts.erase(scriptData->scripts.begin() +
|
||||
i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -323,7 +319,8 @@ void ScriptsTool::on_addScripts_clicked()
|
|||
|
||||
scriptData->scripts.emplace_back(script);
|
||||
|
||||
QListWidgetItem *item = new QListWidgetItem(script_file);
|
||||
QListWidgetItem *item =
|
||||
new QListWidgetItem(script_file);
|
||||
item->setData(Qt::UserRole, QString(file));
|
||||
ui->scripts->addItem(item);
|
||||
|
||||
|
@ -343,8 +340,10 @@ void ScriptsTool::on_removeScripts_clicked()
|
|||
QList<QListWidgetItem *> items = ui->scripts->selectedItems();
|
||||
|
||||
for (QListWidgetItem *item : items)
|
||||
RemoveScript(item->data(Qt::UserRole).toString()
|
||||
.toUtf8().constData());
|
||||
RemoveScript(item->data(Qt::UserRole)
|
||||
.toString()
|
||||
.toUtf8()
|
||||
.constData());
|
||||
RefreshLists();
|
||||
}
|
||||
|
||||
|
@ -352,8 +351,10 @@ void ScriptsTool::on_reloadScripts_clicked()
|
|||
{
|
||||
QList<QListWidgetItem *> items = ui->scripts->selectedItems();
|
||||
for (QListWidgetItem *item : items)
|
||||
ReloadScript(item->data(Qt::UserRole).toString()
|
||||
.toUtf8().constData());
|
||||
ReloadScript(item->data(Qt::UserRole)
|
||||
.toString()
|
||||
.toUtf8()
|
||||
.constData());
|
||||
|
||||
on_scripts_currentRowChanged(ui->scripts->currentRow());
|
||||
}
|
||||
|
@ -368,9 +369,7 @@ void ScriptsTool::on_pythonPathBrowse_clicked()
|
|||
{
|
||||
QString curPath = ui->pythonPath->text();
|
||||
QString newPath = QFileDialog::getExistingDirectory(
|
||||
this,
|
||||
ui->pythonPathLabel->text(),
|
||||
curPath);
|
||||
this, ui->pythonPathLabel->text(), curPath);
|
||||
|
||||
if (newPath.isEmpty())
|
||||
return;
|
||||
|
@ -406,14 +405,14 @@ void ScriptsTool::on_scripts_currentRowChanged(int row)
|
|||
if (row == -1) {
|
||||
propertiesView = new QWidget();
|
||||
propertiesView->setSizePolicy(QSizePolicy::Expanding,
|
||||
QSizePolicy::Expanding);
|
||||
QSizePolicy::Expanding);
|
||||
ui->propertiesLayout->addWidget(propertiesView);
|
||||
ui->description->setText(QString());
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray array = ui->scripts->item(row)->data(Qt::UserRole)
|
||||
.toString().toUtf8();
|
||||
QByteArray array =
|
||||
ui->scripts->item(row)->data(Qt::UserRole).toString().toUtf8();
|
||||
const char *path = array.constData();
|
||||
|
||||
obs_script_t *script = scriptData->FindScript(path);
|
||||
|
@ -425,9 +424,10 @@ void ScriptsTool::on_scripts_currentRowChanged(int row)
|
|||
OBSData settings = obs_script_get_settings(script);
|
||||
obs_data_release(settings);
|
||||
|
||||
propertiesView = new OBSPropertiesView(settings, script,
|
||||
(PropertiesReloadCallback)obs_script_get_properties,
|
||||
(PropertiesUpdateCallback)obs_script_update);
|
||||
propertiesView = new OBSPropertiesView(
|
||||
settings, script,
|
||||
(PropertiesReloadCallback)obs_script_get_properties,
|
||||
(PropertiesUpdateCallback)obs_script_update);
|
||||
ui->propertiesLayout->addWidget(propertiesView);
|
||||
ui->description->setText(obs_script_get_description(script));
|
||||
}
|
||||
|
@ -457,8 +457,7 @@ static void obs_event(enum obs_frontend_event event, void *)
|
|||
|
||||
static void load_script_data(obs_data_t *load_data, bool, void *)
|
||||
{
|
||||
obs_data_array_t *array = obs_data_get_array(load_data,
|
||||
"scripts-tool");
|
||||
obs_data_array_t *array = obs_data_get_array(load_data, "scripts-tool");
|
||||
|
||||
delete scriptData;
|
||||
scriptData = new ScriptData;
|
||||
|
@ -509,21 +508,19 @@ static void save_script_data(obs_data_t *save_data, bool saving, void *)
|
|||
}
|
||||
|
||||
static void script_log(void *, obs_script_t *script, int log_level,
|
||||
const char *message)
|
||||
const char *message)
|
||||
{
|
||||
QString qmsg;
|
||||
|
||||
if (script) {
|
||||
qmsg = QStringLiteral("[%1] %2").arg(
|
||||
obs_script_get_file(script),
|
||||
message);
|
||||
obs_script_get_file(script), message);
|
||||
} else {
|
||||
qmsg = QStringLiteral("[Unknown Script] %1").arg(message);
|
||||
}
|
||||
|
||||
QMetaObject::invokeMethod(scriptLogWindow, "AddLogMsg",
|
||||
Q_ARG(int, log_level),
|
||||
Q_ARG(QString, qmsg));
|
||||
Q_ARG(int, log_level), Q_ARG(QString, qmsg));
|
||||
}
|
||||
|
||||
extern "C" void InitScripts()
|
||||
|
@ -533,13 +530,13 @@ extern "C" void InitScripts()
|
|||
obs_scripting_load();
|
||||
obs_scripting_set_log_callback(script_log, nullptr);
|
||||
|
||||
QAction *action = (QAction*)obs_frontend_add_tools_menu_qaction(
|
||||
obs_module_text("Scripts"));
|
||||
QAction *action = (QAction *)obs_frontend_add_tools_menu_qaction(
|
||||
obs_module_text("Scripts"));
|
||||
|
||||
#if PYTHON_UI
|
||||
config_t *config = obs_frontend_get_global_config();
|
||||
const char *python_path = config_get_string(config, "Python",
|
||||
"Path" ARCH_NAME);
|
||||
const char *python_path =
|
||||
config_get_string(config, "Python", "Path" ARCH_NAME);
|
||||
|
||||
if (!obs_scripting_python_loaded() && python_path && *python_path)
|
||||
obs_scripting_load_python(python_path);
|
||||
|
@ -547,8 +544,7 @@ extern "C" void InitScripts()
|
|||
|
||||
scriptData = new ScriptData;
|
||||
|
||||
auto cb = [] ()
|
||||
{
|
||||
auto cb = []() {
|
||||
obs_frontend_push_ui_translation(obs_module_get_string);
|
||||
|
||||
if (!scriptsWindow) {
|
||||
|
|
|
@ -8,8 +8,7 @@ class HScrollArea : public QScrollArea {
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
inline HScrollArea(QWidget *parent = nullptr)
|
||||
: QScrollArea(parent)
|
||||
inline HScrollArea(QWidget *parent = nullptr) : QScrollArea(parent)
|
||||
{
|
||||
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
}
|
||||
|
|
|
@ -25,13 +25,13 @@
|
|||
#include "qt-wrappers.hpp"
|
||||
|
||||
static inline bool operator!=(const obs_key_combination_t &c1,
|
||||
const obs_key_combination_t &c2)
|
||||
const obs_key_combination_t &c2)
|
||||
{
|
||||
return c1.modifiers != c2.modifiers || c1.key != c2.key;
|
||||
}
|
||||
|
||||
static inline bool operator==(const obs_key_combination_t &c1,
|
||||
const obs_key_combination_t &c2)
|
||||
const obs_key_combination_t &c2)
|
||||
{
|
||||
return !(c1 != c2);
|
||||
}
|
||||
|
@ -105,32 +105,34 @@ void OBSHotkeyEdit::mousePressEvent(QMouseEvent *event)
|
|||
new_key.key = OBS_KEY_MOUSE3;
|
||||
break;
|
||||
|
||||
#define MAP_BUTTON(i, j) case Qt::ExtraButton ## i: \
|
||||
new_key.key = OBS_KEY_MOUSE ## j; break;
|
||||
MAP_BUTTON( 1, 4);
|
||||
MAP_BUTTON( 2, 5);
|
||||
MAP_BUTTON( 3, 6);
|
||||
MAP_BUTTON( 4, 7);
|
||||
MAP_BUTTON( 5, 8);
|
||||
MAP_BUTTON( 6, 9);
|
||||
MAP_BUTTON( 7, 10);
|
||||
MAP_BUTTON( 8, 11);
|
||||
MAP_BUTTON( 9, 12);
|
||||
MAP_BUTTON(10, 13);
|
||||
MAP_BUTTON(11, 14);
|
||||
MAP_BUTTON(12, 15);
|
||||
MAP_BUTTON(13, 16);
|
||||
MAP_BUTTON(14, 17);
|
||||
MAP_BUTTON(15, 18);
|
||||
MAP_BUTTON(16, 19);
|
||||
MAP_BUTTON(17, 20);
|
||||
MAP_BUTTON(18, 21);
|
||||
MAP_BUTTON(19, 22);
|
||||
MAP_BUTTON(20, 23);
|
||||
MAP_BUTTON(21, 24);
|
||||
MAP_BUTTON(22, 25);
|
||||
MAP_BUTTON(23, 26);
|
||||
MAP_BUTTON(24, 27);
|
||||
#define MAP_BUTTON(i, j) \
|
||||
case Qt::ExtraButton##i: \
|
||||
new_key.key = OBS_KEY_MOUSE##j; \
|
||||
break;
|
||||
MAP_BUTTON(1, 4)
|
||||
MAP_BUTTON(2, 5)
|
||||
MAP_BUTTON(3, 6)
|
||||
MAP_BUTTON(4, 7)
|
||||
MAP_BUTTON(5, 8)
|
||||
MAP_BUTTON(6, 9)
|
||||
MAP_BUTTON(7, 10)
|
||||
MAP_BUTTON(8, 11)
|
||||
MAP_BUTTON(9, 12)
|
||||
MAP_BUTTON(10, 13)
|
||||
MAP_BUTTON(11, 14)
|
||||
MAP_BUTTON(12, 15)
|
||||
MAP_BUTTON(13, 16)
|
||||
MAP_BUTTON(14, 17)
|
||||
MAP_BUTTON(15, 18)
|
||||
MAP_BUTTON(16, 19)
|
||||
MAP_BUTTON(17, 20)
|
||||
MAP_BUTTON(18, 21)
|
||||
MAP_BUTTON(19, 22)
|
||||
MAP_BUTTON(20, 23)
|
||||
MAP_BUTTON(21, 24)
|
||||
MAP_BUTTON(22, 25)
|
||||
MAP_BUTTON(23, 26)
|
||||
MAP_BUTTON(24, 27)
|
||||
#undef MAP_BUTTON
|
||||
}
|
||||
|
||||
|
@ -183,13 +185,13 @@ void OBSHotkeyEdit::ClearKey()
|
|||
|
||||
void OBSHotkeyEdit::InitSignalHandler()
|
||||
{
|
||||
layoutChanged = {obs_get_signal_handler(),
|
||||
"hotkey_layout_change",
|
||||
[](void *this_, calldata_t*)
|
||||
{
|
||||
auto edit = static_cast<OBSHotkeyEdit*>(this_);
|
||||
QMetaObject::invokeMethod(edit, "ReloadKeyLayout");
|
||||
}, this};
|
||||
layoutChanged = {
|
||||
obs_get_signal_handler(), "hotkey_layout_change",
|
||||
[](void *this_, calldata_t *) {
|
||||
auto edit = static_cast<OBSHotkeyEdit *>(this_);
|
||||
QMetaObject::invokeMethod(edit, "ReloadKeyLayout");
|
||||
},
|
||||
this};
|
||||
}
|
||||
|
||||
void OBSHotkeyEdit::ReloadKeyLayout()
|
||||
|
@ -198,7 +200,7 @@ void OBSHotkeyEdit::ReloadKeyLayout()
|
|||
}
|
||||
|
||||
void OBSHotkeyWidget::SetKeyCombinations(
|
||||
const std::vector<obs_key_combination_t> &combos)
|
||||
const std::vector<obs_key_combination_t> &combos)
|
||||
{
|
||||
if (combos.empty())
|
||||
AddEdit({0, OBS_KEY_NONE});
|
||||
|
@ -210,10 +212,8 @@ void OBSHotkeyWidget::SetKeyCombinations(
|
|||
bool OBSHotkeyWidget::Changed() const
|
||||
{
|
||||
return changed ||
|
||||
std::any_of(begin(edits), end(edits), [](OBSHotkeyEdit *edit)
|
||||
{
|
||||
return edit->changed;
|
||||
});
|
||||
std::any_of(begin(edits), end(edits),
|
||||
[](OBSHotkeyEdit *edit) { return edit->changed; });
|
||||
}
|
||||
|
||||
void OBSHotkeyWidget::Apply()
|
||||
|
@ -230,7 +230,7 @@ void OBSHotkeyWidget::Apply()
|
|||
}
|
||||
|
||||
void OBSHotkeyWidget::GetCombinations(
|
||||
std::vector<obs_key_combination_t> &combinations) const
|
||||
std::vector<obs_key_combination_t> &combinations) const
|
||||
{
|
||||
combinations.clear();
|
||||
for (auto &edit : edits)
|
||||
|
@ -249,21 +249,19 @@ void OBSHotkeyWidget::Save(std::vector<obs_key_combination_t> &combinations)
|
|||
GetCombinations(combinations);
|
||||
Apply();
|
||||
|
||||
auto AtomicUpdate = [&]()
|
||||
{
|
||||
auto AtomicUpdate = [&]() {
|
||||
ignoreChangedBindings = true;
|
||||
|
||||
obs_hotkey_load_bindings(id,
|
||||
combinations.data(), combinations.size());
|
||||
obs_hotkey_load_bindings(id, combinations.data(),
|
||||
combinations.size());
|
||||
|
||||
ignoreChangedBindings = false;
|
||||
};
|
||||
using AtomicUpdate_t = decltype(&AtomicUpdate);
|
||||
|
||||
obs_hotkey_update_atomic([](void *d)
|
||||
{
|
||||
(*static_cast<AtomicUpdate_t>(d))();
|
||||
}, static_cast<void*>(&AtomicUpdate));
|
||||
obs_hotkey_update_atomic(
|
||||
[](void *d) { (*static_cast<AtomicUpdate_t>(d))(); },
|
||||
static_cast<void *>(&AtomicUpdate));
|
||||
}
|
||||
|
||||
void OBSHotkeyWidget::AddEdit(obs_key_combination combo, int idx)
|
||||
|
@ -285,12 +283,13 @@ void OBSHotkeyWidget::AddEdit(obs_key_combination combo, int idx)
|
|||
clear->setFlat(true);
|
||||
clear->setEnabled(!obs_key_combination_is_empty(combo));
|
||||
|
||||
QObject::connect(edit, &OBSHotkeyEdit::KeyChanged,
|
||||
[=](obs_key_combination_t new_combo)
|
||||
{
|
||||
clear->setEnabled(!obs_key_combination_is_empty(new_combo));
|
||||
revert->setEnabled(edit->original != new_combo);
|
||||
});
|
||||
QObject::connect(
|
||||
edit, &OBSHotkeyEdit::KeyChanged,
|
||||
[=](obs_key_combination_t new_combo) {
|
||||
clear->setEnabled(
|
||||
!obs_key_combination_is_empty(new_combo));
|
||||
revert->setEnabled(edit->original != new_combo);
|
||||
});
|
||||
|
||||
auto add = new QPushButton;
|
||||
add->setProperty("themeID", "addIconSmall");
|
||||
|
@ -303,25 +302,18 @@ void OBSHotkeyWidget::AddEdit(obs_key_combination combo, int idx)
|
|||
remove->setFixedSize(24, 24);
|
||||
remove->setFlat(true);
|
||||
|
||||
auto CurrentIndex = [&, remove]
|
||||
{
|
||||
auto res = std::find(begin(removeButtons),
|
||||
end(removeButtons),
|
||||
remove);
|
||||
auto CurrentIndex = [&, remove] {
|
||||
auto res = std::find(begin(removeButtons), end(removeButtons),
|
||||
remove);
|
||||
return std::distance(begin(removeButtons), res);
|
||||
};
|
||||
|
||||
QObject::connect(add, &QPushButton::clicked,
|
||||
[&, CurrentIndex]
|
||||
{
|
||||
QObject::connect(add, &QPushButton::clicked, [&, CurrentIndex] {
|
||||
AddEdit({0, OBS_KEY_NONE}, CurrentIndex() + 1);
|
||||
});
|
||||
|
||||
QObject::connect(remove, &QPushButton::clicked,
|
||||
[&, CurrentIndex]
|
||||
{
|
||||
RemoveEdit(CurrentIndex());
|
||||
});
|
||||
[&, CurrentIndex] { RemoveEdit(CurrentIndex()); });
|
||||
|
||||
QHBoxLayout *subLayout = new QHBoxLayout;
|
||||
subLayout->setContentsMargins(0, 4, 0, 0);
|
||||
|
@ -346,16 +338,13 @@ void OBSHotkeyWidget::AddEdit(obs_key_combination combo, int idx)
|
|||
|
||||
layout()->insertLayout(idx, subLayout);
|
||||
|
||||
QObject::connect(revert, &QPushButton::clicked,
|
||||
edit, &OBSHotkeyEdit::ResetKey);
|
||||
QObject::connect(clear, &QPushButton::clicked,
|
||||
edit, &OBSHotkeyEdit::ClearKey);
|
||||
QObject::connect(revert, &QPushButton::clicked, edit,
|
||||
&OBSHotkeyEdit::ResetKey);
|
||||
QObject::connect(clear, &QPushButton::clicked, edit,
|
||||
&OBSHotkeyEdit::ClearKey);
|
||||
|
||||
QObject::connect(edit, &OBSHotkeyEdit::KeyChanged,
|
||||
[&](obs_key_combination)
|
||||
{
|
||||
emit KeyChanged();
|
||||
});
|
||||
[&](obs_key_combination) { emit KeyChanged(); });
|
||||
}
|
||||
|
||||
void OBSHotkeyWidget::RemoveEdit(size_t idx, bool signal)
|
||||
|
@ -384,34 +373,35 @@ void OBSHotkeyWidget::RemoveEdit(size_t idx, bool signal)
|
|||
|
||||
void OBSHotkeyWidget::BindingsChanged(void *data, calldata_t *param)
|
||||
{
|
||||
auto widget = static_cast<OBSHotkeyWidget*>(data);
|
||||
auto key = static_cast<obs_hotkey_t*>(calldata_ptr(param, "key"));
|
||||
auto widget = static_cast<OBSHotkeyWidget *>(data);
|
||||
auto key = static_cast<obs_hotkey_t *>(calldata_ptr(param, "key"));
|
||||
|
||||
QMetaObject::invokeMethod(widget, "HandleChangedBindings",
|
||||
Q_ARG(obs_hotkey_id, obs_hotkey_get_id(key)));
|
||||
Q_ARG(obs_hotkey_id, obs_hotkey_get_id(key)));
|
||||
}
|
||||
|
||||
void OBSHotkeyWidget::HandleChangedBindings(obs_hotkey_id id_)
|
||||
{
|
||||
if (ignoreChangedBindings || id != id_) return;
|
||||
if (ignoreChangedBindings || id != id_)
|
||||
return;
|
||||
|
||||
std::vector<obs_key_combination_t> bindings;
|
||||
auto LoadBindings = [&](obs_hotkey_binding_t *binding)
|
||||
{
|
||||
if (obs_hotkey_binding_get_hotkey_id(binding) != id) return;
|
||||
auto LoadBindings = [&](obs_hotkey_binding_t *binding) {
|
||||
if (obs_hotkey_binding_get_hotkey_id(binding) != id)
|
||||
return;
|
||||
|
||||
auto get_combo = obs_hotkey_binding_get_key_combination;
|
||||
bindings.push_back(get_combo(binding));
|
||||
};
|
||||
using LoadBindings_t = decltype(&LoadBindings);
|
||||
|
||||
obs_enum_hotkey_bindings([](void *data,
|
||||
size_t, obs_hotkey_binding_t *binding)
|
||||
{
|
||||
auto LoadBindings = *static_cast<LoadBindings_t>(data);
|
||||
LoadBindings(binding);
|
||||
return true;
|
||||
}, static_cast<void*>(&LoadBindings));
|
||||
obs_enum_hotkey_bindings(
|
||||
[](void *data, size_t, obs_hotkey_binding_t *binding) {
|
||||
auto LoadBindings = *static_cast<LoadBindings_t>(data);
|
||||
LoadBindings(binding);
|
||||
return true;
|
||||
},
|
||||
static_cast<void *>(&LoadBindings));
|
||||
|
||||
while (edits.size() > 0)
|
||||
RemoveEdit(edits.size() - 1, false);
|
||||
|
|
|
@ -45,10 +45,8 @@ class OBSHotkeyEdit : public QLineEdit {
|
|||
Q_OBJECT;
|
||||
|
||||
public:
|
||||
OBSHotkeyEdit(obs_key_combination_t original,
|
||||
QWidget *parent=nullptr)
|
||||
: QLineEdit(parent),
|
||||
original(original)
|
||||
OBSHotkeyEdit(obs_key_combination_t original, QWidget *parent = nullptr)
|
||||
: QLineEdit(parent), original(original)
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
// disable the input cursor on OSX, focus should be clear
|
||||
|
@ -63,9 +61,10 @@ public:
|
|||
|
||||
obs_key_combination_t original;
|
||||
obs_key_combination_t key;
|
||||
bool changed = false;
|
||||
bool changed = false;
|
||||
|
||||
protected:
|
||||
OBSSignal layoutChanged;
|
||||
OBSSignal layoutChanged;
|
||||
|
||||
void InitSignalHandler();
|
||||
|
||||
|
@ -92,15 +91,14 @@ class OBSHotkeyWidget : public QWidget {
|
|||
|
||||
public:
|
||||
OBSHotkeyWidget(obs_hotkey_id id, std::string name,
|
||||
const std::vector<obs_key_combination_t> &combos={},
|
||||
QWidget *parent=nullptr)
|
||||
const std::vector<obs_key_combination_t> &combos = {},
|
||||
QWidget *parent = nullptr)
|
||||
: QWidget(parent),
|
||||
id(id),
|
||||
name(name),
|
||||
bindingsChanged(obs_get_signal_handler(),
|
||||
"hotkey_bindings_changed",
|
||||
&OBSHotkeyWidget::BindingsChanged,
|
||||
this)
|
||||
&OBSHotkeyWidget::BindingsChanged, this)
|
||||
{
|
||||
auto layout = new QVBoxLayout;
|
||||
layout->setSpacing(0);
|
||||
|
@ -110,7 +108,7 @@ public:
|
|||
SetKeyCombinations(combos);
|
||||
}
|
||||
|
||||
void SetKeyCombinations(const std::vector<obs_key_combination_t>&);
|
||||
void SetKeyCombinations(const std::vector<obs_key_combination_t> &);
|
||||
|
||||
obs_hotkey_id id;
|
||||
std::string name;
|
||||
|
@ -129,7 +127,7 @@ public:
|
|||
}
|
||||
|
||||
void Apply();
|
||||
void GetCombinations(std::vector<obs_key_combination_t>&) const;
|
||||
void GetCombinations(std::vector<obs_key_combination_t> &) const;
|
||||
void Save();
|
||||
void Save(std::vector<obs_key_combination_t> &combinations);
|
||||
|
||||
|
@ -137,8 +135,8 @@ public:
|
|||
void leaveEvent(QEvent *event) override;
|
||||
|
||||
private:
|
||||
void AddEdit(obs_key_combination combo, int idx=-1);
|
||||
void RemoveEdit(size_t idx, bool signal=true);
|
||||
void AddEdit(obs_key_combination combo, int idx = -1);
|
||||
void RemoveEdit(size_t idx, bool signal = true);
|
||||
|
||||
static void BindingsChanged(void *data, calldata_t *param);
|
||||
|
||||
|
@ -150,7 +148,7 @@ private:
|
|||
|
||||
QVBoxLayout *layout() const
|
||||
{
|
||||
return dynamic_cast<QVBoxLayout*>(QWidget::layout());
|
||||
return dynamic_cast<QVBoxLayout *>(QWidget::layout());
|
||||
}
|
||||
|
||||
private slots:
|
||||
|
|
|
@ -16,7 +16,7 @@ public:
|
|||
}
|
||||
|
||||
explicit inline MenuButton(const QString &text,
|
||||
QWidget *parent = nullptr)
|
||||
QWidget *parent = nullptr)
|
||||
: QPushButton(text, parent)
|
||||
{
|
||||
}
|
||||
|
|
11
UI/obf.c
11
UI/obf.c
|
@ -1,21 +1,20 @@
|
|||
#include "obf.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#define LOWER_HALFBYTE(x) ((x) & 0xF)
|
||||
#define LOWER_HALFBYTE(x) ((x)&0xF)
|
||||
#define UPPER_HALFBYTE(x) (((x) >> 4) & 0xF)
|
||||
|
||||
void deobfuscate_str(char *str, uint64_t val)
|
||||
{
|
||||
uint8_t *dec_val = (uint8_t*)&val;
|
||||
uint8_t *dec_val = (uint8_t *)&val;
|
||||
int i = 0;
|
||||
|
||||
while (*str != 0) {
|
||||
int pos = i / 2;
|
||||
bool bottom = (i % 2) == 0;
|
||||
uint8_t *ch = (uint8_t*)str;
|
||||
uint8_t xor = bottom ?
|
||||
LOWER_HALFBYTE(dec_val[pos]) :
|
||||
UPPER_HALFBYTE(dec_val[pos]);
|
||||
uint8_t *ch = (uint8_t *)str;
|
||||
uint8_t xor = bottom ? LOWER_HALFBYTE(dec_val[pos])
|
||||
: UPPER_HALFBYTE(dec_val[pos]);
|
||||
|
||||
*ch ^= xor;
|
||||
|
||||
|
|
686
UI/obs-app.cpp
686
UI/obs-app.cpp
File diff suppressed because it is too large
Load diff
|
@ -36,48 +36,50 @@
|
|||
|
||||
std::string CurrentTimeString();
|
||||
std::string CurrentDateTimeString();
|
||||
std::string GenerateTimeDateFilename(const char *extension, bool noSpace=false);
|
||||
std::string GenerateTimeDateFilename(const char *extension,
|
||||
bool noSpace = false);
|
||||
std::string GenerateSpecifiedFilename(const char *extension, bool noSpace,
|
||||
const char *format);
|
||||
const char *format);
|
||||
QObject *CreateShortcutFilter();
|
||||
|
||||
struct BaseLexer {
|
||||
lexer lex;
|
||||
|
||||
public:
|
||||
inline BaseLexer() {lexer_init(&lex);}
|
||||
inline ~BaseLexer() {lexer_free(&lex);}
|
||||
operator lexer*() {return &lex;}
|
||||
inline BaseLexer() { lexer_init(&lex); }
|
||||
inline ~BaseLexer() { lexer_free(&lex); }
|
||||
operator lexer *() { return &lex; }
|
||||
};
|
||||
|
||||
class OBSTranslator : public QTranslator {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
virtual bool isEmpty() const override {return false;}
|
||||
virtual bool isEmpty() const override { return false; }
|
||||
|
||||
virtual QString translate(const char *context, const char *sourceText,
|
||||
const char *disambiguation, int n) const override;
|
||||
const char *disambiguation,
|
||||
int n) const override;
|
||||
};
|
||||
|
||||
typedef std::function<void ()> VoidFunc;
|
||||
typedef std::function<void()> VoidFunc;
|
||||
|
||||
class OBSApp : public QApplication {
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
std::string locale;
|
||||
std::string theme;
|
||||
ConfigFile globalConfig;
|
||||
TextLookup textLookup;
|
||||
OBSContext obsContext;
|
||||
QPointer<OBSMainWindow> mainWindow;
|
||||
profiler_name_store_t *profilerNameStore = nullptr;
|
||||
std::string locale;
|
||||
std::string theme;
|
||||
ConfigFile globalConfig;
|
||||
TextLookup textLookup;
|
||||
OBSContext obsContext;
|
||||
QPointer<OBSMainWindow> mainWindow;
|
||||
profiler_name_store_t *profilerNameStore = nullptr;
|
||||
|
||||
os_inhibit_t *sleepInhibitor = nullptr;
|
||||
int sleepInhibitRefs = 0;
|
||||
|
||||
bool enableHotkeysInFocus = true;
|
||||
os_inhibit_t *sleepInhibitor = nullptr;
|
||||
int sleepInhibitRefs = 0;
|
||||
|
||||
bool enableHotkeysInFocus = true;
|
||||
|
||||
std::deque<obs_frontend_translate_ui_cb> translatorHooks;
|
||||
|
||||
|
@ -93,8 +95,8 @@ private:
|
|||
QPalette defaultPalette;
|
||||
|
||||
void ParseExtraThemeData(const char *path);
|
||||
void AddExtraThemeColor(QPalette &pal, int group,
|
||||
const char *name, uint32_t color);
|
||||
void AddExtraThemeColor(QPalette &pal, int group, const char *name,
|
||||
uint32_t color);
|
||||
|
||||
public:
|
||||
OBSApp(int &argc, char **argv, profiler_name_store_t *store);
|
||||
|
@ -105,19 +107,16 @@ public:
|
|||
|
||||
void EnableInFocusHotkeys(bool enable);
|
||||
|
||||
inline QMainWindow *GetMainWindow() const {return mainWindow.data();}
|
||||
inline QMainWindow *GetMainWindow() const { return mainWindow.data(); }
|
||||
|
||||
inline config_t *GlobalConfig() const {return globalConfig;}
|
||||
inline config_t *GlobalConfig() const { return globalConfig; }
|
||||
|
||||
inline const char *GetLocale() const
|
||||
{
|
||||
return locale.c_str();
|
||||
}
|
||||
inline const char *GetLocale() const { return locale.c_str(); }
|
||||
|
||||
inline const char *GetTheme() const {return theme.c_str();}
|
||||
inline const char *GetTheme() const { return theme.c_str(); }
|
||||
bool SetTheme(std::string name, std::string path = "");
|
||||
|
||||
inline lookup_t *GetTextLookup() const {return textLookup;}
|
||||
inline lookup_t *GetTextLookup() const { return textLookup; }
|
||||
|
||||
inline const char *GetString(const char *lookupVal) const
|
||||
{
|
||||
|
@ -146,15 +145,18 @@ public:
|
|||
|
||||
inline void IncrementSleepInhibition()
|
||||
{
|
||||
if (!sleepInhibitor) return;
|
||||
if (!sleepInhibitor)
|
||||
return;
|
||||
if (sleepInhibitRefs++ == 0)
|
||||
os_inhibit_sleep_set_active(sleepInhibitor, true);
|
||||
}
|
||||
|
||||
inline void DecrementSleepInhibition()
|
||||
{
|
||||
if (!sleepInhibitor) return;
|
||||
if (sleepInhibitRefs == 0) return;
|
||||
if (!sleepInhibitor)
|
||||
return;
|
||||
if (sleepInhibitRefs == 0)
|
||||
return;
|
||||
if (--sleepInhibitRefs == 0)
|
||||
os_inhibit_sleep_set_active(sleepInhibitor, false);
|
||||
}
|
||||
|
@ -164,10 +166,7 @@ public:
|
|||
translatorHooks.emplace_front(cb);
|
||||
}
|
||||
|
||||
inline void PopUITranslation()
|
||||
{
|
||||
translatorHooks.pop_front();
|
||||
}
|
||||
inline void PopUITranslation() { translatorHooks.pop_front(); }
|
||||
|
||||
public slots:
|
||||
void Exec(VoidFunc func);
|
||||
|
@ -182,12 +181,21 @@ char *GetConfigPathPtr(const char *name);
|
|||
int GetProgramDataPath(char *path, size_t size, const char *name);
|
||||
char *GetProgramDataPathPtr(const char *name);
|
||||
|
||||
inline OBSApp *App() {return static_cast<OBSApp*>(qApp);}
|
||||
inline OBSApp *App()
|
||||
{
|
||||
return static_cast<OBSApp *>(qApp);
|
||||
}
|
||||
|
||||
inline config_t *GetGlobalConfig() {return App()->GlobalConfig();}
|
||||
inline config_t *GetGlobalConfig()
|
||||
{
|
||||
return App()->GlobalConfig();
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> GetLocaleNames();
|
||||
inline const char *Str(const char *lookup) {return App()->GetString(lookup);}
|
||||
inline const char *Str(const char *lookup)
|
||||
{
|
||||
return App()->GetString(lookup);
|
||||
}
|
||||
#define QTStr(lookupVal) QString::fromUtf8(Str(lookupVal))
|
||||
|
||||
bool GetFileSafeName(const char *name, std::string &file);
|
||||
|
@ -197,8 +205,8 @@ bool WindowPositionValid(QRect rect);
|
|||
|
||||
static inline int GetProfilePath(char *path, size_t size, const char *file)
|
||||
{
|
||||
OBSMainWindow *window = reinterpret_cast<OBSMainWindow*>(
|
||||
App()->GetMainWindow());
|
||||
OBSMainWindow *window =
|
||||
reinterpret_cast<OBSMainWindow *>(App()->GetMainWindow());
|
||||
return window->GetProfilePath(path, size, file);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ static inline bool callbacks_valid_(const char *func_name)
|
|||
{
|
||||
if (!c) {
|
||||
blog(LOG_WARNING, "Tried to call %s with no callbacks!",
|
||||
func_name);
|
||||
func_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ static inline bool callbacks_valid_(const char *func_name)
|
|||
static char **convert_string_list(vector<string> &strings)
|
||||
{
|
||||
size_t size = 0;
|
||||
size_t string_data_offset = (strings.size() + 1) * sizeof(char*);
|
||||
size_t string_data_offset = (strings.size() + 1) * sizeof(char *);
|
||||
uint8_t *out;
|
||||
char **ptr_list;
|
||||
char *string_data;
|
||||
|
@ -39,9 +39,9 @@ static char **convert_string_list(vector<string> &strings)
|
|||
if (!size)
|
||||
return 0;
|
||||
|
||||
out = (uint8_t*)bmalloc(size);
|
||||
ptr_list = (char**)out;
|
||||
string_data = (char*)(out + string_data_offset);
|
||||
out = (uint8_t *)bmalloc(size);
|
||||
ptr_list = (char **)out;
|
||||
string_data = (char *)(out + string_data_offset);
|
||||
|
||||
for (auto &str : strings) {
|
||||
*ptr_list = string_data;
|
||||
|
@ -52,30 +52,27 @@ static char **convert_string_list(vector<string> &strings)
|
|||
}
|
||||
|
||||
*ptr_list = nullptr;
|
||||
return (char**)out;
|
||||
return (char **)out;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
void *obs_frontend_get_main_window(void)
|
||||
{
|
||||
return !!callbacks_valid()
|
||||
? c->obs_frontend_get_main_window()
|
||||
: nullptr;
|
||||
return !!callbacks_valid() ? c->obs_frontend_get_main_window()
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
void *obs_frontend_get_main_window_handle(void)
|
||||
{
|
||||
return !!callbacks_valid()
|
||||
? c->obs_frontend_get_main_window_handle()
|
||||
: nullptr;
|
||||
return !!callbacks_valid() ? c->obs_frontend_get_main_window_handle()
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
void *obs_frontend_get_system_tray(void)
|
||||
{
|
||||
return !!callbacks_valid()
|
||||
? c->obs_frontend_get_system_tray()
|
||||
: nullptr;
|
||||
return !!callbacks_valid() ? c->obs_frontend_get_system_tray()
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
char **obs_frontend_get_scene_names(void)
|
||||
|
@ -99,31 +96,32 @@ char **obs_frontend_get_scene_names(void)
|
|||
|
||||
void obs_frontend_get_scenes(struct obs_frontend_source_list *sources)
|
||||
{
|
||||
if (callbacks_valid()) c->obs_frontend_get_scenes(sources);
|
||||
if (callbacks_valid())
|
||||
c->obs_frontend_get_scenes(sources);
|
||||
}
|
||||
|
||||
obs_source_t *obs_frontend_get_current_scene(void)
|
||||
{
|
||||
return !!callbacks_valid()
|
||||
? c->obs_frontend_get_current_scene()
|
||||
: nullptr;
|
||||
return !!callbacks_valid() ? c->obs_frontend_get_current_scene()
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
void obs_frontend_set_current_scene(obs_source_t *scene)
|
||||
{
|
||||
if (callbacks_valid()) c->obs_frontend_set_current_scene(scene);
|
||||
if (callbacks_valid())
|
||||
c->obs_frontend_set_current_scene(scene);
|
||||
}
|
||||
|
||||
void obs_frontend_get_transitions(struct obs_frontend_source_list *sources)
|
||||
{
|
||||
if (callbacks_valid()) c->obs_frontend_get_transitions(sources);
|
||||
if (callbacks_valid())
|
||||
c->obs_frontend_get_transitions(sources);
|
||||
}
|
||||
|
||||
obs_source_t *obs_frontend_get_current_transition(void)
|
||||
{
|
||||
return !!callbacks_valid()
|
||||
? c->obs_frontend_get_current_transition()
|
||||
: nullptr;
|
||||
return !!callbacks_valid() ? c->obs_frontend_get_current_transition()
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
void obs_frontend_set_current_transition(obs_source_t *transition)
|
||||
|
@ -134,9 +132,8 @@ void obs_frontend_set_current_transition(obs_source_t *transition)
|
|||
|
||||
int obs_frontend_get_transition_duration(void)
|
||||
{
|
||||
return !!callbacks_valid()
|
||||
? c->obs_frontend_get_transition_duration()
|
||||
: 0;
|
||||
return !!callbacks_valid() ? c->obs_frontend_get_transition_duration()
|
||||
: 0;
|
||||
}
|
||||
|
||||
void obs_frontend_set_transition_duration(int duration)
|
||||
|
@ -158,8 +155,8 @@ char **obs_frontend_get_scene_collections(void)
|
|||
char *obs_frontend_get_current_scene_collection(void)
|
||||
{
|
||||
return !!callbacks_valid()
|
||||
? c->obs_frontend_get_current_scene_collection()
|
||||
: nullptr;
|
||||
? c->obs_frontend_get_current_scene_collection()
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
void obs_frontend_set_current_scene_collection(const char *collection)
|
||||
|
@ -170,9 +167,8 @@ void obs_frontend_set_current_scene_collection(const char *collection)
|
|||
|
||||
bool obs_frontend_add_scene_collection(const char *name)
|
||||
{
|
||||
return callbacks_valid()
|
||||
? c->obs_frontend_add_scene_collection(name)
|
||||
: false;
|
||||
return callbacks_valid() ? c->obs_frontend_add_scene_collection(name)
|
||||
: false;
|
||||
}
|
||||
|
||||
char **obs_frontend_get_profiles(void)
|
||||
|
@ -187,9 +183,8 @@ char **obs_frontend_get_profiles(void)
|
|||
|
||||
char *obs_frontend_get_current_profile(void)
|
||||
{
|
||||
return !!callbacks_valid()
|
||||
? c->obs_frontend_get_current_profile()
|
||||
: nullptr;
|
||||
return !!callbacks_valid() ? c->obs_frontend_get_current_profile()
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
void obs_frontend_set_current_profile(const char *profile)
|
||||
|
@ -200,91 +195,92 @@ void obs_frontend_set_current_profile(const char *profile)
|
|||
|
||||
void obs_frontend_streaming_start(void)
|
||||
{
|
||||
if (callbacks_valid()) c->obs_frontend_streaming_start();
|
||||
if (callbacks_valid())
|
||||
c->obs_frontend_streaming_start();
|
||||
}
|
||||
|
||||
void obs_frontend_streaming_stop(void)
|
||||
{
|
||||
if (callbacks_valid()) c->obs_frontend_streaming_stop();
|
||||
if (callbacks_valid())
|
||||
c->obs_frontend_streaming_stop();
|
||||
}
|
||||
|
||||
bool obs_frontend_streaming_active(void)
|
||||
{
|
||||
return !!callbacks_valid()
|
||||
? c->obs_frontend_streaming_active()
|
||||
: false;
|
||||
return !!callbacks_valid() ? c->obs_frontend_streaming_active() : false;
|
||||
}
|
||||
|
||||
void obs_frontend_recording_start(void)
|
||||
{
|
||||
if (callbacks_valid()) c->obs_frontend_recording_start();
|
||||
if (callbacks_valid())
|
||||
c->obs_frontend_recording_start();
|
||||
}
|
||||
|
||||
void obs_frontend_recording_stop(void)
|
||||
{
|
||||
if (callbacks_valid()) c->obs_frontend_recording_stop();
|
||||
if (callbacks_valid())
|
||||
c->obs_frontend_recording_stop();
|
||||
}
|
||||
|
||||
bool obs_frontend_recording_active(void)
|
||||
{
|
||||
return !!callbacks_valid()
|
||||
? c->obs_frontend_recording_active()
|
||||
: false;
|
||||
return !!callbacks_valid() ? c->obs_frontend_recording_active() : false;
|
||||
}
|
||||
|
||||
void obs_frontend_replay_buffer_start(void)
|
||||
{
|
||||
if (callbacks_valid()) c->obs_frontend_replay_buffer_start();
|
||||
if (callbacks_valid())
|
||||
c->obs_frontend_replay_buffer_start();
|
||||
}
|
||||
|
||||
void obs_frontend_replay_buffer_save(void)
|
||||
{
|
||||
if (callbacks_valid()) c->obs_frontend_replay_buffer_save();
|
||||
if (callbacks_valid())
|
||||
c->obs_frontend_replay_buffer_save();
|
||||
}
|
||||
|
||||
void obs_frontend_replay_buffer_stop(void)
|
||||
{
|
||||
if (callbacks_valid()) c->obs_frontend_replay_buffer_stop();
|
||||
if (callbacks_valid())
|
||||
c->obs_frontend_replay_buffer_stop();
|
||||
}
|
||||
|
||||
bool obs_frontend_replay_buffer_active(void)
|
||||
{
|
||||
return !!callbacks_valid()
|
||||
? c->obs_frontend_replay_buffer_active()
|
||||
: false;
|
||||
return !!callbacks_valid() ? c->obs_frontend_replay_buffer_active()
|
||||
: false;
|
||||
}
|
||||
|
||||
void *obs_frontend_add_tools_menu_qaction(const char *name)
|
||||
{
|
||||
return !!callbacks_valid()
|
||||
? c->obs_frontend_add_tools_menu_qaction(name)
|
||||
: nullptr;
|
||||
? c->obs_frontend_add_tools_menu_qaction(name)
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
void obs_frontend_add_tools_menu_item(const char *name,
|
||||
obs_frontend_cb callback, void *private_data)
|
||||
obs_frontend_cb callback,
|
||||
void *private_data)
|
||||
{
|
||||
if (callbacks_valid())
|
||||
c->obs_frontend_add_tools_menu_item(name, callback,
|
||||
private_data);
|
||||
private_data);
|
||||
}
|
||||
|
||||
void *obs_frontend_add_dock(void *dock)
|
||||
{
|
||||
return !!callbacks_valid()
|
||||
? c->obs_frontend_add_dock(dock)
|
||||
: nullptr;
|
||||
return !!callbacks_valid() ? c->obs_frontend_add_dock(dock) : nullptr;
|
||||
}
|
||||
|
||||
void obs_frontend_add_event_callback(obs_frontend_event_cb callback,
|
||||
void *private_data)
|
||||
void *private_data)
|
||||
{
|
||||
if (callbacks_valid())
|
||||
c->obs_frontend_add_event_callback(callback, private_data);
|
||||
}
|
||||
|
||||
void obs_frontend_remove_event_callback(obs_frontend_event_cb callback,
|
||||
void *private_data)
|
||||
void *private_data)
|
||||
{
|
||||
if (callbacks_valid())
|
||||
c->obs_frontend_remove_event_callback(callback, private_data);
|
||||
|
@ -292,37 +288,32 @@ void obs_frontend_remove_event_callback(obs_frontend_event_cb callback,
|
|||
|
||||
obs_output_t *obs_frontend_get_streaming_output(void)
|
||||
{
|
||||
return !!callbacks_valid()
|
||||
? c->obs_frontend_get_streaming_output()
|
||||
: nullptr;
|
||||
return !!callbacks_valid() ? c->obs_frontend_get_streaming_output()
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
obs_output_t *obs_frontend_get_recording_output(void)
|
||||
{
|
||||
return !!callbacks_valid()
|
||||
? c->obs_frontend_get_recording_output()
|
||||
: nullptr;
|
||||
return !!callbacks_valid() ? c->obs_frontend_get_recording_output()
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
obs_output_t *obs_frontend_get_replay_buffer_output(void)
|
||||
{
|
||||
return !!callbacks_valid()
|
||||
? c->obs_frontend_get_replay_buffer_output()
|
||||
: nullptr;
|
||||
return !!callbacks_valid() ? c->obs_frontend_get_replay_buffer_output()
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
config_t *obs_frontend_get_profile_config(void)
|
||||
{
|
||||
return !!callbacks_valid()
|
||||
? c->obs_frontend_get_profile_config()
|
||||
: nullptr;
|
||||
return !!callbacks_valid() ? c->obs_frontend_get_profile_config()
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
config_t *obs_frontend_get_global_config(void)
|
||||
{
|
||||
return !!callbacks_valid()
|
||||
? c->obs_frontend_get_global_config()
|
||||
: nullptr;
|
||||
return !!callbacks_valid() ? c->obs_frontend_get_global_config()
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
void obs_frontend_save(void)
|
||||
|
@ -344,28 +335,28 @@ void obs_frontend_defer_save_end(void)
|
|||
}
|
||||
|
||||
void obs_frontend_add_save_callback(obs_frontend_save_cb callback,
|
||||
void *private_data)
|
||||
void *private_data)
|
||||
{
|
||||
if (callbacks_valid())
|
||||
c->obs_frontend_add_save_callback(callback, private_data);
|
||||
}
|
||||
|
||||
void obs_frontend_remove_save_callback(obs_frontend_save_cb callback,
|
||||
void *private_data)
|
||||
void *private_data)
|
||||
{
|
||||
if (callbacks_valid())
|
||||
c->obs_frontend_remove_save_callback(callback, private_data);
|
||||
}
|
||||
|
||||
void obs_frontend_add_preload_callback(obs_frontend_save_cb callback,
|
||||
void *private_data)
|
||||
void *private_data)
|
||||
{
|
||||
if (callbacks_valid())
|
||||
c->obs_frontend_add_preload_callback(callback, private_data);
|
||||
}
|
||||
|
||||
void obs_frontend_remove_preload_callback(obs_frontend_save_cb callback,
|
||||
void *private_data)
|
||||
void *private_data)
|
||||
{
|
||||
if (callbacks_valid())
|
||||
c->obs_frontend_remove_preload_callback(callback, private_data);
|
||||
|
@ -389,11 +380,10 @@ void obs_frontend_set_streaming_service(obs_service_t *service)
|
|||
c->obs_frontend_set_streaming_service(service);
|
||||
}
|
||||
|
||||
obs_service_t* obs_frontend_get_streaming_service(void)
|
||||
obs_service_t *obs_frontend_get_streaming_service(void)
|
||||
{
|
||||
return !!callbacks_valid()
|
||||
? c->obs_frontend_get_streaming_service()
|
||||
: nullptr;
|
||||
return !!callbacks_valid() ? c->obs_frontend_get_streaming_service()
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
void obs_frontend_save_streaming_service(void)
|
||||
|
@ -405,8 +395,8 @@ void obs_frontend_save_streaming_service(void)
|
|||
bool obs_frontend_preview_program_mode_active(void)
|
||||
{
|
||||
return !!callbacks_valid()
|
||||
? c->obs_frontend_preview_program_mode_active()
|
||||
: false;
|
||||
? c->obs_frontend_preview_program_mode_active()
|
||||
: false;
|
||||
}
|
||||
|
||||
void obs_frontend_set_preview_program_mode(bool enable)
|
||||
|
@ -429,16 +419,13 @@ void obs_frontend_set_preview_enabled(bool enable)
|
|||
|
||||
bool obs_frontend_preview_enabled(void)
|
||||
{
|
||||
return !!callbacks_valid()
|
||||
? c->obs_frontend_preview_enabled()
|
||||
: false;
|
||||
return !!callbacks_valid() ? c->obs_frontend_preview_enabled() : false;
|
||||
}
|
||||
|
||||
obs_source_t *obs_frontend_get_current_preview_scene(void)
|
||||
{
|
||||
return !!callbacks_valid()
|
||||
? c->obs_frontend_get_current_preview_scene()
|
||||
: nullptr;
|
||||
return !!callbacks_valid() ? c->obs_frontend_get_current_preview_scene()
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
void obs_frontend_set_current_preview_scene(obs_source_t *scene)
|
||||
|
|
|
@ -43,7 +43,7 @@ enum obs_frontend_event {
|
|||
OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED,
|
||||
|
||||
OBS_FRONTEND_EVENT_SCENE_COLLECTION_CLEANUP,
|
||||
OBS_FRONTEND_EVENT_FINISHED_LOADING
|
||||
OBS_FRONTEND_EVENT_FINISHED_LOADING,
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
@ -51,11 +51,11 @@ enum obs_frontend_event {
|
|||
#ifndef SWIG
|
||||
|
||||
struct obs_frontend_source_list {
|
||||
DARRAY(obs_source_t*) sources;
|
||||
DARRAY(obs_source_t *) sources;
|
||||
};
|
||||
|
||||
static inline void obs_frontend_source_list_free(
|
||||
struct obs_frontend_source_list *source_list)
|
||||
static inline void
|
||||
obs_frontend_source_list_free(struct obs_frontend_source_list *source_list)
|
||||
{
|
||||
size_t num = source_list->sources.num;
|
||||
for (size_t i = 0; i < num; i++)
|
||||
|
@ -89,8 +89,8 @@ EXPORT void obs_frontend_get_scenes(struct obs_frontend_source_list *sources);
|
|||
EXPORT obs_source_t *obs_frontend_get_current_scene(void);
|
||||
EXPORT void obs_frontend_set_current_scene(obs_source_t *scene);
|
||||
|
||||
EXPORT void obs_frontend_get_transitions(
|
||||
struct obs_frontend_source_list *sources);
|
||||
EXPORT void
|
||||
obs_frontend_get_transitions(struct obs_frontend_source_list *sources);
|
||||
EXPORT obs_source_t *obs_frontend_get_current_transition(void);
|
||||
EXPORT void obs_frontend_set_current_transition(obs_source_t *transition);
|
||||
EXPORT int obs_frontend_get_transition_duration(void);
|
||||
|
@ -109,37 +109,38 @@ typedef void (*obs_frontend_cb)(void *private_data);
|
|||
|
||||
EXPORT void *obs_frontend_add_tools_menu_qaction(const char *name);
|
||||
EXPORT void obs_frontend_add_tools_menu_item(const char *name,
|
||||
obs_frontend_cb callback, void *private_data);
|
||||
obs_frontend_cb callback,
|
||||
void *private_data);
|
||||
|
||||
/* takes QDockWidget and returns QAction */
|
||||
EXPORT void *obs_frontend_add_dock(void *dock);
|
||||
|
||||
typedef void (*obs_frontend_event_cb)(enum obs_frontend_event event,
|
||||
void *private_data);
|
||||
void *private_data);
|
||||
|
||||
EXPORT void obs_frontend_add_event_callback(obs_frontend_event_cb callback,
|
||||
void *private_data);
|
||||
void *private_data);
|
||||
EXPORT void obs_frontend_remove_event_callback(obs_frontend_event_cb callback,
|
||||
void *private_data);
|
||||
void *private_data);
|
||||
|
||||
typedef void (*obs_frontend_save_cb)(obs_data_t *save_data, bool saving,
|
||||
void *private_data);
|
||||
void *private_data);
|
||||
|
||||
EXPORT void obs_frontend_add_save_callback(obs_frontend_save_cb callback,
|
||||
void *private_data);
|
||||
void *private_data);
|
||||
EXPORT void obs_frontend_remove_save_callback(obs_frontend_save_cb callback,
|
||||
void *private_data);
|
||||
void *private_data);
|
||||
|
||||
EXPORT void obs_frontend_add_preload_callback(obs_frontend_save_cb callback,
|
||||
void *private_data);
|
||||
void *private_data);
|
||||
EXPORT void obs_frontend_remove_preload_callback(obs_frontend_save_cb callback,
|
||||
void *private_data);
|
||||
void *private_data);
|
||||
|
||||
typedef bool (*obs_frontend_translate_ui_cb)(const char *text,
|
||||
const char **out);
|
||||
const char **out);
|
||||
|
||||
EXPORT void obs_frontend_push_ui_translation(
|
||||
obs_frontend_translate_ui_cb translate);
|
||||
EXPORT void
|
||||
obs_frontend_push_ui_translation(obs_frontend_translate_ui_cb translate);
|
||||
EXPORT void obs_frontend_pop_ui_translation(void);
|
||||
|
||||
#endif //!SWIG
|
||||
|
@ -169,7 +170,7 @@ EXPORT config_t *obs_frontend_get_profile_config(void);
|
|||
EXPORT config_t *obs_frontend_get_global_config(void);
|
||||
|
||||
EXPORT void obs_frontend_set_streaming_service(obs_service_t *service);
|
||||
EXPORT obs_service_t* obs_frontend_get_streaming_service(void);
|
||||
EXPORT obs_service_t *obs_frontend_get_streaming_service(void);
|
||||
EXPORT void obs_frontend_save_streaming_service(void);
|
||||
|
||||
EXPORT bool obs_frontend_preview_program_mode_active(void);
|
||||
|
|
|
@ -7,103 +7,111 @@
|
|||
|
||||
struct obs_frontend_callbacks {
|
||||
virtual ~obs_frontend_callbacks() {}
|
||||
virtual void *obs_frontend_get_main_window(void)=0;
|
||||
virtual void *obs_frontend_get_main_window_handle(void)=0;
|
||||
virtual void *obs_frontend_get_system_tray(void)=0;
|
||||
virtual void *obs_frontend_get_main_window(void) = 0;
|
||||
virtual void *obs_frontend_get_main_window_handle(void) = 0;
|
||||
virtual void *obs_frontend_get_system_tray(void) = 0;
|
||||
|
||||
virtual void obs_frontend_get_scenes(
|
||||
struct obs_frontend_source_list *sources)=0;
|
||||
virtual obs_source_t *obs_frontend_get_current_scene(void)=0;
|
||||
virtual void obs_frontend_set_current_scene(obs_source_t *scene)=0;
|
||||
virtual void
|
||||
obs_frontend_get_scenes(struct obs_frontend_source_list *sources) = 0;
|
||||
virtual obs_source_t *obs_frontend_get_current_scene(void) = 0;
|
||||
virtual void obs_frontend_set_current_scene(obs_source_t *scene) = 0;
|
||||
|
||||
virtual void obs_frontend_get_transitions(
|
||||
struct obs_frontend_source_list *sources)=0;
|
||||
virtual obs_source_t *obs_frontend_get_current_transition(void)=0;
|
||||
virtual void obs_frontend_set_current_transition(
|
||||
obs_source_t *transition)=0;
|
||||
virtual int obs_frontend_get_transition_duration(void)=0;
|
||||
virtual void obs_frontend_set_transition_duration(int duration)=0;
|
||||
struct obs_frontend_source_list *sources) = 0;
|
||||
virtual obs_source_t *obs_frontend_get_current_transition(void) = 0;
|
||||
virtual void
|
||||
obs_frontend_set_current_transition(obs_source_t *transition) = 0;
|
||||
virtual int obs_frontend_get_transition_duration(void) = 0;
|
||||
virtual void obs_frontend_set_transition_duration(int duration) = 0;
|
||||
|
||||
virtual void obs_frontend_get_scene_collections(
|
||||
std::vector<std::string> &strings)=0;
|
||||
virtual char *obs_frontend_get_current_scene_collection(void)=0;
|
||||
virtual void obs_frontend_set_current_scene_collection(
|
||||
const char *collection)=0;
|
||||
virtual bool obs_frontend_add_scene_collection(const char *name)=0;
|
||||
std::vector<std::string> &strings) = 0;
|
||||
virtual char *obs_frontend_get_current_scene_collection(void) = 0;
|
||||
virtual void
|
||||
obs_frontend_set_current_scene_collection(const char *collection) = 0;
|
||||
virtual bool obs_frontend_add_scene_collection(const char *name) = 0;
|
||||
|
||||
virtual void obs_frontend_get_profiles(
|
||||
std::vector<std::string> &strings)=0;
|
||||
virtual char *obs_frontend_get_current_profile(void)=0;
|
||||
virtual void obs_frontend_set_current_profile(const char *profile)=0;
|
||||
virtual void
|
||||
obs_frontend_get_profiles(std::vector<std::string> &strings) = 0;
|
||||
virtual char *obs_frontend_get_current_profile(void) = 0;
|
||||
virtual void obs_frontend_set_current_profile(const char *profile) = 0;
|
||||
|
||||
virtual void obs_frontend_streaming_start(void)=0;
|
||||
virtual void obs_frontend_streaming_stop(void)=0;
|
||||
virtual bool obs_frontend_streaming_active(void)=0;
|
||||
virtual void obs_frontend_streaming_start(void) = 0;
|
||||
virtual void obs_frontend_streaming_stop(void) = 0;
|
||||
virtual bool obs_frontend_streaming_active(void) = 0;
|
||||
|
||||
virtual void obs_frontend_recording_start(void)=0;
|
||||
virtual void obs_frontend_recording_stop(void)=0;
|
||||
virtual bool obs_frontend_recording_active(void)=0;
|
||||
virtual void obs_frontend_recording_start(void) = 0;
|
||||
virtual void obs_frontend_recording_stop(void) = 0;
|
||||
virtual bool obs_frontend_recording_active(void) = 0;
|
||||
|
||||
virtual void obs_frontend_replay_buffer_start(void)=0;
|
||||
virtual void obs_frontend_replay_buffer_start(void) = 0;
|
||||
virtual void obs_frontend_replay_buffer_save(void) = 0;
|
||||
virtual void obs_frontend_replay_buffer_stop(void)=0;
|
||||
virtual bool obs_frontend_replay_buffer_active(void)=0;
|
||||
virtual void obs_frontend_replay_buffer_stop(void) = 0;
|
||||
virtual bool obs_frontend_replay_buffer_active(void) = 0;
|
||||
|
||||
virtual void *obs_frontend_add_tools_menu_qaction(const char *name)=0;
|
||||
virtual void *obs_frontend_add_tools_menu_qaction(const char *name) = 0;
|
||||
virtual void obs_frontend_add_tools_menu_item(const char *name,
|
||||
obs_frontend_cb callback, void *private_data)=0;
|
||||
obs_frontend_cb callback,
|
||||
void *private_data) = 0;
|
||||
|
||||
virtual void *obs_frontend_add_dock(void *dock)=0;
|
||||
virtual void *obs_frontend_add_dock(void *dock) = 0;
|
||||
|
||||
virtual void obs_frontend_add_event_callback(
|
||||
obs_frontend_event_cb callback, void *private_data)=0;
|
||||
virtual void obs_frontend_remove_event_callback(
|
||||
obs_frontend_event_cb callback, void *private_data)=0;
|
||||
virtual void
|
||||
obs_frontend_add_event_callback(obs_frontend_event_cb callback,
|
||||
void *private_data) = 0;
|
||||
virtual void
|
||||
obs_frontend_remove_event_callback(obs_frontend_event_cb callback,
|
||||
void *private_data) = 0;
|
||||
|
||||
virtual obs_output_t *obs_frontend_get_streaming_output(void)=0;
|
||||
virtual obs_output_t *obs_frontend_get_recording_output(void)=0;
|
||||
virtual obs_output_t *obs_frontend_get_replay_buffer_output(void)=0;
|
||||
virtual obs_output_t *obs_frontend_get_streaming_output(void) = 0;
|
||||
virtual obs_output_t *obs_frontend_get_recording_output(void) = 0;
|
||||
virtual obs_output_t *obs_frontend_get_replay_buffer_output(void) = 0;
|
||||
|
||||
virtual config_t *obs_frontend_get_profile_config(void)=0;
|
||||
virtual config_t *obs_frontend_get_global_config(void)=0;
|
||||
virtual config_t *obs_frontend_get_profile_config(void) = 0;
|
||||
virtual config_t *obs_frontend_get_global_config(void) = 0;
|
||||
|
||||
virtual void obs_frontend_save(void) = 0;
|
||||
virtual void obs_frontend_defer_save_begin(void) = 0;
|
||||
virtual void obs_frontend_defer_save_end(void) = 0;
|
||||
virtual void obs_frontend_add_save_callback(
|
||||
obs_frontend_save_cb callback, void *private_data)=0;
|
||||
virtual void obs_frontend_remove_save_callback(
|
||||
obs_frontend_save_cb callback, void *private_data)=0;
|
||||
virtual void
|
||||
obs_frontend_add_save_callback(obs_frontend_save_cb callback,
|
||||
void *private_data) = 0;
|
||||
virtual void
|
||||
obs_frontend_remove_save_callback(obs_frontend_save_cb callback,
|
||||
void *private_data) = 0;
|
||||
|
||||
virtual void obs_frontend_add_preload_callback(
|
||||
obs_frontend_save_cb callback, void *private_data)=0;
|
||||
virtual void obs_frontend_remove_preload_callback(
|
||||
obs_frontend_save_cb callback, void *private_data)=0;
|
||||
virtual void
|
||||
obs_frontend_add_preload_callback(obs_frontend_save_cb callback,
|
||||
void *private_data) = 0;
|
||||
virtual void
|
||||
obs_frontend_remove_preload_callback(obs_frontend_save_cb callback,
|
||||
void *private_data) = 0;
|
||||
|
||||
virtual void obs_frontend_push_ui_translation(
|
||||
obs_frontend_translate_ui_cb translate)=0;
|
||||
virtual void obs_frontend_pop_ui_translation(void)=0;
|
||||
obs_frontend_translate_ui_cb translate) = 0;
|
||||
virtual void obs_frontend_pop_ui_translation(void) = 0;
|
||||
|
||||
virtual void obs_frontend_set_streaming_service(
|
||||
obs_service_t *service)=0;
|
||||
virtual obs_service_t *obs_frontend_get_streaming_service(void)=0;
|
||||
virtual void obs_frontend_save_streaming_service()=0;
|
||||
virtual void
|
||||
obs_frontend_set_streaming_service(obs_service_t *service) = 0;
|
||||
virtual obs_service_t *obs_frontend_get_streaming_service(void) = 0;
|
||||
virtual void obs_frontend_save_streaming_service() = 0;
|
||||
|
||||
virtual bool obs_frontend_preview_program_mode_active(void)=0;
|
||||
virtual void obs_frontend_set_preview_program_mode(bool enable)=0;
|
||||
virtual void obs_frontend_preview_program_trigger_transition(void)=0;
|
||||
virtual bool obs_frontend_preview_program_mode_active(void) = 0;
|
||||
virtual void obs_frontend_set_preview_program_mode(bool enable) = 0;
|
||||
virtual void obs_frontend_preview_program_trigger_transition(void) = 0;
|
||||
|
||||
virtual bool obs_frontend_preview_enabled(void)=0;
|
||||
virtual void obs_frontend_set_preview_enabled(bool enable)=0;
|
||||
virtual bool obs_frontend_preview_enabled(void) = 0;
|
||||
virtual void obs_frontend_set_preview_enabled(bool enable) = 0;
|
||||
|
||||
virtual obs_source_t *obs_frontend_get_current_preview_scene(void)=0;
|
||||
virtual void obs_frontend_set_current_preview_scene(obs_source_t *scene)=0;
|
||||
virtual obs_source_t *obs_frontend_get_current_preview_scene(void) = 0;
|
||||
virtual void
|
||||
obs_frontend_set_current_preview_scene(obs_source_t *scene) = 0;
|
||||
|
||||
virtual void on_load(obs_data_t *settings)=0;
|
||||
virtual void on_preload(obs_data_t *settings)=0;
|
||||
virtual void on_save(obs_data_t *settings)=0;
|
||||
virtual void on_event(enum obs_frontend_event event)=0;
|
||||
virtual void on_load(obs_data_t *settings) = 0;
|
||||
virtual void on_preload(obs_data_t *settings) = 0;
|
||||
virtual void on_save(obs_data_t *settings) = 0;
|
||||
virtual void on_event(enum obs_frontend_event event) = 0;
|
||||
};
|
||||
|
||||
EXPORT void obs_frontend_set_callbacks_internal(
|
||||
obs_frontend_callbacks *callbacks);
|
||||
EXPORT void
|
||||
obs_frontend_set_callbacks_internal(obs_frontend_callbacks *callbacks);
|
||||
|
|
|
@ -37,8 +37,8 @@ using namespace std;
|
|||
#include <util/windows/HRError.hpp>
|
||||
#include <util/windows/ComPtr.hpp>
|
||||
|
||||
static inline bool check_path(const char* data, const char *path,
|
||||
string &output)
|
||||
static inline bool check_path(const char *data, const char *path,
|
||||
string &output)
|
||||
{
|
||||
ostringstream str;
|
||||
str << path << data;
|
||||
|
@ -65,10 +65,10 @@ bool InitApplicationBundle()
|
|||
string GetDefaultVideoSavePath()
|
||||
{
|
||||
wchar_t path_utf16[MAX_PATH];
|
||||
char path_utf8[MAX_PATH] = {};
|
||||
char path_utf8[MAX_PATH] = {};
|
||||
|
||||
SHGetFolderPathW(NULL, CSIDL_MYVIDEO, NULL, SHGFP_TYPE_CURRENT,
|
||||
path_utf16);
|
||||
path_utf16);
|
||||
|
||||
os_wcs_to_utf8(path_utf16, wcslen(path_utf16), path_utf8, MAX_PATH);
|
||||
return string(path_utf8);
|
||||
|
@ -79,18 +79,18 @@ static vector<string> GetUserPreferredLocales()
|
|||
vector<string> result;
|
||||
|
||||
ULONG num, length = 0;
|
||||
if (!GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &num,
|
||||
nullptr, &length))
|
||||
if (!GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &num, nullptr,
|
||||
&length))
|
||||
return result;
|
||||
|
||||
vector<wchar_t> buffer(length);
|
||||
if (!GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &num,
|
||||
&buffer.front(), &length))
|
||||
&buffer.front(), &length))
|
||||
return result;
|
||||
|
||||
result.reserve(num);
|
||||
auto start = begin(buffer);
|
||||
auto end_ = end(buffer);
|
||||
auto end_ = end(buffer);
|
||||
decltype(start) separator;
|
||||
while ((separator = find(start, end_, 0)) != end_) {
|
||||
if (result.size() == num)
|
||||
|
@ -162,7 +162,7 @@ uint32_t GetWindowsVersion()
|
|||
|
||||
void SetAeroEnabled(bool enable)
|
||||
{
|
||||
static HRESULT (WINAPI *func)(UINT) = nullptr;
|
||||
static HRESULT(WINAPI * func)(UINT) = nullptr;
|
||||
static bool failed = false;
|
||||
|
||||
if (!func) {
|
||||
|
@ -176,8 +176,8 @@ void SetAeroEnabled(bool enable)
|
|||
return;
|
||||
}
|
||||
|
||||
func = reinterpret_cast<decltype(func)>(GetProcAddress(dwm,
|
||||
"DwmEnableComposition"));
|
||||
func = reinterpret_cast<decltype(func)>(
|
||||
GetProcAddress(dwm, "DwmEnableComposition"));
|
||||
if (!func) {
|
||||
failed = true;
|
||||
return;
|
||||
|
@ -197,7 +197,7 @@ void SetAlwaysOnTop(QWidget *window, bool enable)
|
|||
{
|
||||
HWND hwnd = (HWND)window->winId();
|
||||
SetWindowPos(hwnd, enable ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0,
|
||||
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
|
||||
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
|
||||
}
|
||||
|
||||
void SetProcessPriority(const char *priority)
|
||||
|
@ -208,11 +208,13 @@ void SetProcessPriority(const char *priority)
|
|||
if (strcmp(priority, "High") == 0)
|
||||
SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
|
||||
else if (strcmp(priority, "AboveNormal") == 0)
|
||||
SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS);
|
||||
SetPriorityClass(GetCurrentProcess(),
|
||||
ABOVE_NORMAL_PRIORITY_CLASS);
|
||||
else if (strcmp(priority, "Normal") == 0)
|
||||
SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
|
||||
else if (strcmp(priority, "BelowNormal") == 0)
|
||||
SetPriorityClass(GetCurrentProcess(), BELOW_NORMAL_PRIORITY_CLASS);
|
||||
SetPriorityClass(GetCurrentProcess(),
|
||||
BELOW_NORMAL_PRIORITY_CLASS);
|
||||
else if (strcmp(priority, "Idle") == 0)
|
||||
SetPriorityClass(GetCurrentProcess(), IDLE_PRIORITY_CLASS);
|
||||
}
|
||||
|
@ -227,16 +229,16 @@ void SetWin32DropStyle(QWidget *window)
|
|||
|
||||
bool DisableAudioDucking(bool disable)
|
||||
{
|
||||
ComPtr<IMMDeviceEnumerator> devEmum;
|
||||
ComPtr<IMMDevice> device;
|
||||
ComPtr<IMMDeviceEnumerator> devEmum;
|
||||
ComPtr<IMMDevice> device;
|
||||
ComPtr<IAudioSessionManager2> sessionManager2;
|
||||
ComPtr<IAudioSessionControl> sessionControl;
|
||||
ComPtr<IAudioSessionControl> sessionControl;
|
||||
ComPtr<IAudioSessionControl2> sessionControl2;
|
||||
|
||||
HRESULT result = CoCreateInstance(__uuidof(MMDeviceEnumerator),
|
||||
nullptr, CLSCTX_INPROC_SERVER,
|
||||
__uuidof(IMMDeviceEnumerator),
|
||||
(void **)&devEmum);
|
||||
HRESULT result = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr,
|
||||
CLSCTX_INPROC_SERVER,
|
||||
__uuidof(IMMDeviceEnumerator),
|
||||
(void **)&devEmum);
|
||||
if (FAILED(result))
|
||||
return false;
|
||||
|
||||
|
@ -245,13 +247,13 @@ bool DisableAudioDucking(bool disable)
|
|||
return false;
|
||||
|
||||
result = device->Activate(__uuidof(IAudioSessionManager2),
|
||||
CLSCTX_INPROC_SERVER, nullptr,
|
||||
(void **)&sessionManager2);
|
||||
CLSCTX_INPROC_SERVER, nullptr,
|
||||
(void **)&sessionManager2);
|
||||
if (FAILED(result))
|
||||
return false;
|
||||
|
||||
result = sessionManager2->GetAudioSessionControl(nullptr, 0,
|
||||
&sessionControl);
|
||||
&sessionControl);
|
||||
if (FAILED(result))
|
||||
return false;
|
||||
|
||||
|
|
|
@ -29,8 +29,8 @@
|
|||
#include "platform.hpp"
|
||||
using namespace std;
|
||||
|
||||
static inline bool check_path(const char* data, const char *path,
|
||||
string &output)
|
||||
static inline bool check_path(const char *data, const char *path,
|
||||
string &output)
|
||||
{
|
||||
ostringstream str;
|
||||
str << path << data;
|
||||
|
|
|
@ -48,6 +48,7 @@ struct RunOnceMutexData;
|
|||
|
||||
class RunOnceMutex {
|
||||
RunOnceMutexData *data = nullptr;
|
||||
|
||||
public:
|
||||
RunOnceMutex(RunOnceMutexData *data_) : data(data_) {}
|
||||
RunOnceMutex(const RunOnceMutex &rom) = delete;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -10,8 +10,7 @@ class OBSPropertiesView;
|
|||
class QLabel;
|
||||
|
||||
typedef obs_properties_t *(*PropertiesReloadCallback)(void *obj);
|
||||
typedef void (*PropertiesUpdateCallback)(void *obj,
|
||||
obs_data_t *settings);
|
||||
typedef void (*PropertiesUpdateCallback)(void *obj, obs_data_t *settings);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
|
@ -22,8 +21,8 @@ class WidgetInfo : public QObject {
|
|||
|
||||
private:
|
||||
OBSPropertiesView *view;
|
||||
obs_property_t *property;
|
||||
QWidget *widget;
|
||||
obs_property_t *property;
|
||||
QWidget *widget;
|
||||
|
||||
void BoolChanged(const char *setting);
|
||||
void IntChanged(const char *setting);
|
||||
|
@ -41,9 +40,10 @@ private:
|
|||
|
||||
public:
|
||||
inline WidgetInfo(OBSPropertiesView *view_, obs_property_t *prop,
|
||||
QWidget *widget_)
|
||||
QWidget *widget_)
|
||||
: view(view_), property(prop), widget(widget_)
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
public slots:
|
||||
|
||||
|
@ -72,37 +72,38 @@ class OBSPropertiesView : public VScrollArea {
|
|||
std::unique_ptr<obs_properties_t, properties_delete_t>;
|
||||
|
||||
private:
|
||||
QWidget *widget = nullptr;
|
||||
properties_t properties;
|
||||
OBSData settings;
|
||||
void *obj = nullptr;
|
||||
std::string type;
|
||||
PropertiesReloadCallback reloadCallback;
|
||||
PropertiesUpdateCallback callback = nullptr;
|
||||
int minSize;
|
||||
QWidget *widget = nullptr;
|
||||
properties_t properties;
|
||||
OBSData settings;
|
||||
void *obj = nullptr;
|
||||
std::string type;
|
||||
PropertiesReloadCallback reloadCallback;
|
||||
PropertiesUpdateCallback callback = nullptr;
|
||||
int minSize;
|
||||
std::vector<std::unique_ptr<WidgetInfo>> children;
|
||||
std::string lastFocused;
|
||||
QWidget *lastWidget = nullptr;
|
||||
bool deferUpdate;
|
||||
std::string lastFocused;
|
||||
QWidget *lastWidget = nullptr;
|
||||
bool deferUpdate;
|
||||
|
||||
QWidget *NewWidget(obs_property_t *prop, QWidget *widget,
|
||||
const char *signal);
|
||||
const char *signal);
|
||||
|
||||
QWidget *AddCheckbox(obs_property_t *prop);
|
||||
QWidget *AddText(obs_property_t *prop, QFormLayout *layout,
|
||||
QLabel *&label);
|
||||
QLabel *&label);
|
||||
void AddPath(obs_property_t *prop, QFormLayout *layout, QLabel **label);
|
||||
void AddInt(obs_property_t *prop, QFormLayout *layout, QLabel **label);
|
||||
void AddFloat(obs_property_t *prop, QFormLayout *layout,
|
||||
QLabel**label);
|
||||
QLabel **label);
|
||||
QWidget *AddList(obs_property_t *prop, bool &warning);
|
||||
void AddEditableList(obs_property_t *prop, QFormLayout *layout,
|
||||
QLabel *&label);
|
||||
QLabel *&label);
|
||||
QWidget *AddButton(obs_property_t *prop);
|
||||
void AddColor(obs_property_t *prop, QFormLayout *layout, QLabel *&label);
|
||||
void AddColor(obs_property_t *prop, QFormLayout *layout,
|
||||
QLabel *&label);
|
||||
void AddFont(obs_property_t *prop, QFormLayout *layout, QLabel *&label);
|
||||
void AddFrameRate(obs_property_t *prop, bool &warning,
|
||||
QFormLayout *layout, QLabel *&label);
|
||||
QFormLayout *layout, QLabel *&label);
|
||||
|
||||
void AddGroup(obs_property_t *prop, QFormLayout *layout);
|
||||
|
||||
|
@ -125,15 +126,14 @@ signals:
|
|||
|
||||
public:
|
||||
OBSPropertiesView(OBSData settings, void *obj,
|
||||
PropertiesReloadCallback reloadCallback,
|
||||
PropertiesUpdateCallback callback,
|
||||
int minSize = 0);
|
||||
PropertiesReloadCallback reloadCallback,
|
||||
PropertiesUpdateCallback callback, int minSize = 0);
|
||||
OBSPropertiesView(OBSData settings, const char *type,
|
||||
PropertiesReloadCallback reloadCallback,
|
||||
int minSize = 0);
|
||||
PropertiesReloadCallback reloadCallback,
|
||||
int minSize = 0);
|
||||
|
||||
inline obs_data_t *GetSettings() const {return settings;}
|
||||
inline obs_data_t *GetSettings() const { return settings; }
|
||||
|
||||
inline void UpdateSettings() {callback(obj, settings);}
|
||||
inline bool DeferUpdate() const {return deferUpdate;}
|
||||
inline void UpdateSettings() { callback(obj, settings); }
|
||||
inline bool DeferUpdate() const { return deferUpdate; }
|
||||
};
|
||||
|
|
|
@ -15,13 +15,13 @@
|
|||
#endif
|
||||
|
||||
static bool operator!=(const media_frames_per_second &a,
|
||||
const media_frames_per_second &b)
|
||||
const media_frames_per_second &b)
|
||||
{
|
||||
return a.numerator != b.numerator || a.denominator != b.denominator;
|
||||
}
|
||||
|
||||
static bool operator==(const media_frames_per_second &a,
|
||||
const media_frames_per_second &b)
|
||||
const media_frames_per_second &b)
|
||||
{
|
||||
return !(a != b);
|
||||
}
|
||||
|
@ -36,27 +36,27 @@ class OBSFrameRatePropertyWidget : public QWidget {
|
|||
public:
|
||||
frame_rate_ranges_t fps_ranges;
|
||||
|
||||
QComboBox *modeSelect = nullptr;
|
||||
QStackedWidget *modeDisplay = nullptr;
|
||||
QComboBox *modeSelect = nullptr;
|
||||
QStackedWidget *modeDisplay = nullptr;
|
||||
|
||||
QWidget *labels = nullptr;
|
||||
QLabel *currentFPS = nullptr;
|
||||
QLabel *timePerFrame = nullptr;
|
||||
QLabel *minLabel = nullptr;
|
||||
QLabel *maxLabel = nullptr;
|
||||
QWidget *labels = nullptr;
|
||||
QLabel *currentFPS = nullptr;
|
||||
QLabel *timePerFrame = nullptr;
|
||||
QLabel *minLabel = nullptr;
|
||||
QLabel *maxLabel = nullptr;
|
||||
|
||||
QComboBox *simpleFPS = nullptr;
|
||||
QComboBox *simpleFPS = nullptr;
|
||||
|
||||
QComboBox *fpsRange = nullptr;
|
||||
QSpinBox *numEdit = nullptr;
|
||||
QSpinBox *denEdit = nullptr;
|
||||
QComboBox *fpsRange = nullptr;
|
||||
QSpinBox *numEdit = nullptr;
|
||||
QSpinBox *denEdit = nullptr;
|
||||
|
||||
bool updating = false;
|
||||
bool updating = false;
|
||||
|
||||
const char *name = nullptr;
|
||||
obs_data_t *settings = nullptr;
|
||||
const char *name = nullptr;
|
||||
obs_data_t *settings = nullptr;
|
||||
|
||||
QLabel *warningLabel = nullptr;
|
||||
QLabel *warningLabel = nullptr;
|
||||
|
||||
OBSFrameRatePropertyWidget() = default;
|
||||
};
|
||||
|
|
|
@ -8,23 +8,18 @@
|
|||
|
||||
static inline long long color_to_int(QColor color)
|
||||
{
|
||||
auto shift = [&](unsigned val, int shift)
|
||||
{
|
||||
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);
|
||||
return shift(color.red(), 0) | shift(color.green(), 8) |
|
||||
shift(color.blue(), 16) | shift(color.alpha(), 24);
|
||||
}
|
||||
|
||||
static inline QColor rgba_to_color(uint32_t rgba)
|
||||
{
|
||||
return QColor::fromRgb(rgba & 0xFF,
|
||||
(rgba >> 8) & 0xFF,
|
||||
(rgba >> 16) & 0xFF,
|
||||
(rgba >> 24) & 0xFF);
|
||||
return QColor::fromRgb(rgba & 0xFF, (rgba >> 8) & 0xFF,
|
||||
(rgba >> 16) & 0xFF, (rgba >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
OBSQTDisplay::OBSQTDisplay(QWidget *parent, Qt::WindowFlags flags)
|
||||
|
@ -37,8 +32,7 @@ OBSQTDisplay::OBSQTDisplay(QWidget *parent, Qt::WindowFlags flags)
|
|||
setAttribute(Qt::WA_DontCreateNativeAncestors);
|
||||
setAttribute(Qt::WA_NativeWindow);
|
||||
|
||||
auto windowVisible = [this] (bool visible)
|
||||
{
|
||||
auto windowVisible = [this](bool visible) {
|
||||
if (!visible)
|
||||
return;
|
||||
|
||||
|
@ -46,12 +40,12 @@ OBSQTDisplay::OBSQTDisplay(QWidget *parent, Qt::WindowFlags flags)
|
|||
CreateDisplay();
|
||||
} else {
|
||||
QSize size = GetPixelSize(this);
|
||||
obs_display_resize(display, size.width(), size.height());
|
||||
obs_display_resize(display, size.width(),
|
||||
size.height());
|
||||
}
|
||||
};
|
||||
|
||||
auto sizeChanged = [this] (QScreen*)
|
||||
{
|
||||
auto sizeChanged = [this](QScreen *) {
|
||||
CreateDisplay();
|
||||
|
||||
QSize size = GetPixelSize(this);
|
||||
|
@ -89,11 +83,11 @@ void OBSQTDisplay::CreateDisplay()
|
|||
|
||||
QSize size = GetPixelSize(this);
|
||||
|
||||
gs_init_data info = {};
|
||||
info.cx = size.width();
|
||||
info.cy = size.height();
|
||||
info.format = GS_RGBA;
|
||||
info.zsformat = GS_ZS_NONE;
|
||||
gs_init_data info = {};
|
||||
info.cx = size.width();
|
||||
info.cy = size.height();
|
||||
info.format = GS_RGBA;
|
||||
info.zsformat = GS_ZS_NONE;
|
||||
|
||||
QTToGSWindow(winId(), info.window);
|
||||
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
|
||||
class OBSQTDisplay : public QWidget {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QColor displayBackgroundColor MEMBER backgroundColor
|
||||
READ GetDisplayBackgroundColor
|
||||
WRITE SetDisplayBackgroundColor)
|
||||
Q_PROPERTY(QColor displayBackgroundColor MEMBER backgroundColor READ
|
||||
GetDisplayBackgroundColor WRITE
|
||||
SetDisplayBackgroundColor)
|
||||
|
||||
OBSDisplay display;
|
||||
|
||||
|
@ -24,11 +24,11 @@ signals:
|
|||
|
||||
public:
|
||||
OBSQTDisplay(QWidget *parent = nullptr,
|
||||
Qt::WindowFlags flags = nullptr);
|
||||
Qt::WindowFlags flags = nullptr);
|
||||
|
||||
virtual QPaintEngine *paintEngine() const override;
|
||||
|
||||
inline obs_display_t *GetDisplay() const {return display;}
|
||||
inline obs_display_t *GetDisplay() const { return display; }
|
||||
|
||||
uint32_t backgroundColor = GREY_COLOR_BACKGROUND;
|
||||
|
||||
|
|
|
@ -45,20 +45,17 @@ void OBSErrorBox(QWidget *parent, const char *msg, ...)
|
|||
va_end(args);
|
||||
}
|
||||
|
||||
QMessageBox::StandardButton OBSMessageBox::question(
|
||||
QWidget *parent,
|
||||
const QString &title,
|
||||
const QString &text,
|
||||
QMessageBox::StandardButtons buttons,
|
||||
QMessageBox::StandardButton defaultButton)
|
||||
QMessageBox::StandardButton
|
||||
OBSMessageBox::question(QWidget *parent, const QString &title,
|
||||
const QString &text,
|
||||
QMessageBox::StandardButtons buttons,
|
||||
QMessageBox::StandardButton defaultButton)
|
||||
{
|
||||
QMessageBox mb(QMessageBox::Question,
|
||||
title, text, buttons,
|
||||
parent);
|
||||
QMessageBox mb(QMessageBox::Question, title, text, buttons, parent);
|
||||
mb.setDefaultButton(defaultButton);
|
||||
if (buttons & QMessageBox::Ok) \
|
||||
if (buttons & QMessageBox::Ok)
|
||||
mb.setButtonText(QMessageBox::Ok, QTStr("OK"));
|
||||
#define translate_button(x) \
|
||||
#define translate_button(x) \
|
||||
if (buttons & QMessageBox::x) \
|
||||
mb.setButtonText(QMessageBox::x, QTStr(#x));
|
||||
translate_button(Open);
|
||||
|
@ -78,41 +75,31 @@ QMessageBox::StandardButton OBSMessageBox::question(
|
|||
return (QMessageBox::StandardButton)mb.exec();
|
||||
}
|
||||
|
||||
void OBSMessageBox::information(
|
||||
QWidget *parent,
|
||||
const QString &title,
|
||||
const QString &text)
|
||||
void OBSMessageBox::information(QWidget *parent, const QString &title,
|
||||
const QString &text)
|
||||
{
|
||||
QMessageBox mb(QMessageBox::Information,
|
||||
title, text, QMessageBox::Ok,
|
||||
parent);
|
||||
QMessageBox mb(QMessageBox::Information, title, text, QMessageBox::Ok,
|
||||
parent);
|
||||
mb.setButtonText(QMessageBox::Ok, QTStr("OK"));
|
||||
mb.exec();
|
||||
}
|
||||
|
||||
void OBSMessageBox::warning(
|
||||
QWidget *parent,
|
||||
const QString &title,
|
||||
const QString &text,
|
||||
bool enableRichText)
|
||||
void OBSMessageBox::warning(QWidget *parent, const QString &title,
|
||||
const QString &text, bool enableRichText)
|
||||
{
|
||||
QMessageBox mb(QMessageBox::Warning,
|
||||
title, text, QMessageBox::Ok,
|
||||
parent);
|
||||
QMessageBox mb(QMessageBox::Warning, title, text, QMessageBox::Ok,
|
||||
parent);
|
||||
if (enableRichText)
|
||||
mb.setTextFormat(Qt::RichText);
|
||||
mb.setButtonText(QMessageBox::Ok, QTStr("OK"));
|
||||
mb.exec();
|
||||
}
|
||||
|
||||
void OBSMessageBox::critical(
|
||||
QWidget *parent,
|
||||
const QString &title,
|
||||
const QString &text)
|
||||
void OBSMessageBox::critical(QWidget *parent, const QString &title,
|
||||
const QString &text)
|
||||
{
|
||||
QMessageBox mb(QMessageBox::Critical,
|
||||
title, text, QMessageBox::Ok,
|
||||
parent);
|
||||
QMessageBox mb(QMessageBox::Critical, title, text, QMessageBox::Ok,
|
||||
parent);
|
||||
mb.setButtonText(QMessageBox::Ok, QTStr("OK"));
|
||||
mb.exec();
|
||||
}
|
||||
|
@ -156,13 +143,13 @@ uint32_t TranslateQtKeyboardEventModifiers(Qt::KeyboardModifiers mods)
|
|||
}
|
||||
|
||||
QDataStream &operator<<(QDataStream &out,
|
||||
const std::vector<std::shared_ptr<OBSSignal>> &)
|
||||
const std::vector<std::shared_ptr<OBSSignal>> &)
|
||||
{
|
||||
return out;
|
||||
}
|
||||
|
||||
QDataStream &operator>>(QDataStream &in,
|
||||
std::vector<std::shared_ptr<OBSSignal>> &)
|
||||
std::vector<std::shared_ptr<OBSSignal>> &)
|
||||
{
|
||||
return in;
|
||||
}
|
||||
|
@ -186,7 +173,7 @@ QDataStream &operator>>(QDataStream &in, OBSScene &scene)
|
|||
|
||||
QDataStream &operator<<(QDataStream &out, const OBSSceneItem &si)
|
||||
{
|
||||
obs_scene_t *scene = obs_sceneitem_get_scene(si);
|
||||
obs_scene_t *scene = obs_sceneitem_get_scene(si);
|
||||
obs_source_t *source = obs_sceneitem_get_source(si);
|
||||
return out << QString(obs_source_get_name(obs_scene_get_source(scene)))
|
||||
<< QString(obs_source_get_name(source));
|
||||
|
@ -234,15 +221,12 @@ void DeleteLayout(QLayout *layout)
|
|||
|
||||
class QuickThread : public QThread {
|
||||
public:
|
||||
explicit inline QuickThread(std::function<void()> func_)
|
||||
: func(func_)
|
||||
{}
|
||||
explicit inline QuickThread(std::function<void()> func_) : func(func_)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void run() override
|
||||
{
|
||||
func();
|
||||
}
|
||||
virtual void run() override { func(); }
|
||||
|
||||
std::function<void()> func;
|
||||
};
|
||||
|
@ -258,11 +242,10 @@ void ExecuteFuncSafeBlock(std::function<void()> func)
|
|||
{
|
||||
QEventLoop eventLoop;
|
||||
|
||||
auto wait = [&] ()
|
||||
{
|
||||
auto wait = [&]() {
|
||||
func();
|
||||
QMetaObject::invokeMethod(&eventLoop, "quit",
|
||||
Qt::QueuedConnection);
|
||||
Qt::QueuedConnection);
|
||||
};
|
||||
|
||||
os_atomic_inc_long(&insideEventLoop);
|
||||
|
@ -273,10 +256,8 @@ void ExecuteFuncSafeBlock(std::function<void()> func)
|
|||
os_atomic_dec_long(&insideEventLoop);
|
||||
}
|
||||
|
||||
void ExecuteFuncSafeBlockMsgBox(
|
||||
std::function<void()> func,
|
||||
const QString &title,
|
||||
const QString &text)
|
||||
void ExecuteFuncSafeBlockMsgBox(std::function<void()> func,
|
||||
const QString &title, const QString &text)
|
||||
{
|
||||
QMessageBox dlg;
|
||||
dlg.setWindowFlags(dlg.windowFlags() & ~Qt::WindowCloseButtonHint);
|
||||
|
@ -284,8 +265,7 @@ void ExecuteFuncSafeBlockMsgBox(
|
|||
dlg.setText(text);
|
||||
dlg.setStandardButtons(0);
|
||||
|
||||
auto wait = [&] ()
|
||||
{
|
||||
auto wait = [&]() {
|
||||
func();
|
||||
QMetaObject::invokeMethod(&dlg, "accept", Qt::QueuedConnection);
|
||||
};
|
||||
|
@ -305,10 +285,8 @@ void EnableThreadedMessageBoxes(bool enable)
|
|||
enable_message_boxes = enable;
|
||||
}
|
||||
|
||||
void ExecThreadedWithoutBlocking(
|
||||
std::function<void()> func,
|
||||
const QString &title,
|
||||
const QString &text)
|
||||
void ExecThreadedWithoutBlocking(std::function<void()> func,
|
||||
const QString &title, const QString &text)
|
||||
{
|
||||
if (!enable_message_boxes)
|
||||
ExecuteFuncSafeBlock(func);
|
||||
|
|
|
@ -38,25 +38,19 @@ struct gs_window;
|
|||
|
||||
class OBSMessageBox {
|
||||
public:
|
||||
static QMessageBox::StandardButton question(
|
||||
QWidget *parent,
|
||||
const QString &title,
|
||||
const QString &text,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::StandardButtons( QMessageBox::Yes | QMessageBox::No ),
|
||||
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
|
||||
static void information(
|
||||
QWidget *parent,
|
||||
const QString &title,
|
||||
const QString &text);
|
||||
static void warning(
|
||||
QWidget *parent,
|
||||
const QString &title,
|
||||
const QString &text,
|
||||
bool enableRichText = false);
|
||||
static void critical(
|
||||
QWidget *parent,
|
||||
const QString &title,
|
||||
const QString &text);
|
||||
static QMessageBox::StandardButton
|
||||
question(QWidget *parent, const QString &title, const QString &text,
|
||||
QMessageBox::StandardButtons buttons =
|
||||
QMessageBox::StandardButtons(QMessageBox::Yes |
|
||||
QMessageBox::No),
|
||||
QMessageBox::StandardButton defaultButton =
|
||||
QMessageBox::NoButton);
|
||||
static void information(QWidget *parent, const QString &title,
|
||||
const QString &text);
|
||||
static void warning(QWidget *parent, const QString &title,
|
||||
const QString &text, bool enableRichText = false);
|
||||
static void critical(QWidget *parent, const QString &title,
|
||||
const QString &text);
|
||||
};
|
||||
|
||||
void OBSErrorBox(QWidget *parent, const char *msg, ...);
|
||||
|
@ -65,10 +59,11 @@ void QTToGSWindow(WId windowId, gs_window &gswindow);
|
|||
|
||||
uint32_t TranslateQtKeyboardEventModifiers(Qt::KeyboardModifiers mods);
|
||||
|
||||
QDataStream &operator<<(QDataStream &out,
|
||||
const std::vector<std::shared_ptr<OBSSignal>> &signal_vec);
|
||||
QDataStream &
|
||||
operator<<(QDataStream &out,
|
||||
const std::vector<std::shared_ptr<OBSSignal>> &signal_vec);
|
||||
QDataStream &operator>>(QDataStream &in,
|
||||
std::vector<std::shared_ptr<OBSSignal>> &signal_vec);
|
||||
std::vector<std::shared_ptr<OBSSignal>> &signal_vec);
|
||||
QDataStream &operator<<(QDataStream &out, const OBSScene &scene);
|
||||
QDataStream &operator>>(QDataStream &in, OBSScene &scene);
|
||||
QDataStream &operator<<(QDataStream &out, const OBSSceneItem &si);
|
||||
|
@ -77,18 +72,14 @@ QDataStream &operator>>(QDataStream &in, OBSSceneItem &si);
|
|||
QThread *CreateQThread(std::function<void()> func);
|
||||
|
||||
void ExecuteFuncSafeBlock(std::function<void()> func);
|
||||
void ExecuteFuncSafeBlockMsgBox(
|
||||
std::function<void()> func,
|
||||
const QString &title,
|
||||
const QString &text);
|
||||
void ExecuteFuncSafeBlockMsgBox(std::function<void()> func,
|
||||
const QString &title, const QString &text);
|
||||
|
||||
/* allows executing without message boxes if starting up, otherwise with a
|
||||
* message box */
|
||||
void EnableThreadedMessageBoxes(bool enable);
|
||||
void ExecThreadedWithoutBlocking(
|
||||
std::function<void()> func,
|
||||
const QString &title,
|
||||
const QString &text);
|
||||
void ExecThreadedWithoutBlocking(std::function<void()> func,
|
||||
const QString &title, const QString &text);
|
||||
|
||||
class SignalBlocker {
|
||||
QWidget *widget;
|
||||
|
@ -100,10 +91,7 @@ public:
|
|||
blocked = widget->blockSignals(true);
|
||||
}
|
||||
|
||||
inline ~SignalBlocker()
|
||||
{
|
||||
widget->blockSignals(blocked);
|
||||
}
|
||||
inline ~SignalBlocker() { widget->blockSignals(blocked); }
|
||||
};
|
||||
|
||||
void DeleteLayout(QLayout *layout);
|
||||
|
@ -111,6 +99,6 @@ void DeleteLayout(QLayout *layout);
|
|||
static inline Qt::ConnectionType WaitConnection()
|
||||
{
|
||||
return QThread::currentThread() == qApp->thread()
|
||||
? Qt::DirectConnection
|
||||
: Qt::BlockingQueuedConnection;
|
||||
? Qt::DirectConnection
|
||||
: Qt::BlockingQueuedConnection;
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
static auto curl_deleter = [] (CURL *curl) {curl_easy_cleanup(curl);};
|
||||
static auto curl_deleter = [](CURL *curl) { curl_easy_cleanup(curl); };
|
||||
using Curl = unique_ptr<CURL, decltype(curl_deleter)>;
|
||||
|
||||
static size_t string_write(char *ptr, size_t size, size_t nmemb, string &str)
|
||||
|
@ -53,12 +53,11 @@ void RemoteTextThread::run()
|
|||
struct curl_slist *header = nullptr;
|
||||
string str;
|
||||
|
||||
header = curl_slist_append(header,
|
||||
versionString.c_str());
|
||||
header = curl_slist_append(header, versionString.c_str());
|
||||
|
||||
if (!contentTypeString.empty()) {
|
||||
header = curl_slist_append(header,
|
||||
contentTypeString.c_str());
|
||||
contentTypeString.c_str());
|
||||
}
|
||||
|
||||
for (std::string &h : extraHeaders)
|
||||
|
@ -66,18 +65,15 @@ void RemoteTextThread::run()
|
|||
|
||||
curl_easy_setopt(curl.get(), CURLOPT_URL, url.c_str());
|
||||
curl_easy_setopt(curl.get(), CURLOPT_ACCEPT_ENCODING, "");
|
||||
curl_easy_setopt(curl.get(), CURLOPT_HTTPHEADER,
|
||||
header);
|
||||
curl_easy_setopt(curl.get(), CURLOPT_ERRORBUFFER,
|
||||
error);
|
||||
curl_easy_setopt(curl.get(), CURLOPT_HTTPHEADER, header);
|
||||
curl_easy_setopt(curl.get(), CURLOPT_ERRORBUFFER, error);
|
||||
curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION,
|
||||
string_write);
|
||||
curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA,
|
||||
&str);
|
||||
string_write);
|
||||
curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, &str);
|
||||
|
||||
if (timeoutSec)
|
||||
curl_easy_setopt(curl.get(), CURLOPT_TIMEOUT,
|
||||
timeoutSec);
|
||||
timeoutSec);
|
||||
|
||||
#if LIBCURL_VERSION_NUM >= 0x072400
|
||||
// A lot of servers don't yet support ALPN
|
||||
|
@ -86,7 +82,7 @@ void RemoteTextThread::run()
|
|||
|
||||
if (!postData.empty()) {
|
||||
curl_easy_setopt(curl.get(), CURLOPT_POSTFIELDS,
|
||||
postData.c_str());
|
||||
postData.c_str());
|
||||
}
|
||||
|
||||
code = curl_easy_perform(curl.get());
|
||||
|
@ -101,7 +97,7 @@ void RemoteTextThread::run()
|
|||
}
|
||||
|
||||
static size_t header_write(char *ptr, size_t size, size_t nmemb,
|
||||
vector<string> &list)
|
||||
vector<string> &list)
|
||||
{
|
||||
string str;
|
||||
|
||||
|
@ -118,16 +114,10 @@ static size_t header_write(char *ptr, size_t size, size_t nmemb,
|
|||
return total;
|
||||
}
|
||||
|
||||
bool GetRemoteFile(
|
||||
const char *url,
|
||||
std::string &str,
|
||||
std::string &error,
|
||||
long *responseCode,
|
||||
const char *contentType,
|
||||
const char *postData,
|
||||
std::vector<std::string> extraHeaders,
|
||||
std::string *signature,
|
||||
int timeoutSec)
|
||||
bool GetRemoteFile(const char *url, std::string &str, std::string &error,
|
||||
long *responseCode, const char *contentType,
|
||||
const char *postData, std::vector<std::string> extraHeaders,
|
||||
std::string *signature, int timeoutSec)
|
||||
{
|
||||
vector<string> header_in_list;
|
||||
char error_in[CURL_ERROR_SIZE];
|
||||
|
@ -148,12 +138,11 @@ bool GetRemoteFile(
|
|||
if (curl) {
|
||||
struct curl_slist *header = nullptr;
|
||||
|
||||
header = curl_slist_append(header,
|
||||
versionString.c_str());
|
||||
header = curl_slist_append(header, versionString.c_str());
|
||||
|
||||
if (!contentTypeString.empty()) {
|
||||
header = curl_slist_append(header,
|
||||
contentTypeString.c_str());
|
||||
contentTypeString.c_str());
|
||||
}
|
||||
|
||||
for (std::string &h : extraHeaders)
|
||||
|
@ -161,24 +150,21 @@ bool GetRemoteFile(
|
|||
|
||||
curl_easy_setopt(curl.get(), CURLOPT_URL, url);
|
||||
curl_easy_setopt(curl.get(), CURLOPT_ACCEPT_ENCODING, "");
|
||||
curl_easy_setopt(curl.get(), CURLOPT_HTTPHEADER,
|
||||
header);
|
||||
curl_easy_setopt(curl.get(), CURLOPT_ERRORBUFFER,
|
||||
error_in);
|
||||
curl_easy_setopt(curl.get(), CURLOPT_HTTPHEADER, header);
|
||||
curl_easy_setopt(curl.get(), CURLOPT_ERRORBUFFER, error_in);
|
||||
curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION,
|
||||
string_write);
|
||||
curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA,
|
||||
&str);
|
||||
string_write);
|
||||
curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, &str);
|
||||
if (signature) {
|
||||
curl_easy_setopt(curl.get(), CURLOPT_HEADERFUNCTION,
|
||||
header_write);
|
||||
header_write);
|
||||
curl_easy_setopt(curl.get(), CURLOPT_HEADERDATA,
|
||||
&header_in_list);
|
||||
&header_in_list);
|
||||
}
|
||||
|
||||
if (timeoutSec)
|
||||
curl_easy_setopt(curl.get(), CURLOPT_TIMEOUT,
|
||||
timeoutSec);
|
||||
timeoutSec);
|
||||
|
||||
#if LIBCURL_VERSION_NUM >= 0x072400
|
||||
// A lot of servers don't yet support ALPN
|
||||
|
@ -187,13 +173,13 @@ bool GetRemoteFile(
|
|||
|
||||
if (postData) {
|
||||
curl_easy_setopt(curl.get(), CURLOPT_POSTFIELDS,
|
||||
postData);
|
||||
postData);
|
||||
}
|
||||
|
||||
code = curl_easy_perform(curl.get());
|
||||
if (responseCode)
|
||||
curl_easy_getinfo(curl.get(), CURLINFO_RESPONSE_CODE,
|
||||
responseCode);
|
||||
responseCode);
|
||||
|
||||
if (code != CURLE_OK) {
|
||||
error = error_in;
|
||||
|
|
|
@ -38,38 +38,34 @@ signals:
|
|||
void Result(const QString &text, const QString &error);
|
||||
|
||||
public:
|
||||
inline RemoteTextThread(
|
||||
std::string url_,
|
||||
std::string contentType_ = std::string(),
|
||||
std::string postData_ = std::string(),
|
||||
int timeoutSec_ = 0)
|
||||
: url (url_),
|
||||
contentType (contentType_),
|
||||
postData (postData_),
|
||||
timeoutSec (timeoutSec_)
|
||||
{}
|
||||
inline RemoteTextThread(std::string url_,
|
||||
std::string contentType_ = std::string(),
|
||||
std::string postData_ = std::string(),
|
||||
int timeoutSec_ = 0)
|
||||
: url(url_),
|
||||
contentType(contentType_),
|
||||
postData(postData_),
|
||||
timeoutSec(timeoutSec_)
|
||||
{
|
||||
}
|
||||
|
||||
inline RemoteTextThread(
|
||||
std::string url_,
|
||||
std::vector<std::string> &&extraHeaders_,
|
||||
std::string contentType_ = std::string(),
|
||||
std::string postData_ = std::string(),
|
||||
int timeoutSec_ = 0)
|
||||
: url (url_),
|
||||
contentType (contentType_),
|
||||
postData (postData_),
|
||||
extraHeaders (std::move(extraHeaders_)),
|
||||
timeoutSec (timeoutSec_)
|
||||
{}
|
||||
inline RemoteTextThread(std::string url_,
|
||||
std::vector<std::string> &&extraHeaders_,
|
||||
std::string contentType_ = std::string(),
|
||||
std::string postData_ = std::string(),
|
||||
int timeoutSec_ = 0)
|
||||
: url(url_),
|
||||
contentType(contentType_),
|
||||
postData(postData_),
|
||||
extraHeaders(std::move(extraHeaders_)),
|
||||
timeoutSec(timeoutSec_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
bool GetRemoteFile(
|
||||
const char *url,
|
||||
std::string &str,
|
||||
std::string &error,
|
||||
long *responseCode = nullptr,
|
||||
const char *contentType = nullptr,
|
||||
const char *url, std::string &str, std::string &error,
|
||||
long *responseCode = nullptr, const char *contentType = nullptr,
|
||||
const char *postData = nullptr,
|
||||
std::vector<std::string> extraHeaders = std::vector<std::string>(),
|
||||
std::string *signature = nullptr,
|
||||
int timeoutSec = 0);
|
||||
std::string *signature = nullptr, int timeoutSec = 0);
|
||||
|
|
|
@ -1,19 +1,20 @@
|
|||
#include "slider-absoluteset-style.hpp"
|
||||
|
||||
SliderAbsoluteSetStyle::SliderAbsoluteSetStyle(const QString& baseStyle)
|
||||
:QProxyStyle(baseStyle)
|
||||
SliderAbsoluteSetStyle::SliderAbsoluteSetStyle(const QString &baseStyle)
|
||||
: QProxyStyle(baseStyle)
|
||||
{
|
||||
}
|
||||
SliderAbsoluteSetStyle::SliderAbsoluteSetStyle(QStyle* baseStyle)
|
||||
:QProxyStyle(baseStyle)
|
||||
SliderAbsoluteSetStyle::SliderAbsoluteSetStyle(QStyle *baseStyle)
|
||||
: QProxyStyle(baseStyle)
|
||||
{
|
||||
}
|
||||
|
||||
int SliderAbsoluteSetStyle::styleHint(QStyle::StyleHint hint,
|
||||
const QStyleOption* option = 0, const QWidget* widget = 0,
|
||||
QStyleHintReturn* returnData = 0) const
|
||||
const QStyleOption *option = 0,
|
||||
const QWidget *widget = 0,
|
||||
QStyleHintReturn *returnData = 0) const
|
||||
{
|
||||
if(hint == QStyle::SH_Slider_AbsoluteSetButtons)
|
||||
if (hint == QStyle::SH_Slider_AbsoluteSetButtons)
|
||||
return (Qt::LeftButton | Qt::MidButton);
|
||||
return QProxyStyle::styleHint(hint, option, widget, returnData);
|
||||
}
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
#include <QProxyStyle>
|
||||
|
||||
class SliderAbsoluteSetStyle : public QProxyStyle
|
||||
{
|
||||
class SliderAbsoluteSetStyle : public QProxyStyle {
|
||||
public:
|
||||
SliderAbsoluteSetStyle(const QString& baseStyle);
|
||||
SliderAbsoluteSetStyle(QStyle* baseStyle = Q_NULLPTR);
|
||||
int styleHint(QStyle::StyleHint hint, const QStyleOption* option,
|
||||
const QWidget* widget, QStyleHintReturn* returnData) const;
|
||||
SliderAbsoluteSetStyle(const QString &baseStyle);
|
||||
SliderAbsoluteSetStyle(QStyle *baseStyle = Q_NULLPTR);
|
||||
int styleHint(QStyle::StyleHint hint, const QStyleOption *option,
|
||||
const QWidget *widget,
|
||||
QStyleHintReturn *returnData) const;
|
||||
};
|
||||
|
|
|
@ -6,7 +6,7 @@ SliderIgnoreScroll::SliderIgnoreScroll(QWidget *parent) : QSlider(parent)
|
|||
}
|
||||
|
||||
SliderIgnoreScroll::SliderIgnoreScroll(Qt::Orientation orientation,
|
||||
QWidget *parent)
|
||||
QWidget *parent)
|
||||
: QSlider(parent)
|
||||
{
|
||||
setFocusPolicy(Qt::StrongFocus);
|
||||
|
|
|
@ -9,7 +9,8 @@ class SliderIgnoreScroll : public QSlider {
|
|||
|
||||
public:
|
||||
SliderIgnoreScroll(QWidget *parent = nullptr);
|
||||
SliderIgnoreScroll(Qt::Orientation orientation, QWidget *parent = nullptr);
|
||||
SliderIgnoreScroll(Qt::Orientation orientation,
|
||||
QWidget *parent = nullptr);
|
||||
|
||||
protected:
|
||||
virtual void wheelEvent(QWheelEvent *event) override;
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
void OBSSourceLabel::SourceRenamed(void *data, calldata_t *params)
|
||||
{
|
||||
auto &label = *static_cast<OBSSourceLabel*>(data);
|
||||
auto &label = *static_cast<OBSSourceLabel *>(data);
|
||||
|
||||
const char *name = calldata_string(params, "new_name");
|
||||
label.setText(name);
|
||||
|
@ -29,13 +29,13 @@ void OBSSourceLabel::SourceRenamed(void *data, calldata_t *params)
|
|||
|
||||
void OBSSourceLabel::SourceRemoved(void *data, calldata_t *)
|
||||
{
|
||||
auto &label = *static_cast<OBSSourceLabel*>(data);
|
||||
auto &label = *static_cast<OBSSourceLabel *>(data);
|
||||
emit label.Removed();
|
||||
}
|
||||
|
||||
void OBSSourceLabel::SourceDestroyed(void *data, calldata_t *)
|
||||
{
|
||||
auto &label = *static_cast<OBSSourceLabel*>(data);
|
||||
auto &label = *static_cast<OBSSourceLabel *>(data);
|
||||
emit label.Destroyed();
|
||||
|
||||
label.destroyedSignal.Disconnect();
|
||||
|
|
|
@ -28,17 +28,18 @@ public:
|
|||
OBSSignal removedSignal;
|
||||
OBSSignal destroyedSignal;
|
||||
|
||||
OBSSourceLabel(const obs_source_t *source, QWidget *parent=nullptr,
|
||||
Qt::WindowFlags f=0)
|
||||
OBSSourceLabel(const obs_source_t *source, QWidget *parent = nullptr,
|
||||
Qt::WindowFlags f = 0)
|
||||
: QLabel(obs_source_get_name(source), parent, f),
|
||||
renamedSignal(obs_source_get_signal_handler(source), "rename",
|
||||
&OBSSourceLabel::SourceRenamed, this),
|
||||
&OBSSourceLabel::SourceRenamed, this),
|
||||
removedSignal(obs_source_get_signal_handler(source), "remove",
|
||||
&OBSSourceLabel::SourceRemoved, this),
|
||||
&OBSSourceLabel::SourceRemoved, this),
|
||||
destroyedSignal(obs_source_get_signal_handler(source),
|
||||
"destroy", &OBSSourceLabel::SourceDestroyed,
|
||||
this)
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
static void SourceRenamed(void *data, calldata_t *params);
|
||||
|
|
|
@ -25,15 +25,14 @@
|
|||
|
||||
static inline OBSScene GetCurrentScene()
|
||||
{
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
|
||||
return main->GetCurrentScene();
|
||||
}
|
||||
|
||||
/* ========================================================================= */
|
||||
|
||||
SourceTreeItem::SourceTreeItem(SourceTree *tree_, OBSSceneItem sceneitem_)
|
||||
: tree (tree_),
|
||||
sceneitem (sceneitem_)
|
||||
: tree(tree_), sceneitem(sceneitem_)
|
||||
{
|
||||
setAttribute(Qt::WA_TranslucentBackground);
|
||||
setMouseTracking(true);
|
||||
|
@ -98,14 +97,12 @@ SourceTreeItem::SourceTreeItem(SourceTree *tree_, OBSSceneItem sceneitem_)
|
|||
|
||||
/* --------------------------------------------------------- */
|
||||
|
||||
auto setItemVisible = [this] (bool checked)
|
||||
{
|
||||
auto setItemVisible = [this](bool checked) {
|
||||
SignalBlocker sourcesSignalBlocker(this);
|
||||
obs_sceneitem_set_visible(sceneitem, checked);
|
||||
};
|
||||
|
||||
auto setItemLocked = [this] (bool checked)
|
||||
{
|
||||
auto setItemLocked = [this](bool checked) {
|
||||
SignalBlocker sourcesSignalBlocker(this);
|
||||
obs_sceneitem_set_locked(sceneitem, checked);
|
||||
};
|
||||
|
@ -150,59 +147,58 @@ void SourceTreeItem::ReconnectSignals()
|
|||
|
||||
/* --------------------------------------------------------- */
|
||||
|
||||
auto removeItem = [] (void *data, calldata_t *cd)
|
||||
{
|
||||
SourceTreeItem *this_ = reinterpret_cast<SourceTreeItem*>(data);
|
||||
auto removeItem = [](void *data, calldata_t *cd) {
|
||||
SourceTreeItem *this_ =
|
||||
reinterpret_cast<SourceTreeItem *>(data);
|
||||
obs_sceneitem_t *curItem =
|
||||
(obs_sceneitem_t*)calldata_ptr(cd, "item");
|
||||
(obs_sceneitem_t *)calldata_ptr(cd, "item");
|
||||
|
||||
if (curItem == this_->sceneitem) {
|
||||
QMetaObject::invokeMethod(this_->tree,
|
||||
"Remove",
|
||||
Q_ARG(OBSSceneItem, curItem));
|
||||
QMetaObject::invokeMethod(this_->tree, "Remove",
|
||||
Q_ARG(OBSSceneItem, curItem));
|
||||
curItem = nullptr;
|
||||
}
|
||||
if (!curItem)
|
||||
QMetaObject::invokeMethod(this_, "Clear");
|
||||
};
|
||||
|
||||
auto itemVisible = [] (void *data, calldata_t *cd)
|
||||
{
|
||||
SourceTreeItem *this_ = reinterpret_cast<SourceTreeItem*>(data);
|
||||
auto itemVisible = [](void *data, calldata_t *cd) {
|
||||
SourceTreeItem *this_ =
|
||||
reinterpret_cast<SourceTreeItem *>(data);
|
||||
obs_sceneitem_t *curItem =
|
||||
(obs_sceneitem_t*)calldata_ptr(cd, "item");
|
||||
(obs_sceneitem_t *)calldata_ptr(cd, "item");
|
||||
bool visible = calldata_bool(cd, "visible");
|
||||
|
||||
if (curItem == this_->sceneitem)
|
||||
QMetaObject::invokeMethod(this_, "VisibilityChanged",
|
||||
Q_ARG(bool, visible));
|
||||
Q_ARG(bool, visible));
|
||||
};
|
||||
|
||||
auto itemLocked = [] (void *data, calldata_t *cd)
|
||||
{
|
||||
SourceTreeItem *this_ = reinterpret_cast<SourceTreeItem*>(data);
|
||||
auto itemLocked = [](void *data, calldata_t *cd) {
|
||||
SourceTreeItem *this_ =
|
||||
reinterpret_cast<SourceTreeItem *>(data);
|
||||
obs_sceneitem_t *curItem =
|
||||
(obs_sceneitem_t*)calldata_ptr(cd, "item");
|
||||
(obs_sceneitem_t *)calldata_ptr(cd, "item");
|
||||
bool locked = calldata_bool(cd, "locked");
|
||||
|
||||
if (curItem == this_->sceneitem)
|
||||
QMetaObject::invokeMethod(this_, "LockedChanged",
|
||||
Q_ARG(bool, locked));
|
||||
Q_ARG(bool, locked));
|
||||
};
|
||||
|
||||
auto itemDeselect = [] (void *data, calldata_t *cd)
|
||||
{
|
||||
SourceTreeItem *this_ = reinterpret_cast<SourceTreeItem*>(data);
|
||||
auto itemDeselect = [](void *data, calldata_t *cd) {
|
||||
SourceTreeItem *this_ =
|
||||
reinterpret_cast<SourceTreeItem *>(data);
|
||||
obs_sceneitem_t *curItem =
|
||||
(obs_sceneitem_t*)calldata_ptr(cd, "item");
|
||||
(obs_sceneitem_t *)calldata_ptr(cd, "item");
|
||||
|
||||
if (curItem == this_->sceneitem)
|
||||
QMetaObject::invokeMethod(this_, "Deselect");
|
||||
};
|
||||
|
||||
auto reorderGroup = [] (void *data, calldata_t*)
|
||||
{
|
||||
SourceTreeItem *this_ = reinterpret_cast<SourceTreeItem*>(data);
|
||||
auto reorderGroup = [](void *data, calldata_t *) {
|
||||
SourceTreeItem *this_ =
|
||||
reinterpret_cast<SourceTreeItem *>(data);
|
||||
QMetaObject::invokeMethod(this_->tree, "ReorderItems");
|
||||
};
|
||||
|
||||
|
@ -220,27 +216,27 @@ void SourceTreeItem::ReconnectSignals()
|
|||
signal = obs_source_get_signal_handler(source);
|
||||
|
||||
groupReorderSignal.Connect(signal, "reorder", reorderGroup,
|
||||
this);
|
||||
this);
|
||||
}
|
||||
|
||||
if (scene != GetCurrentScene())
|
||||
deselectSignal.Connect(signal, "item_deselect", itemDeselect,
|
||||
this);
|
||||
this);
|
||||
|
||||
/* --------------------------------------------------------- */
|
||||
|
||||
auto renamed = [] (void *data, calldata_t *cd)
|
||||
{
|
||||
SourceTreeItem *this_ = reinterpret_cast<SourceTreeItem*>(data);
|
||||
auto renamed = [](void *data, calldata_t *cd) {
|
||||
SourceTreeItem *this_ =
|
||||
reinterpret_cast<SourceTreeItem *>(data);
|
||||
const char *name = calldata_string(cd, "new_name");
|
||||
|
||||
QMetaObject::invokeMethod(this_, "Renamed",
|
||||
Q_ARG(QString, QT_UTF8(name)));
|
||||
Q_ARG(QString, QT_UTF8(name)));
|
||||
};
|
||||
|
||||
auto removeSource = [] (void *data, calldata_t *)
|
||||
{
|
||||
SourceTreeItem *this_ = reinterpret_cast<SourceTreeItem*>(data);
|
||||
auto removeSource = [](void *data, calldata_t *) {
|
||||
SourceTreeItem *this_ =
|
||||
reinterpret_cast<SourceTreeItem *>(data);
|
||||
this_->DisconnectSignals();
|
||||
this_->sceneitem = nullptr;
|
||||
};
|
||||
|
@ -260,7 +256,7 @@ void SourceTreeItem::mouseDoubleClickEvent(QMouseEvent *event)
|
|||
} else {
|
||||
obs_source_t *source = obs_sceneitem_get_source(sceneitem);
|
||||
OBSBasic *main =
|
||||
reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
||||
reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
|
||||
if (source) {
|
||||
main->CreatePropertiesWindow(source);
|
||||
}
|
||||
|
@ -289,7 +285,7 @@ void SourceTreeItem::ExitEditMode(bool save)
|
|||
if (!editor)
|
||||
return;
|
||||
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
|
||||
OBSScene scene = main->GetCurrentScene();
|
||||
|
||||
std::string newName = QT_TO_UTF8(editor->text());
|
||||
|
@ -308,9 +304,8 @@ void SourceTreeItem::ExitEditMode(bool save)
|
|||
return;
|
||||
|
||||
if (newName.empty()) {
|
||||
OBSMessageBox::information(main,
|
||||
QTStr("NoNameEntered.Title"),
|
||||
QTStr("NoNameEntered.Text"));
|
||||
OBSMessageBox::information(main, QTStr("NoNameEntered.Title"),
|
||||
QTStr("NoNameEntered.Text"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -324,15 +319,13 @@ void SourceTreeItem::ExitEditMode(bool save)
|
|||
/* ----------------------------------------- */
|
||||
/* check for existing source */
|
||||
|
||||
obs_source_t *existingSource =
|
||||
obs_get_source_by_name(newName.c_str());
|
||||
obs_source_t *existingSource = obs_get_source_by_name(newName.c_str());
|
||||
obs_source_release(existingSource);
|
||||
bool exists = !!existingSource;
|
||||
|
||||
if (exists) {
|
||||
OBSMessageBox::information(main,
|
||||
QTStr("NameExists.Title"),
|
||||
QTStr("NameExists.Text"));
|
||||
OBSMessageBox::information(main, QTStr("NameExists.Title"),
|
||||
QTStr("NameExists.Text"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -355,22 +348,22 @@ bool SourceTreeItem::eventFilter(QObject *object, QEvent *event)
|
|||
switch (keyEvent->key()) {
|
||||
case Qt::Key_Escape:
|
||||
QMetaObject::invokeMethod(this, "ExitEditMode",
|
||||
Qt::QueuedConnection,
|
||||
Q_ARG(bool, false));
|
||||
Qt::QueuedConnection,
|
||||
Q_ARG(bool, false));
|
||||
return true;
|
||||
case Qt::Key_Tab:
|
||||
case Qt::Key_Backtab:
|
||||
case Qt::Key_Enter:
|
||||
case Qt::Key_Return:
|
||||
QMetaObject::invokeMethod(this, "ExitEditMode",
|
||||
Qt::QueuedConnection,
|
||||
Q_ARG(bool, true));
|
||||
Qt::QueuedConnection,
|
||||
Q_ARG(bool, true));
|
||||
return true;
|
||||
}
|
||||
} else if (event->type() == QEvent::FocusOut) {
|
||||
QMetaObject::invokeMethod(this, "ExitEditMode",
|
||||
Qt::QueuedConnection,
|
||||
Q_ARG(bool, true));
|
||||
Qt::QueuedConnection,
|
||||
Q_ARG(bool, true));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -405,14 +398,14 @@ void SourceTreeItem::Update(bool force)
|
|||
if (obs_sceneitem_is_group(sceneitem)) {
|
||||
newType = Type::Group;
|
||||
|
||||
/* ------------------------------------------------- */
|
||||
/* if it's a group sub-item */
|
||||
/* ------------------------------------------------- */
|
||||
/* if it's a group sub-item */
|
||||
|
||||
} else if (itemScene != scene) {
|
||||
newType = Type::SubItem;
|
||||
|
||||
/* ------------------------------------------------- */
|
||||
/* if it's a regular item */
|
||||
/* ------------------------------------------------- */
|
||||
/* if it's a regular item */
|
||||
|
||||
} else {
|
||||
newType = Type::Item;
|
||||
|
@ -448,9 +441,8 @@ void SourceTreeItem::Update(bool force)
|
|||
|
||||
} else if (type == Type::Group) {
|
||||
expand = new SourceTreeSubItemCheckBox();
|
||||
expand->setSizePolicy(
|
||||
QSizePolicy::Maximum,
|
||||
QSizePolicy::Maximum);
|
||||
expand->setSizePolicy(QSizePolicy::Maximum,
|
||||
QSizePolicy::Maximum);
|
||||
expand->setMaximumSize(10, 16);
|
||||
expand->setMinimumSize(10, 0);
|
||||
#ifdef __APPLE__
|
||||
|
@ -458,14 +450,15 @@ void SourceTreeItem::Update(bool force)
|
|||
#endif
|
||||
boxLayout->insertWidget(0, expand);
|
||||
|
||||
obs_data_t *data = obs_sceneitem_get_private_settings(sceneitem);
|
||||
obs_data_t *data =
|
||||
obs_sceneitem_get_private_settings(sceneitem);
|
||||
expand->blockSignals(true);
|
||||
expand->setChecked(obs_data_get_bool(data, "collapsed"));
|
||||
expand->blockSignals(false);
|
||||
obs_data_release(data);
|
||||
|
||||
connect(expand, &QPushButton::toggled,
|
||||
this, &SourceTreeItem::ExpandClicked);
|
||||
connect(expand, &QPushButton::toggled, this,
|
||||
&SourceTreeItem::ExpandClicked);
|
||||
|
||||
} else {
|
||||
spacer = new QSpacerItem(3, 1);
|
||||
|
@ -517,10 +510,10 @@ void SourceTreeModel::Clear()
|
|||
hasGroups = false;
|
||||
}
|
||||
|
||||
static bool enumItem(obs_scene_t*, obs_sceneitem_t *item, void *ptr)
|
||||
static bool enumItem(obs_scene_t *, obs_sceneitem_t *item, void *ptr)
|
||||
{
|
||||
QVector<OBSSceneItem> &items =
|
||||
*reinterpret_cast<QVector<OBSSceneItem>*>(ptr);
|
||||
*reinterpret_cast<QVector<OBSSceneItem> *>(ptr);
|
||||
|
||||
if (obs_sceneitem_is_group(item)) {
|
||||
obs_data_t *data = obs_sceneitem_get_private_settings(item);
|
||||
|
@ -556,14 +549,15 @@ void SourceTreeModel::SceneChanged()
|
|||
bool select = obs_sceneitem_selected(items[i]);
|
||||
QModelIndex index = createIndex(i, 0);
|
||||
|
||||
st->selectionModel()->select(index, select
|
||||
? QItemSelectionModel::Select
|
||||
: QItemSelectionModel::Deselect);
|
||||
st->selectionModel()->select(
|
||||
index, select ? QItemSelectionModel::Select
|
||||
: QItemSelectionModel::Deselect);
|
||||
}
|
||||
}
|
||||
|
||||
/* moves a scene item index (blame linux distros for using older Qt builds) */
|
||||
static inline void MoveItem(QVector<OBSSceneItem> &items, int oldIdx, int newIdx)
|
||||
static inline void MoveItem(QVector<OBSSceneItem> &items, int oldIdx,
|
||||
int newIdx)
|
||||
{
|
||||
OBSSceneItem item = items[oldIdx];
|
||||
items.remove(oldIdx);
|
||||
|
@ -637,7 +631,7 @@ void SourceTreeModel::ReorderItems()
|
|||
|
||||
/* move items */
|
||||
beginMoveRows(QModelIndex(), idx1Old, idx1Old + count - 1,
|
||||
QModelIndex(), idx1New + count);
|
||||
QModelIndex(), idx1New + count);
|
||||
for (i = 0; i < count; i++) {
|
||||
int to = idx1New + count;
|
||||
if (to > idx1Old)
|
||||
|
@ -709,8 +703,7 @@ OBSSceneItem SourceTreeModel::Get(int idx)
|
|||
}
|
||||
|
||||
SourceTreeModel::SourceTreeModel(SourceTree *st_)
|
||||
: QAbstractListModel (st_),
|
||||
st (st_)
|
||||
: QAbstractListModel(st_), st(st_)
|
||||
{
|
||||
obs_frontend_add_event_callback(OBSFrontendEvent, this);
|
||||
}
|
||||
|
@ -744,8 +737,7 @@ Qt::ItemFlags SourceTreeModel::flags(const QModelIndex &index) const
|
|||
obs_sceneitem_t *item = items[index.row()];
|
||||
bool is_group = obs_sceneitem_is_group(item);
|
||||
|
||||
return QAbstractListModel::flags(index) |
|
||||
Qt::ItemIsEditable |
|
||||
return QAbstractListModel::flags(index) | Qt::ItemIsEditable |
|
||||
Qt::ItemIsDragEnabled |
|
||||
(is_group ? Qt::ItemIsDropEnabled : Qt::NoItemFlags);
|
||||
}
|
||||
|
@ -775,8 +767,8 @@ QString SourceTreeModel::GetNewGroupName()
|
|||
void SourceTreeModel::AddGroup()
|
||||
{
|
||||
QString name = GetNewGroupName();
|
||||
obs_sceneitem_t *group = obs_scene_add_group(GetCurrentScene(),
|
||||
QT_TO_UTF8(name));
|
||||
obs_sceneitem_t *group =
|
||||
obs_scene_add_group(GetCurrentScene(), QT_TO_UTF8(name));
|
||||
if (!group)
|
||||
return;
|
||||
|
||||
|
@ -788,7 +780,7 @@ void SourceTreeModel::AddGroup()
|
|||
UpdateGroupState(true);
|
||||
|
||||
QMetaObject::invokeMethod(st, "Edit", Qt::QueuedConnection,
|
||||
Q_ARG(int, 0));
|
||||
Q_ARG(int, 0));
|
||||
}
|
||||
|
||||
void SourceTreeModel::GroupSelectedItems(QModelIndexList &indices)
|
||||
|
@ -807,8 +799,7 @@ void SourceTreeModel::GroupSelectedItems(QModelIndexList &indices)
|
|||
}
|
||||
|
||||
obs_sceneitem_t *item = obs_scene_insert_group(
|
||||
scene, QT_TO_UTF8(name),
|
||||
item_order.data(), item_order.size());
|
||||
scene, QT_TO_UTF8(name), item_order.data(), item_order.size());
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
|
@ -827,7 +818,7 @@ void SourceTreeModel::GroupSelectedItems(QModelIndexList &indices)
|
|||
int toIdx = newIdx + i + 1;
|
||||
if (fromIdx != toIdx) {
|
||||
beginMoveRows(QModelIndex(), fromIdx, fromIdx,
|
||||
QModelIndex(), toIdx);
|
||||
QModelIndex(), toIdx);
|
||||
MoveItem(items, fromIdx, toIdx);
|
||||
endMoveRows();
|
||||
}
|
||||
|
@ -839,7 +830,7 @@ void SourceTreeModel::GroupSelectedItems(QModelIndexList &indices)
|
|||
obs_sceneitem_select(item, true);
|
||||
|
||||
QMetaObject::invokeMethod(st, "Edit", Qt::QueuedConnection,
|
||||
Q_ARG(int, newIdx));
|
||||
Q_ARG(int, newIdx));
|
||||
}
|
||||
|
||||
void SourceTreeModel::UngroupSelectedGroups(QModelIndexList &indices)
|
||||
|
@ -929,20 +920,20 @@ SourceTree::SourceTree(QWidget *parent_) : QListView(parent_)
|
|||
SourceTreeModel *stm_ = new SourceTreeModel(this);
|
||||
setModel(stm_);
|
||||
setStyleSheet(QString(
|
||||
"*[bgColor=\"1\"]{background-color:rgba(255,68,68,33%);}" \
|
||||
"*[bgColor=\"2\"]{background-color:rgba(255,255,68,33%);}" \
|
||||
"*[bgColor=\"3\"]{background-color:rgba(68,255,68,33%);}" \
|
||||
"*[bgColor=\"4\"]{background-color:rgba(68,255,255,33%);}" \
|
||||
"*[bgColor=\"5\"]{background-color:rgba(68,68,255,33%);}" \
|
||||
"*[bgColor=\"6\"]{background-color:rgba(255,68,255,33%);}" \
|
||||
"*[bgColor=\"7\"]{background-color:rgba(68,68,68,33%);}" \
|
||||
"*[bgColor=\"1\"]{background-color:rgba(255,68,68,33%);}"
|
||||
"*[bgColor=\"2\"]{background-color:rgba(255,255,68,33%);}"
|
||||
"*[bgColor=\"3\"]{background-color:rgba(68,255,68,33%);}"
|
||||
"*[bgColor=\"4\"]{background-color:rgba(68,255,255,33%);}"
|
||||
"*[bgColor=\"5\"]{background-color:rgba(68,68,255,33%);}"
|
||||
"*[bgColor=\"6\"]{background-color:rgba(255,68,255,33%);}"
|
||||
"*[bgColor=\"7\"]{background-color:rgba(68,68,68,33%);}"
|
||||
"*[bgColor=\"8\"]{background-color:rgba(255,255,255,33%);}"));
|
||||
|
||||
setMouseTracking(true);
|
||||
|
||||
UpdateNoSourcesMessage();
|
||||
connect(App(), &OBSApp::StyleChanged,
|
||||
this, &SourceTree::UpdateNoSourcesMessage);
|
||||
connect(App(), &OBSApp::StyleChanged, this,
|
||||
&SourceTree::UpdateNoSourcesMessage);
|
||||
}
|
||||
|
||||
void SourceTree::ResetWidgets()
|
||||
|
@ -994,9 +985,9 @@ void SourceTree::SelectItem(obs_sceneitem_t *sceneitem, bool select)
|
|||
|
||||
QModelIndex index = stm->createIndex(i, 0);
|
||||
if (index.isValid())
|
||||
selectionModel()->select(index, select
|
||||
? QItemSelectionModel::Select
|
||||
: QItemSelectionModel::Deselect);
|
||||
selectionModel()->select(
|
||||
index, select ? QItemSelectionModel::Select
|
||||
: QItemSelectionModel::Deselect);
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(OBSSceneItem);
|
||||
|
@ -1040,9 +1031,9 @@ void SourceTree::dropEvent(QDropEvent *event)
|
|||
obs_sceneitem_t *dropItem = items[row]; /* item being dropped on */
|
||||
bool itemIsGroup = obs_sceneitem_is_group(dropItem);
|
||||
|
||||
obs_sceneitem_t *dropGroup = itemIsGroup
|
||||
? dropItem
|
||||
: obs_sceneitem_get_group(scene, dropItem);
|
||||
obs_sceneitem_t *dropGroup =
|
||||
itemIsGroup ? dropItem
|
||||
: obs_sceneitem_get_group(scene, dropItem);
|
||||
|
||||
/* not a group if moving above the group */
|
||||
if (indicator == QAbstractItemView::AboveItem && itemIsGroup)
|
||||
|
@ -1056,7 +1047,8 @@ void SourceTree::dropEvent(QDropEvent *event)
|
|||
|
||||
bool dropOnCollapsed = false;
|
||||
if (dropGroup) {
|
||||
obs_data_t *data = obs_sceneitem_get_private_settings(dropGroup);
|
||||
obs_data_t *data =
|
||||
obs_sceneitem_get_private_settings(dropGroup);
|
||||
dropOnCollapsed = obs_data_get_bool(data, "collapsed");
|
||||
obs_data_release(data);
|
||||
}
|
||||
|
@ -1086,9 +1078,8 @@ void SourceTree::dropEvent(QDropEvent *event)
|
|||
/* if dropping a group, detect if it's */
|
||||
/* below another group */
|
||||
|
||||
obs_sceneitem_t *itemBelow = row == stm->items.count()
|
||||
? nullptr
|
||||
: stm->items[row];
|
||||
obs_sceneitem_t *itemBelow =
|
||||
row == stm->items.count() ? nullptr : stm->items[row];
|
||||
if (hasGroups) {
|
||||
if (!itemBelow ||
|
||||
obs_sceneitem_get_group(scene, itemBelow) != dropGroup) {
|
||||
|
@ -1131,8 +1122,8 @@ void SourceTree::dropEvent(QDropEvent *event)
|
|||
for (int j = items.size() - 1; j >= 0; j--) {
|
||||
obs_sceneitem_t *subitem = items[j];
|
||||
obs_sceneitem_t *subitemGroup =
|
||||
obs_sceneitem_get_group(scene,
|
||||
subitem);
|
||||
obs_sceneitem_get_group(
|
||||
scene, subitem);
|
||||
|
||||
if (subitemGroup == item) {
|
||||
QModelIndex idx =
|
||||
|
@ -1167,7 +1158,7 @@ void SourceTree::dropEvent(QDropEvent *event)
|
|||
|
||||
if (itemTo != from) {
|
||||
stm->beginMoveRows(QModelIndex(), from, from,
|
||||
QModelIndex(), to);
|
||||
QModelIndex(), to);
|
||||
MoveItem(items, from, itemTo);
|
||||
stm->endMoveRows();
|
||||
}
|
||||
|
@ -1186,8 +1177,7 @@ void SourceTree::dropEvent(QDropEvent *event)
|
|||
obs_sceneitem_t *lastGroup = nullptr;
|
||||
int insertCollapsedIdx = 0;
|
||||
|
||||
auto insertCollapsed = [&] (obs_sceneitem_t *item)
|
||||
{
|
||||
auto insertCollapsed = [&](obs_sceneitem_t *item) {
|
||||
struct obs_sceneitem_order_info info;
|
||||
info.group = lastGroup;
|
||||
info.item = item;
|
||||
|
@ -1197,25 +1187,23 @@ void SourceTree::dropEvent(QDropEvent *event)
|
|||
|
||||
using insertCollapsed_t = decltype(insertCollapsed);
|
||||
|
||||
auto preInsertCollapsed = [] (obs_scene_t *, obs_sceneitem_t *item,
|
||||
void *param)
|
||||
{
|
||||
auto preInsertCollapsed = [](obs_scene_t *, obs_sceneitem_t *item,
|
||||
void *param) {
|
||||
(*reinterpret_cast<insertCollapsed_t *>(param))(item);
|
||||
return true;
|
||||
};
|
||||
|
||||
auto insertLastGroup = [&] ()
|
||||
{
|
||||
obs_data_t *data = obs_sceneitem_get_private_settings(lastGroup);
|
||||
auto insertLastGroup = [&]() {
|
||||
obs_data_t *data =
|
||||
obs_sceneitem_get_private_settings(lastGroup);
|
||||
bool collapsed = obs_data_get_bool(data, "collapsed");
|
||||
obs_data_release(data);
|
||||
|
||||
if (collapsed) {
|
||||
insertCollapsedIdx = 0;
|
||||
obs_sceneitem_group_enum_items(
|
||||
lastGroup,
|
||||
preInsertCollapsed,
|
||||
&insertCollapsed);
|
||||
obs_sceneitem_group_enum_items(lastGroup,
|
||||
preInsertCollapsed,
|
||||
&insertCollapsed);
|
||||
}
|
||||
|
||||
struct obs_sceneitem_order_info info;
|
||||
|
@ -1224,8 +1212,7 @@ void SourceTree::dropEvent(QDropEvent *event)
|
|||
orderList.insert(0, info);
|
||||
};
|
||||
|
||||
auto updateScene = [&] ()
|
||||
{
|
||||
auto updateScene = [&]() {
|
||||
struct obs_sceneitem_order_info info;
|
||||
|
||||
for (int i = 0; i < items.size(); i++) {
|
||||
|
@ -1260,14 +1247,13 @@ void SourceTree::dropEvent(QDropEvent *event)
|
|||
insertLastGroup();
|
||||
}
|
||||
|
||||
obs_scene_reorder_items2(scene,
|
||||
orderList.data(), orderList.size());
|
||||
obs_scene_reorder_items2(scene, orderList.data(),
|
||||
orderList.size());
|
||||
};
|
||||
|
||||
using updateScene_t = decltype(updateScene);
|
||||
|
||||
auto preUpdateScene = [] (void *data, obs_scene_t *)
|
||||
{
|
||||
auto preUpdateScene = [](void *data, obs_scene_t *) {
|
||||
(*reinterpret_cast<updateScene_t *>(data))();
|
||||
};
|
||||
|
||||
|
@ -1314,9 +1300,8 @@ void SourceTree::leaveEvent(QEvent *event)
|
|||
QListView::leaveEvent(event);
|
||||
}
|
||||
|
||||
void SourceTree::selectionChanged(
|
||||
const QItemSelection &selected,
|
||||
const QItemSelection &deselected)
|
||||
void SourceTree::selectionChanged(const QItemSelection &selected,
|
||||
const QItemSelection &deselected)
|
||||
{
|
||||
{
|
||||
SignalBlocker sourcesSignalBlocker(this);
|
||||
|
@ -1425,7 +1410,7 @@ bool SourceTree::GroupedItemsSelected() const
|
|||
|
||||
void SourceTree::Remove(OBSSceneItem item)
|
||||
{
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
|
||||
GetStm()->Remove(item);
|
||||
main->SaveProject();
|
||||
|
||||
|
@ -1434,9 +1419,9 @@ void SourceTree::Remove(OBSSceneItem item)
|
|||
obs_source_t *sceneSource = obs_scene_get_source(scene);
|
||||
obs_source_t *itemSource = obs_sceneitem_get_source(item);
|
||||
blog(LOG_INFO, "User Removed source '%s' (%s) from scene '%s'",
|
||||
obs_source_get_name(itemSource),
|
||||
obs_source_get_id(itemSource),
|
||||
obs_source_get_name(sceneSource));
|
||||
obs_source_get_name(itemSource),
|
||||
obs_source_get_id(itemSource),
|
||||
obs_source_get_name(sceneSource));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1465,9 +1450,8 @@ void SourceTree::UpdateNoSourcesMessage()
|
|||
|
||||
QColor color = palette().text().color();
|
||||
bool lightTheme = (color.redF() < 0.5);
|
||||
QString file = lightTheme
|
||||
? ":res/images/no_sources.svg"
|
||||
: darkPath.c_str();
|
||||
QString file = lightTheme ? ":res/images/no_sources.svg"
|
||||
: darkPath.c_str();
|
||||
iconNoSources.load(file);
|
||||
|
||||
QTextOption opt(Qt::AlignHCenter);
|
||||
|
|
|
@ -72,7 +72,7 @@ private:
|
|||
OBSSignal renameSignal;
|
||||
OBSSignal removeSignal;
|
||||
|
||||
virtual void paintEvent(QPaintEvent* event) override;
|
||||
virtual void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
private slots:
|
||||
void Clear();
|
||||
|
@ -123,7 +123,8 @@ public:
|
|||
~SourceTreeModel();
|
||||
|
||||
virtual int rowCount(const QModelIndex &parent) const override;
|
||||
virtual QVariant data(const QModelIndex &index, int role) const override;
|
||||
virtual QVariant data(const QModelIndex &index,
|
||||
int role) const override;
|
||||
|
||||
virtual Qt::ItemFlags flags(const QModelIndex &index) const override;
|
||||
virtual Qt::DropActions supportedDropActions() const override;
|
||||
|
@ -161,12 +162,12 @@ public:
|
|||
|
||||
explicit SourceTree(QWidget *parent = nullptr);
|
||||
|
||||
inline bool IgnoreReorder() const {return ignoreReorder;}
|
||||
inline void Clear() {GetStm()->Clear();}
|
||||
inline bool IgnoreReorder() const { return ignoreReorder; }
|
||||
inline void Clear() { GetStm()->Clear(); }
|
||||
|
||||
inline void Add(obs_sceneitem_t *item) {GetStm()->Add(item);}
|
||||
inline OBSSceneItem Get(int idx) {return GetStm()->Get(idx);}
|
||||
inline QString GetNewGroupName() {return GetStm()->GetNewGroupName();}
|
||||
inline void Add(obs_sceneitem_t *item) { GetStm()->Add(item); }
|
||||
inline OBSSceneItem Get(int idx) { return GetStm()->Get(idx); }
|
||||
inline QString GetNewGroupName() { return GetStm()->GetNewGroupName(); }
|
||||
|
||||
void SelectItem(obs_sceneitem_t *sceneitem, bool select);
|
||||
|
||||
|
@ -175,7 +176,7 @@ public:
|
|||
bool GroupedItemsSelected() const;
|
||||
|
||||
public slots:
|
||||
inline void ReorderItems() {GetStm()->ReorderItems();}
|
||||
inline void ReorderItems() { GetStm()->ReorderItems(); }
|
||||
void Remove(OBSSceneItem item);
|
||||
void GroupSelectedItems();
|
||||
void UngroupSelectedGroups();
|
||||
|
@ -189,5 +190,7 @@ protected:
|
|||
virtual void leaveEvent(QEvent *event) override;
|
||||
virtual void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
virtual void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) override;
|
||||
virtual void
|
||||
selectionChanged(const QItemSelection &selected,
|
||||
const QItemSelection &deselected) override;
|
||||
};
|
||||
|
|
|
@ -8,8 +8,7 @@ class VScrollArea : public QScrollArea {
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
inline VScrollArea(QWidget *parent = nullptr)
|
||||
: QScrollArea(parent)
|
||||
inline VScrollArea(QWidget *parent = nullptr) : QScrollArea(parent)
|
||||
{
|
||||
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
}
|
||||
|
|
|
@ -10,11 +10,11 @@
|
|||
#include <QLabel>
|
||||
|
||||
VisibilityItemWidget::VisibilityItemWidget(obs_source_t *source_)
|
||||
: source (source_),
|
||||
enabledSignal (obs_source_get_signal_handler(source), "enable",
|
||||
OBSSourceEnabled, this),
|
||||
renamedSignal (obs_source_get_signal_handler(source), "rename",
|
||||
OBSSourceRenamed, this)
|
||||
: source(source_),
|
||||
enabledSignal(obs_source_get_signal_handler(source), "enable",
|
||||
OBSSourceEnabled, this),
|
||||
renamedSignal(obs_source_get_signal_handler(source), "rename",
|
||||
OBSSourceRenamed, this)
|
||||
{
|
||||
const char *name = obs_source_get_name(source);
|
||||
bool enabled = obs_source_enabled(source);
|
||||
|
@ -38,15 +38,15 @@ VisibilityItemWidget::VisibilityItemWidget(obs_source_t *source_)
|
|||
setLayout(itemLayout);
|
||||
setStyleSheet("background-color: rgba(255, 255, 255, 0);");
|
||||
|
||||
connect(vis, SIGNAL(clicked(bool)),
|
||||
this, SLOT(VisibilityClicked(bool)));
|
||||
connect(vis, SIGNAL(clicked(bool)), this,
|
||||
SLOT(VisibilityClicked(bool)));
|
||||
}
|
||||
|
||||
VisibilityItemWidget::VisibilityItemWidget(obs_sceneitem_t *item_)
|
||||
: item (item_),
|
||||
source (obs_sceneitem_get_source(item)),
|
||||
renamedSignal (obs_source_get_signal_handler(source), "rename",
|
||||
OBSSourceRenamed, this)
|
||||
: item(item_),
|
||||
source(obs_sceneitem_get_source(item)),
|
||||
renamedSignal(obs_source_get_signal_handler(source), "rename",
|
||||
OBSSourceRenamed, this)
|
||||
{
|
||||
const char *name = obs_source_get_name(source);
|
||||
bool enabled = obs_sceneitem_visible(item);
|
||||
|
@ -90,18 +90,15 @@ VisibilityItemWidget::VisibilityItemWidget(obs_sceneitem_t *item_)
|
|||
|
||||
signal_handler_t *signal = obs_source_get_signal_handler(sceneSource);
|
||||
signal_handler_connect(signal, "remove", OBSSceneRemove, this);
|
||||
signal_handler_connect(signal, "item_remove", OBSSceneItemRemove,
|
||||
this);
|
||||
signal_handler_connect(signal, "item_remove", OBSSceneItemRemove, this);
|
||||
signal_handler_connect(signal, "item_visible", OBSSceneItemVisible,
|
||||
this);
|
||||
signal_handler_connect(signal, "item_locked", OBSSceneItemLocked,
|
||||
this);
|
||||
this);
|
||||
signal_handler_connect(signal, "item_locked", OBSSceneItemLocked, this);
|
||||
|
||||
connect(vis, SIGNAL(clicked(bool)),
|
||||
this, SLOT(VisibilityClicked(bool)));
|
||||
connect(vis, SIGNAL(clicked(bool)), this,
|
||||
SLOT(VisibilityClicked(bool)));
|
||||
|
||||
connect(lock, SIGNAL(clicked(bool)),
|
||||
this, SLOT(LockClicked(bool)));
|
||||
connect(lock, SIGNAL(clicked(bool)), this, SLOT(LockClicked(bool)));
|
||||
}
|
||||
|
||||
VisibilityItemWidget::~VisibilityItemWidget()
|
||||
|
@ -120,11 +117,11 @@ void VisibilityItemWidget::DisconnectItemSignals()
|
|||
|
||||
signal_handler_disconnect(signal, "remove", OBSSceneRemove, this);
|
||||
signal_handler_disconnect(signal, "item_remove", OBSSceneItemRemove,
|
||||
this);
|
||||
this);
|
||||
signal_handler_disconnect(signal, "item_visible", OBSSceneItemVisible,
|
||||
this);
|
||||
this);
|
||||
signal_handler_disconnect(signal, "item_locked", OBSSceneItemLocked,
|
||||
this);
|
||||
this);
|
||||
|
||||
sceneRemoved = true;
|
||||
}
|
||||
|
@ -132,7 +129,7 @@ void VisibilityItemWidget::DisconnectItemSignals()
|
|||
void VisibilityItemWidget::OBSSceneRemove(void *param, calldata_t *data)
|
||||
{
|
||||
VisibilityItemWidget *window =
|
||||
reinterpret_cast<VisibilityItemWidget*>(param);
|
||||
reinterpret_cast<VisibilityItemWidget *>(param);
|
||||
|
||||
window->DisconnectItemSignals();
|
||||
|
||||
|
@ -142,8 +139,8 @@ void VisibilityItemWidget::OBSSceneRemove(void *param, calldata_t *data)
|
|||
void VisibilityItemWidget::OBSSceneItemRemove(void *param, calldata_t *data)
|
||||
{
|
||||
VisibilityItemWidget *window =
|
||||
reinterpret_cast<VisibilityItemWidget*>(param);
|
||||
obs_sceneitem_t *item = (obs_sceneitem_t*)calldata_ptr(data, "item");
|
||||
reinterpret_cast<VisibilityItemWidget *>(param);
|
||||
obs_sceneitem_t *item = (obs_sceneitem_t *)calldata_ptr(data, "item");
|
||||
|
||||
if (item == window->item)
|
||||
window->DisconnectItemSignals();
|
||||
|
@ -152,45 +149,47 @@ void VisibilityItemWidget::OBSSceneItemRemove(void *param, calldata_t *data)
|
|||
void VisibilityItemWidget::OBSSceneItemVisible(void *param, calldata_t *data)
|
||||
{
|
||||
VisibilityItemWidget *window =
|
||||
reinterpret_cast<VisibilityItemWidget*>(param);
|
||||
obs_sceneitem_t *curItem = (obs_sceneitem_t*)calldata_ptr(data, "item");
|
||||
reinterpret_cast<VisibilityItemWidget *>(param);
|
||||
obs_sceneitem_t *curItem =
|
||||
(obs_sceneitem_t *)calldata_ptr(data, "item");
|
||||
bool enabled = calldata_bool(data, "visible");
|
||||
|
||||
if (window->item == curItem)
|
||||
QMetaObject::invokeMethod(window, "SourceEnabled",
|
||||
Q_ARG(bool, enabled));
|
||||
Q_ARG(bool, enabled));
|
||||
}
|
||||
|
||||
void VisibilityItemWidget::OBSSceneItemLocked(void *param, calldata_t *data)
|
||||
{
|
||||
VisibilityItemWidget *window =
|
||||
reinterpret_cast<VisibilityItemWidget*>(param);
|
||||
obs_sceneitem_t *curItem = (obs_sceneitem_t*)calldata_ptr(data, "item");
|
||||
reinterpret_cast<VisibilityItemWidget *>(param);
|
||||
obs_sceneitem_t *curItem =
|
||||
(obs_sceneitem_t *)calldata_ptr(data, "item");
|
||||
bool locked = calldata_bool(data, "locked");
|
||||
|
||||
if (window->item == curItem)
|
||||
QMetaObject::invokeMethod(window, "SourceLocked",
|
||||
Q_ARG(bool, locked));
|
||||
Q_ARG(bool, locked));
|
||||
}
|
||||
|
||||
void VisibilityItemWidget::OBSSourceEnabled(void *param, calldata_t *data)
|
||||
{
|
||||
VisibilityItemWidget *window =
|
||||
reinterpret_cast<VisibilityItemWidget*>(param);
|
||||
reinterpret_cast<VisibilityItemWidget *>(param);
|
||||
bool enabled = calldata_bool(data, "enabled");
|
||||
|
||||
QMetaObject::invokeMethod(window, "SourceEnabled",
|
||||
Q_ARG(bool, enabled));
|
||||
Q_ARG(bool, enabled));
|
||||
}
|
||||
|
||||
void VisibilityItemWidget::OBSSourceRenamed(void *param, calldata_t *data)
|
||||
{
|
||||
VisibilityItemWidget *window =
|
||||
reinterpret_cast<VisibilityItemWidget*>(param);
|
||||
reinterpret_cast<VisibilityItemWidget *>(param);
|
||||
const char *name = calldata_string(data, "new_name");
|
||||
|
||||
QMetaObject::invokeMethod(window, "SourceRenamed",
|
||||
Q_ARG(QString, QT_UTF8(name)));
|
||||
Q_ARG(QString, QT_UTF8(name)));
|
||||
}
|
||||
|
||||
void VisibilityItemWidget::VisibilityClicked(bool visible)
|
||||
|
@ -225,8 +224,8 @@ void VisibilityItemWidget::SourceRenamed(QString name)
|
|||
label->setText(name);
|
||||
}
|
||||
|
||||
void VisibilityItemWidget::SetColor(const QColor &color,
|
||||
bool active_, bool selected_)
|
||||
void VisibilityItemWidget::SetColor(const QColor &color, bool active_,
|
||||
bool selected_)
|
||||
{
|
||||
/* Do not update unless the state has actually changed */
|
||||
if (active_ == active && selected_ == selected)
|
||||
|
@ -248,19 +247,19 @@ VisibilityItemDelegate::VisibilityItemDelegate(QObject *parent)
|
|||
}
|
||||
|
||||
void VisibilityItemDelegate::paint(QPainter *painter,
|
||||
const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const
|
||||
const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
QStyledItemDelegate::paint(painter, option, index);
|
||||
|
||||
QObject *parentObj = parent();
|
||||
QListWidget *list = qobject_cast<QListWidget*>(parentObj);
|
||||
QListWidget *list = qobject_cast<QListWidget *>(parentObj);
|
||||
if (!list)
|
||||
return;
|
||||
|
||||
QListWidgetItem *item = list->item(index.row());
|
||||
VisibilityItemWidget *widget =
|
||||
qobject_cast<VisibilityItemWidget*>(list->itemWidget(item));
|
||||
qobject_cast<VisibilityItemWidget *>(list->itemWidget(item));
|
||||
if (!widget)
|
||||
return;
|
||||
|
||||
|
@ -269,8 +268,8 @@ void VisibilityItemDelegate::paint(QPainter *painter,
|
|||
|
||||
QPalette palette = list->palette();
|
||||
#if defined(_WIN32) || defined(__APPLE__)
|
||||
QPalette::ColorGroup group = active ?
|
||||
QPalette::Active : QPalette::Inactive;
|
||||
QPalette::ColorGroup group = active ? QPalette::Active
|
||||
: QPalette::Inactive;
|
||||
#else
|
||||
QPalette::ColorGroup group = QPalette::Active;
|
||||
#endif
|
||||
|
@ -292,7 +291,7 @@ void VisibilityItemDelegate::paint(QPainter *painter,
|
|||
}
|
||||
|
||||
void SetupVisibilityItem(QListWidget *list, QListWidgetItem *item,
|
||||
obs_source_t *source)
|
||||
obs_source_t *source)
|
||||
{
|
||||
VisibilityItemWidget *baseWidget = new VisibilityItemWidget(source);
|
||||
|
||||
|
@ -301,7 +300,7 @@ void SetupVisibilityItem(QListWidget *list, QListWidgetItem *item,
|
|||
}
|
||||
|
||||
void SetupVisibilityItem(QListWidget *list, QListWidgetItem *item,
|
||||
obs_sceneitem_t *sceneItem)
|
||||
obs_sceneitem_t *sceneItem)
|
||||
{
|
||||
VisibilityItemWidget *baseWidget = new VisibilityItemWidget(sceneItem);
|
||||
|
||||
|
|
|
@ -61,10 +61,10 @@ public:
|
|||
VisibilityItemDelegate(QObject *parent = nullptr);
|
||||
|
||||
void paint(QPainter *painter, const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const override;
|
||||
const QModelIndex &index) const override;
|
||||
};
|
||||
|
||||
void SetupVisibilityItem(QListWidget *list, QListWidgetItem *item,
|
||||
obs_source_t *source);
|
||||
obs_source_t *source);
|
||||
void SetupVisibilityItem(QListWidget *list, QListWidgetItem *item,
|
||||
obs_sceneitem_t *sceneItem);
|
||||
obs_sceneitem_t *sceneItem);
|
||||
|
|
|
@ -21,35 +21,35 @@ QWeakPointer<VolumeMeterTimer> VolumeMeter::updateTimer;
|
|||
void VolControl::OBSVolumeChanged(void *data, float db)
|
||||
{
|
||||
Q_UNUSED(db);
|
||||
VolControl *volControl = static_cast<VolControl*>(data);
|
||||
VolControl *volControl = static_cast<VolControl *>(data);
|
||||
|
||||
QMetaObject::invokeMethod(volControl, "VolumeChanged");
|
||||
}
|
||||
|
||||
void VolControl::OBSVolumeLevel(void *data,
|
||||
const float magnitude[MAX_AUDIO_CHANNELS],
|
||||
const float peak[MAX_AUDIO_CHANNELS],
|
||||
const float inputPeak[MAX_AUDIO_CHANNELS])
|
||||
const float magnitude[MAX_AUDIO_CHANNELS],
|
||||
const float peak[MAX_AUDIO_CHANNELS],
|
||||
const float inputPeak[MAX_AUDIO_CHANNELS])
|
||||
{
|
||||
VolControl *volControl = static_cast<VolControl*>(data);
|
||||
VolControl *volControl = static_cast<VolControl *>(data);
|
||||
|
||||
volControl->volMeter->setLevels(magnitude, peak, inputPeak);
|
||||
}
|
||||
|
||||
void VolControl::OBSVolumeMuted(void *data, calldata_t *calldata)
|
||||
{
|
||||
VolControl *volControl = static_cast<VolControl*>(data);
|
||||
VolControl *volControl = static_cast<VolControl *>(data);
|
||||
bool muted = calldata_bool(calldata, "muted");
|
||||
|
||||
QMetaObject::invokeMethod(volControl, "VolumeMuted",
|
||||
Q_ARG(bool, muted));
|
||||
Q_ARG(bool, muted));
|
||||
}
|
||||
|
||||
void VolControl::VolumeChanged()
|
||||
{
|
||||
slider->blockSignals(true);
|
||||
slider->setValue((int) (obs_fader_get_deflection(obs_fader) *
|
||||
FADER_PRECISION));
|
||||
slider->setValue(
|
||||
(int)(obs_fader_get_deflection(obs_fader) * FADER_PRECISION));
|
||||
slider->blockSignals(false);
|
||||
|
||||
updateText();
|
||||
|
@ -75,13 +75,12 @@ void VolControl::SliderChanged(int vol)
|
|||
void VolControl::updateText()
|
||||
{
|
||||
QString db = QString::number(obs_fader_get_db(obs_fader), 'f', 1)
|
||||
.append(" dB");
|
||||
.append(" dB");
|
||||
volLabel->setText(db);
|
||||
|
||||
bool muted = obs_source_muted(source);
|
||||
const char *accTextLookup = muted
|
||||
? "VolControl.SliderMuted"
|
||||
: "VolControl.SliderUnmuted";
|
||||
const char *accTextLookup = muted ? "VolControl.SliderMuted"
|
||||
: "VolControl.SliderUnmuted";
|
||||
|
||||
QString sourceName = obs_source_get_name(source);
|
||||
QString accText = QTStr(accTextLookup).arg(sourceName, db);
|
||||
|
@ -115,16 +114,16 @@ void VolControl::setPeakMeterType(enum obs_peak_meter_type peakMeterType)
|
|||
}
|
||||
|
||||
VolControl::VolControl(OBSSource source_, bool showConfig, bool vertical)
|
||||
: source (std::move(source_)),
|
||||
levelTotal (0.0f),
|
||||
levelCount (0.0f),
|
||||
obs_fader (obs_fader_create(OBS_FADER_LOG)),
|
||||
obs_volmeter (obs_volmeter_create(OBS_FADER_LOG)),
|
||||
vertical (vertical)
|
||||
: source(std::move(source_)),
|
||||
levelTotal(0.0f),
|
||||
levelCount(0.0f),
|
||||
obs_fader(obs_fader_create(OBS_FADER_LOG)),
|
||||
obs_volmeter(obs_volmeter_create(OBS_FADER_LOG)),
|
||||
vertical(vertical)
|
||||
{
|
||||
nameLabel = new QLabel();
|
||||
volLabel = new QLabel();
|
||||
mute = new MuteCheckBox();
|
||||
volLabel = new QLabel();
|
||||
mute = new MuteCheckBox();
|
||||
|
||||
QString sourceName = obs_source_get_name(source);
|
||||
setObjectName(sourceName);
|
||||
|
@ -134,15 +133,15 @@ VolControl::VolControl(OBSSource source_, bool showConfig, bool vertical)
|
|||
config->setProperty("themeID", "configIconSmall");
|
||||
config->setFlat(true);
|
||||
config->setSizePolicy(QSizePolicy::Maximum,
|
||||
QSizePolicy::Maximum);
|
||||
QSizePolicy::Maximum);
|
||||
config->setMaximumSize(22, 22);
|
||||
config->setAutoDefault(false);
|
||||
|
||||
config->setAccessibleName(QTStr("VolControl.Properties")
|
||||
.arg(sourceName));
|
||||
config->setAccessibleName(
|
||||
QTStr("VolControl.Properties").arg(sourceName));
|
||||
|
||||
connect(config, &QAbstractButton::clicked,
|
||||
this, &VolControl::EmitConfigClicked);
|
||||
connect(config, &QAbstractButton::clicked, this,
|
||||
&VolControl::EmitConfigClicked);
|
||||
}
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
|
@ -153,10 +152,10 @@ VolControl::VolControl(OBSSource source_, bool showConfig, bool vertical)
|
|||
QHBoxLayout *nameLayout = new QHBoxLayout;
|
||||
QHBoxLayout *controlLayout = new QHBoxLayout;
|
||||
QHBoxLayout *volLayout = new QHBoxLayout;
|
||||
QHBoxLayout *meterLayout = new QHBoxLayout;
|
||||
QHBoxLayout *meterLayout = new QHBoxLayout;
|
||||
|
||||
volMeter = new VolumeMeter(nullptr, obs_volmeter, true);
|
||||
slider = new SliderIgnoreScroll(Qt::Vertical);
|
||||
volMeter = new VolumeMeter(nullptr, obs_volmeter, true);
|
||||
slider = new SliderIgnoreScroll(Qt::Vertical);
|
||||
|
||||
nameLayout->setAlignment(Qt::AlignCenter);
|
||||
meterLayout->setAlignment(Qt::AlignCenter);
|
||||
|
@ -195,18 +194,18 @@ VolControl::VolControl(OBSSource source_, bool showConfig, bool vertical)
|
|||
|
||||
setMaximumWidth(110);
|
||||
} else {
|
||||
QHBoxLayout *volLayout = new QHBoxLayout;
|
||||
QHBoxLayout *volLayout = new QHBoxLayout;
|
||||
QHBoxLayout *textLayout = new QHBoxLayout;
|
||||
QHBoxLayout *botLayout = new QHBoxLayout;
|
||||
QHBoxLayout *botLayout = new QHBoxLayout;
|
||||
|
||||
volMeter = new VolumeMeter(nullptr, obs_volmeter, false);
|
||||
slider = new SliderIgnoreScroll(Qt::Horizontal);
|
||||
volMeter = new VolumeMeter(nullptr, obs_volmeter, false);
|
||||
slider = new SliderIgnoreScroll(Qt::Horizontal);
|
||||
|
||||
textLayout->setContentsMargins(0, 0, 0, 0);
|
||||
textLayout->addWidget(nameLabel);
|
||||
textLayout->addWidget(volLabel);
|
||||
textLayout->setAlignment(nameLabel, Qt::AlignLeft);
|
||||
textLayout->setAlignment(volLabel, Qt::AlignRight);
|
||||
textLayout->setAlignment(volLabel, Qt::AlignRight);
|
||||
|
||||
volLayout->addWidget(slider);
|
||||
volLayout->addWidget(mute);
|
||||
|
@ -229,7 +228,7 @@ VolControl::VolControl(OBSSource source_, bool showConfig, bool vertical)
|
|||
setLayout(mainLayout);
|
||||
|
||||
QFont font = nameLabel->font();
|
||||
font.setPointSize(font.pointSize()-1);
|
||||
font.setPointSize(font.pointSize() - 1);
|
||||
|
||||
nameLabel->setText(sourceName);
|
||||
nameLabel->setFont(font);
|
||||
|
@ -244,13 +243,13 @@ VolControl::VolControl(OBSSource source_, bool showConfig, bool vertical)
|
|||
obs_fader_add_callback(obs_fader, OBSVolumeChanged, this);
|
||||
obs_volmeter_add_callback(obs_volmeter, OBSVolumeLevel, this);
|
||||
|
||||
signal_handler_connect(obs_source_get_signal_handler(source),
|
||||
"mute", OBSVolumeMuted, this);
|
||||
signal_handler_connect(obs_source_get_signal_handler(source), "mute",
|
||||
OBSVolumeMuted, this);
|
||||
|
||||
QWidget::connect(slider, SIGNAL(valueChanged(int)),
|
||||
this, SLOT(SliderChanged(int)));
|
||||
QWidget::connect(mute, SIGNAL(clicked(bool)),
|
||||
this, SLOT(SetMuted(bool)));
|
||||
QWidget::connect(slider, SIGNAL(valueChanged(int)), this,
|
||||
SLOT(SliderChanged(int)));
|
||||
QWidget::connect(mute, SIGNAL(clicked(bool)), this,
|
||||
SLOT(SetMuted(bool)));
|
||||
|
||||
obs_fader_attach_source(obs_fader, source);
|
||||
obs_volmeter_attach_source(obs_volmeter, source);
|
||||
|
@ -276,8 +275,8 @@ VolControl::~VolControl()
|
|||
obs_fader_remove_callback(obs_fader, OBSVolumeChanged, this);
|
||||
obs_volmeter_remove_callback(obs_volmeter, OBSVolumeLevel, this);
|
||||
|
||||
signal_handler_disconnect(obs_source_get_signal_handler(source),
|
||||
"mute", OBSVolumeMuted, this);
|
||||
signal_handler_disconnect(obs_source_get_signal_handler(source), "mute",
|
||||
OBSVolumeMuted, this);
|
||||
|
||||
obs_fader_destroy(obs_fader);
|
||||
obs_volmeter_destroy(obs_volmeter);
|
||||
|
@ -517,34 +516,33 @@ void VolumeMeter::wheelEvent(QWheelEvent *event)
|
|||
}
|
||||
|
||||
VolumeMeter::VolumeMeter(QWidget *parent, obs_volmeter_t *obs_volmeter,
|
||||
bool vertical)
|
||||
: QWidget(parent), obs_volmeter(obs_volmeter),
|
||||
vertical(vertical)
|
||||
bool vertical)
|
||||
: QWidget(parent), obs_volmeter(obs_volmeter), vertical(vertical)
|
||||
{
|
||||
// Use a font that can be rendered small.
|
||||
tickFont = QFont("Arial");
|
||||
tickFont.setPixelSize(7);
|
||||
// Default meter color settings, they only show if
|
||||
// there is no stylesheet, do not remove.
|
||||
backgroundNominalColor.setRgb(0x26, 0x7f, 0x26); // Dark green
|
||||
backgroundWarningColor.setRgb(0x7f, 0x7f, 0x26); // Dark yellow
|
||||
backgroundErrorColor.setRgb(0x7f, 0x26, 0x26); // Dark red
|
||||
foregroundNominalColor.setRgb(0x4c, 0xff, 0x4c); // Bright green
|
||||
foregroundWarningColor.setRgb(0xff, 0xff, 0x4c); // Bright yellow
|
||||
foregroundErrorColor.setRgb(0xff, 0x4c, 0x4c); // Bright red
|
||||
clipColor.setRgb(0xff, 0xff, 0xff); // Bright white
|
||||
magnitudeColor.setRgb(0x00, 0x00, 0x00); // Black
|
||||
majorTickColor.setRgb(0xff, 0xff, 0xff); // Black
|
||||
minorTickColor.setRgb(0xcc, 0xcc, 0xcc); // Black
|
||||
minimumLevel = -60.0; // -60 dB
|
||||
warningLevel = -20.0; // -20 dB
|
||||
errorLevel = -9.0; // -9 dB
|
||||
clipLevel = -0.5; // -0.5 dB
|
||||
minimumInputLevel = -50.0; // -50 dB
|
||||
peakDecayRate = 11.76; // 20 dB / 1.7 sec
|
||||
magnitudeIntegrationTime = 0.3; // 99% in 300 ms
|
||||
peakHoldDuration = 20.0; // 20 seconds
|
||||
inputPeakHoldDuration = 1.0; // 1 second
|
||||
backgroundNominalColor.setRgb(0x26, 0x7f, 0x26); // Dark green
|
||||
backgroundWarningColor.setRgb(0x7f, 0x7f, 0x26); // Dark yellow
|
||||
backgroundErrorColor.setRgb(0x7f, 0x26, 0x26); // Dark red
|
||||
foregroundNominalColor.setRgb(0x4c, 0xff, 0x4c); // Bright green
|
||||
foregroundWarningColor.setRgb(0xff, 0xff, 0x4c); // Bright yellow
|
||||
foregroundErrorColor.setRgb(0xff, 0x4c, 0x4c); // Bright red
|
||||
clipColor.setRgb(0xff, 0xff, 0xff); // Bright white
|
||||
magnitudeColor.setRgb(0x00, 0x00, 0x00); // Black
|
||||
majorTickColor.setRgb(0xff, 0xff, 0xff); // Black
|
||||
minorTickColor.setRgb(0xcc, 0xcc, 0xcc); // Black
|
||||
minimumLevel = -60.0; // -60 dB
|
||||
warningLevel = -20.0; // -20 dB
|
||||
errorLevel = -9.0; // -9 dB
|
||||
clipLevel = -0.5; // -0.5 dB
|
||||
minimumInputLevel = -50.0; // -50 dB
|
||||
peakDecayRate = 11.76; // 20 dB / 1.7 sec
|
||||
magnitudeIntegrationTime = 0.3; // 99% in 300 ms
|
||||
peakHoldDuration = 20.0; // 20 seconds
|
||||
inputPeakHoldDuration = 1.0; // 1 second
|
||||
|
||||
channels = (int)audio_output_get_channels(obs_get_audio());
|
||||
|
||||
|
@ -566,8 +564,8 @@ VolumeMeter::~VolumeMeter()
|
|||
}
|
||||
|
||||
void VolumeMeter::setLevels(const float magnitude[MAX_AUDIO_CHANNELS],
|
||||
const float peak[MAX_AUDIO_CHANNELS],
|
||||
const float inputPeak[MAX_AUDIO_CHANNELS])
|
||||
const float peak[MAX_AUDIO_CHANNELS],
|
||||
const float inputPeak[MAX_AUDIO_CHANNELS])
|
||||
{
|
||||
uint64_t ts = os_gettime_ns();
|
||||
QMutexLocker locker(&dataMutex);
|
||||
|
@ -632,11 +630,12 @@ inline bool VolumeMeter::detectIdle(uint64_t ts)
|
|||
}
|
||||
}
|
||||
|
||||
inline void VolumeMeter::calculateBallisticsForChannel(int channelNr,
|
||||
uint64_t ts, qreal timeSinceLastRedraw)
|
||||
inline void
|
||||
VolumeMeter::calculateBallisticsForChannel(int channelNr, uint64_t ts,
|
||||
qreal timeSinceLastRedraw)
|
||||
{
|
||||
if (currentPeak[channelNr] >= displayPeak[channelNr] ||
|
||||
isnan(displayPeak[channelNr])) {
|
||||
isnan(displayPeak[channelNr])) {
|
||||
// Attack of peak is immediate.
|
||||
displayPeak[channelNr] = currentPeak[channelNr];
|
||||
} else {
|
||||
|
@ -645,11 +644,11 @@ inline void VolumeMeter::calculateBallisticsForChannel(int channelNr,
|
|||
// 24 dB / 2.8 seconds for Slow Profile (Type II PPM)
|
||||
float decay = float(peakDecayRate * timeSinceLastRedraw);
|
||||
displayPeak[channelNr] = CLAMP(displayPeak[channelNr] - decay,
|
||||
currentPeak[channelNr], 0);
|
||||
currentPeak[channelNr], 0);
|
||||
}
|
||||
|
||||
if (currentPeak[channelNr] >= displayPeakHold[channelNr] ||
|
||||
!isfinite(displayPeakHold[channelNr])) {
|
||||
!isfinite(displayPeakHold[channelNr])) {
|
||||
// Attack of peak-hold is immediate, but keep track
|
||||
// when it was last updated.
|
||||
displayPeakHold[channelNr] = currentPeak[channelNr];
|
||||
|
@ -657,8 +656,10 @@ inline void VolumeMeter::calculateBallisticsForChannel(int channelNr,
|
|||
} else {
|
||||
// The peak and hold falls back to peak
|
||||
// after 20 seconds.
|
||||
qreal timeSinceLastPeak = (uint64_t)(ts -
|
||||
displayPeakHoldLastUpdateTime[channelNr]) * 0.000000001;
|
||||
qreal timeSinceLastPeak =
|
||||
(uint64_t)(ts -
|
||||
displayPeakHoldLastUpdateTime[channelNr]) *
|
||||
0.000000001;
|
||||
if (timeSinceLastPeak > peakHoldDuration) {
|
||||
displayPeakHold[channelNr] = currentPeak[channelNr];
|
||||
displayPeakHoldLastUpdateTime[channelNr] = ts;
|
||||
|
@ -666,21 +667,22 @@ inline void VolumeMeter::calculateBallisticsForChannel(int channelNr,
|
|||
}
|
||||
|
||||
if (currentInputPeak[channelNr] >= displayInputPeakHold[channelNr] ||
|
||||
!isfinite(displayInputPeakHold[channelNr])) {
|
||||
!isfinite(displayInputPeakHold[channelNr])) {
|
||||
// Attack of peak-hold is immediate, but keep track
|
||||
// when it was last updated.
|
||||
displayInputPeakHold[channelNr] = currentInputPeak[channelNr];
|
||||
displayInputPeakHoldLastUpdateTime[channelNr] = ts;
|
||||
} else {
|
||||
// The peak and hold falls back to peak after 1 second.
|
||||
qreal timeSinceLastPeak = (uint64_t)(ts -
|
||||
displayInputPeakHoldLastUpdateTime[channelNr]) *
|
||||
qreal timeSinceLastPeak =
|
||||
(uint64_t)(
|
||||
ts -
|
||||
displayInputPeakHoldLastUpdateTime[channelNr]) *
|
||||
0.000000001;
|
||||
if (timeSinceLastPeak > inputPeakHoldDuration) {
|
||||
displayInputPeakHold[channelNr] =
|
||||
currentInputPeak[channelNr];
|
||||
displayInputPeakHoldLastUpdateTime[channelNr] =
|
||||
ts;
|
||||
displayInputPeakHoldLastUpdateTime[channelNr] = ts;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -692,27 +694,29 @@ inline void VolumeMeter::calculateBallisticsForChannel(int channelNr,
|
|||
// A VU meter will integrate to the new value to 99% in 300 ms.
|
||||
// The calculation here is very simplified and is more accurate
|
||||
// with higher frame-rate.
|
||||
float attack = float((currentMagnitude[channelNr] -
|
||||
displayMagnitude[channelNr]) *
|
||||
(timeSinceLastRedraw /
|
||||
magnitudeIntegrationTime) * 0.99);
|
||||
displayMagnitude[channelNr] = CLAMP(displayMagnitude[channelNr]
|
||||
+ attack, (float)minimumLevel, 0);
|
||||
float attack =
|
||||
float((currentMagnitude[channelNr] -
|
||||
displayMagnitude[channelNr]) *
|
||||
(timeSinceLastRedraw / magnitudeIntegrationTime) *
|
||||
0.99);
|
||||
displayMagnitude[channelNr] =
|
||||
CLAMP(displayMagnitude[channelNr] + attack,
|
||||
(float)minimumLevel, 0);
|
||||
}
|
||||
}
|
||||
|
||||
inline void VolumeMeter::calculateBallistics(uint64_t ts,
|
||||
qreal timeSinceLastRedraw)
|
||||
qreal timeSinceLastRedraw)
|
||||
{
|
||||
QMutexLocker locker(&dataMutex);
|
||||
|
||||
for (int channelNr = 0; channelNr < MAX_AUDIO_CHANNELS; channelNr++)
|
||||
calculateBallisticsForChannel(channelNr, ts,
|
||||
timeSinceLastRedraw);
|
||||
timeSinceLastRedraw);
|
||||
}
|
||||
|
||||
void VolumeMeter::paintInputMeter(QPainter &painter, int x, int y, int width,
|
||||
int height, float peakHold)
|
||||
int height, float peakHold)
|
||||
{
|
||||
QMutexLocker locker(&dataMutex);
|
||||
QColor color;
|
||||
|
@ -732,7 +736,7 @@ void VolumeMeter::paintInputMeter(QPainter &painter, int x, int y, int width,
|
|||
}
|
||||
|
||||
void VolumeMeter::paintHTicks(QPainter &painter, int x, int y, int width,
|
||||
int height)
|
||||
int height)
|
||||
{
|
||||
qreal scale = width / minimumLevel;
|
||||
|
||||
|
@ -740,7 +744,7 @@ void VolumeMeter::paintHTicks(QPainter &painter, int x, int y, int width,
|
|||
painter.setPen(majorTickColor);
|
||||
|
||||
// Draw major tick lines and numeric indicators.
|
||||
for (int i = 0; i >= minimumLevel; i-= 5) {
|
||||
for (int i = 0; i >= minimumLevel; i -= 5) {
|
||||
int position = int(x + width - (i * scale) - 1);
|
||||
QString str = QString::number(i);
|
||||
|
||||
|
@ -768,7 +772,7 @@ void VolumeMeter::paintVTicks(QPainter &painter, int x, int y, int height)
|
|||
painter.setPen(majorTickColor);
|
||||
|
||||
// Draw major tick lines and numeric indicators.
|
||||
for (int i = 0; i >= minimumLevel; i-= 5) {
|
||||
for (int i = 0; i >= minimumLevel; i -= 5) {
|
||||
int position = y + int((i * scale) - 1);
|
||||
QString str = QString::number(i);
|
||||
|
||||
|
@ -798,22 +802,23 @@ void VolumeMeter::ClipEnding()
|
|||
}
|
||||
|
||||
void VolumeMeter::paintHMeter(QPainter &painter, int x, int y, int width,
|
||||
int height, float magnitude, float peak, float peakHold)
|
||||
int height, float magnitude, float peak,
|
||||
float peakHold)
|
||||
{
|
||||
qreal scale = width / minimumLevel;
|
||||
|
||||
QMutexLocker locker(&dataMutex);
|
||||
int minimumPosition = x + 0;
|
||||
int maximumPosition = x + width;
|
||||
int magnitudePosition = int(x + width - (magnitude * scale));
|
||||
int peakPosition = int(x + width - (peak * scale));
|
||||
int peakHoldPosition = int(x + width - (peakHold * scale));
|
||||
int warningPosition = int(x + width - (warningLevel * scale));
|
||||
int errorPosition = int(x + width - (errorLevel * scale));
|
||||
int minimumPosition = x + 0;
|
||||
int maximumPosition = x + width;
|
||||
int magnitudePosition = int(x + width - (magnitude * scale));
|
||||
int peakPosition = int(x + width - (peak * scale));
|
||||
int peakHoldPosition = int(x + width - (peakHold * scale));
|
||||
int warningPosition = int(x + width - (warningLevel * scale));
|
||||
int errorPosition = int(x + width - (errorLevel * scale));
|
||||
|
||||
int nominalLength = warningPosition - minimumPosition;
|
||||
int warningLength = errorPosition - warningPosition;
|
||||
int errorLength = maximumPosition - errorPosition;
|
||||
int nominalLength = warningPosition - minimumPosition;
|
||||
int warningLength = errorPosition - warningPosition;
|
||||
int errorLength = maximumPosition - errorPosition;
|
||||
locker.unlock();
|
||||
|
||||
if (clipping) {
|
||||
|
@ -822,87 +827,89 @@ void VolumeMeter::paintHMeter(QPainter &painter, int x, int y, int width,
|
|||
|
||||
if (peakPosition < minimumPosition) {
|
||||
painter.fillRect(minimumPosition, y, nominalLength, height,
|
||||
backgroundNominalColor);
|
||||
backgroundNominalColor);
|
||||
painter.fillRect(warningPosition, y, warningLength, height,
|
||||
backgroundWarningColor);
|
||||
backgroundWarningColor);
|
||||
painter.fillRect(errorPosition, y, errorLength, height,
|
||||
backgroundErrorColor);
|
||||
backgroundErrorColor);
|
||||
} else if (peakPosition < warningPosition) {
|
||||
painter.fillRect(minimumPosition, y, peakPosition -
|
||||
minimumPosition, height,
|
||||
foregroundNominalColor);
|
||||
painter.fillRect(peakPosition, y, warningPosition -
|
||||
peakPosition, height, backgroundNominalColor);
|
||||
painter.fillRect(minimumPosition, y,
|
||||
peakPosition - minimumPosition, height,
|
||||
foregroundNominalColor);
|
||||
painter.fillRect(peakPosition, y,
|
||||
warningPosition - peakPosition, height,
|
||||
backgroundNominalColor);
|
||||
painter.fillRect(warningPosition, y, warningLength, height,
|
||||
backgroundWarningColor);
|
||||
backgroundWarningColor);
|
||||
painter.fillRect(errorPosition, y, errorLength, height,
|
||||
backgroundErrorColor);
|
||||
backgroundErrorColor);
|
||||
} else if (peakPosition < errorPosition) {
|
||||
painter.fillRect(minimumPosition, y, nominalLength, height,
|
||||
foregroundNominalColor);
|
||||
foregroundNominalColor);
|
||||
painter.fillRect(warningPosition, y,
|
||||
peakPosition - warningPosition, height,
|
||||
foregroundWarningColor);
|
||||
painter.fillRect(peakPosition, y, errorPosition -
|
||||
peakPosition, height, backgroundWarningColor);
|
||||
peakPosition - warningPosition, height,
|
||||
foregroundWarningColor);
|
||||
painter.fillRect(peakPosition, y, errorPosition - peakPosition,
|
||||
height, backgroundWarningColor);
|
||||
painter.fillRect(errorPosition, y, errorLength, height,
|
||||
backgroundErrorColor);
|
||||
backgroundErrorColor);
|
||||
} else if (peakPosition < maximumPosition) {
|
||||
painter.fillRect(minimumPosition, y, nominalLength, height,
|
||||
foregroundNominalColor);
|
||||
foregroundNominalColor);
|
||||
painter.fillRect(warningPosition, y, warningLength, height,
|
||||
foregroundWarningColor);
|
||||
foregroundWarningColor);
|
||||
painter.fillRect(errorPosition, y, peakPosition - errorPosition,
|
||||
height, foregroundErrorColor);
|
||||
height, foregroundErrorColor);
|
||||
painter.fillRect(peakPosition, y,
|
||||
maximumPosition - peakPosition, height,
|
||||
backgroundErrorColor);
|
||||
maximumPosition - peakPosition, height,
|
||||
backgroundErrorColor);
|
||||
} else {
|
||||
if (!clipping) {
|
||||
QTimer::singleShot(CLIP_FLASH_DURATION_MS, this,
|
||||
SLOT(ClipEnding()));
|
||||
SLOT(ClipEnding()));
|
||||
clipping = true;
|
||||
}
|
||||
|
||||
int end = errorLength + warningLength + nominalLength;
|
||||
painter.fillRect(minimumPosition, y, end, height,
|
||||
QBrush(foregroundErrorColor));
|
||||
QBrush(foregroundErrorColor));
|
||||
}
|
||||
|
||||
if (peakHoldPosition - 3 < minimumPosition)
|
||||
;// Peak-hold below minimum, no drawing.
|
||||
; // Peak-hold below minimum, no drawing.
|
||||
else if (peakHoldPosition < warningPosition)
|
||||
painter.fillRect(peakHoldPosition - 3, y, 3, height,
|
||||
foregroundNominalColor);
|
||||
foregroundNominalColor);
|
||||
else if (peakHoldPosition < errorPosition)
|
||||
painter.fillRect(peakHoldPosition - 3, y, 3, height,
|
||||
foregroundWarningColor);
|
||||
foregroundWarningColor);
|
||||
else
|
||||
painter.fillRect(peakHoldPosition - 3, y, 3, height,
|
||||
foregroundErrorColor);
|
||||
foregroundErrorColor);
|
||||
|
||||
if (magnitudePosition - 3 >= minimumPosition)
|
||||
painter.fillRect(magnitudePosition - 3, y, 3, height,
|
||||
magnitudeColor);
|
||||
magnitudeColor);
|
||||
}
|
||||
|
||||
void VolumeMeter::paintVMeter(QPainter &painter, int x, int y, int width,
|
||||
int height, float magnitude, float peak, float peakHold)
|
||||
int height, float magnitude, float peak,
|
||||
float peakHold)
|
||||
{
|
||||
qreal scale = height / minimumLevel;
|
||||
|
||||
QMutexLocker locker(&dataMutex);
|
||||
int minimumPosition = y + 0;
|
||||
int maximumPosition = y + height;
|
||||
int magnitudePosition = int(y + height - (magnitude * scale));
|
||||
int peakPosition = int(y + height - (peak * scale));
|
||||
int peakHoldPosition = int(y + height - (peakHold * scale));
|
||||
int warningPosition = int(y + height - (warningLevel * scale));
|
||||
int errorPosition = int(y + height - (errorLevel * scale));
|
||||
int minimumPosition = y + 0;
|
||||
int maximumPosition = y + height;
|
||||
int magnitudePosition = int(y + height - (magnitude * scale));
|
||||
int peakPosition = int(y + height - (peak * scale));
|
||||
int peakHoldPosition = int(y + height - (peakHold * scale));
|
||||
int warningPosition = int(y + height - (warningLevel * scale));
|
||||
int errorPosition = int(y + height - (errorLevel * scale));
|
||||
|
||||
int nominalLength = warningPosition - minimumPosition;
|
||||
int warningLength = errorPosition - warningPosition;
|
||||
int errorLength = maximumPosition - errorPosition;
|
||||
int nominalLength = warningPosition - minimumPosition;
|
||||
int warningLength = errorPosition - warningPosition;
|
||||
int errorLength = maximumPosition - errorPosition;
|
||||
locker.unlock();
|
||||
|
||||
if (clipping) {
|
||||
|
@ -911,65 +918,71 @@ void VolumeMeter::paintVMeter(QPainter &painter, int x, int y, int width,
|
|||
|
||||
if (peakPosition < minimumPosition) {
|
||||
painter.fillRect(x, minimumPosition, width, nominalLength,
|
||||
backgroundNominalColor);
|
||||
backgroundNominalColor);
|
||||
painter.fillRect(x, warningPosition, width, warningLength,
|
||||
backgroundWarningColor);
|
||||
backgroundWarningColor);
|
||||
painter.fillRect(x, errorPosition, width, errorLength,
|
||||
backgroundErrorColor);
|
||||
backgroundErrorColor);
|
||||
} else if (peakPosition < warningPosition) {
|
||||
painter.fillRect(x, minimumPosition, width, peakPosition -
|
||||
minimumPosition, foregroundNominalColor);
|
||||
painter.fillRect(x, peakPosition, width, warningPosition -
|
||||
peakPosition, backgroundNominalColor);
|
||||
painter.fillRect(x, minimumPosition, width,
|
||||
peakPosition - minimumPosition,
|
||||
foregroundNominalColor);
|
||||
painter.fillRect(x, peakPosition, width,
|
||||
warningPosition - peakPosition,
|
||||
backgroundNominalColor);
|
||||
painter.fillRect(x, warningPosition, width, warningLength,
|
||||
backgroundWarningColor);
|
||||
backgroundWarningColor);
|
||||
painter.fillRect(x, errorPosition, width, errorLength,
|
||||
backgroundErrorColor);
|
||||
backgroundErrorColor);
|
||||
} else if (peakPosition < errorPosition) {
|
||||
painter.fillRect(x,minimumPosition, width, nominalLength,
|
||||
foregroundNominalColor);
|
||||
painter.fillRect(x, warningPosition, width, peakPosition -
|
||||
warningPosition, foregroundWarningColor);
|
||||
painter.fillRect(x, peakPosition, width, errorPosition -
|
||||
peakPosition, backgroundWarningColor);
|
||||
painter.fillRect(x, minimumPosition, width, nominalLength,
|
||||
foregroundNominalColor);
|
||||
painter.fillRect(x, warningPosition, width,
|
||||
peakPosition - warningPosition,
|
||||
foregroundWarningColor);
|
||||
painter.fillRect(x, peakPosition, width,
|
||||
errorPosition - peakPosition,
|
||||
backgroundWarningColor);
|
||||
painter.fillRect(x, errorPosition, width, errorLength,
|
||||
backgroundErrorColor);
|
||||
backgroundErrorColor);
|
||||
} else if (peakPosition < maximumPosition) {
|
||||
painter.fillRect(x, minimumPosition, width, nominalLength,
|
||||
foregroundNominalColor);
|
||||
foregroundNominalColor);
|
||||
painter.fillRect(x, warningPosition, width, warningLength,
|
||||
foregroundWarningColor);
|
||||
painter.fillRect(x, errorPosition, width, peakPosition -
|
||||
errorPosition, foregroundErrorColor);
|
||||
painter.fillRect(x, peakPosition, width, maximumPosition -
|
||||
peakPosition, backgroundErrorColor);
|
||||
foregroundWarningColor);
|
||||
painter.fillRect(x, errorPosition, width,
|
||||
peakPosition - errorPosition,
|
||||
foregroundErrorColor);
|
||||
painter.fillRect(x, peakPosition, width,
|
||||
maximumPosition - peakPosition,
|
||||
backgroundErrorColor);
|
||||
} else {
|
||||
if (!clipping) {
|
||||
QTimer::singleShot(CLIP_FLASH_DURATION_MS, this,
|
||||
SLOT(ClipEnding()));
|
||||
SLOT(ClipEnding()));
|
||||
clipping = true;
|
||||
}
|
||||
|
||||
int end = errorLength + warningLength + nominalLength;
|
||||
painter.fillRect(x, minimumPosition, width, end,
|
||||
QBrush(foregroundErrorColor));
|
||||
QBrush(foregroundErrorColor));
|
||||
}
|
||||
|
||||
if (peakHoldPosition - 3 < minimumPosition)
|
||||
;// Peak-hold below minimum, no drawing.
|
||||
; // Peak-hold below minimum, no drawing.
|
||||
else if (peakHoldPosition < warningPosition)
|
||||
painter.fillRect(x, peakHoldPosition - 3, width, 3,
|
||||
foregroundNominalColor);
|
||||
foregroundNominalColor);
|
||||
else if (peakHoldPosition < errorPosition)
|
||||
painter.fillRect(x, peakHoldPosition - 3, width, 3,
|
||||
foregroundWarningColor);
|
||||
foregroundWarningColor);
|
||||
else
|
||||
painter.fillRect(x, peakHoldPosition - 3, width, 3,
|
||||
foregroundErrorColor);
|
||||
foregroundErrorColor);
|
||||
|
||||
if (magnitudePosition - 3 >= minimumPosition)
|
||||
painter.fillRect(x, magnitudePosition - 3, width, 3,
|
||||
magnitudeColor);
|
||||
magnitudeColor);
|
||||
}
|
||||
|
||||
void VolumeMeter::paintEvent(QPaintEvent *event)
|
||||
|
@ -978,7 +991,7 @@ void VolumeMeter::paintEvent(QPaintEvent *event)
|
|||
qreal timeSinceLastRedraw = (ts - lastRedrawTime) * 0.000000001;
|
||||
|
||||
const QRect rect = event->region().boundingRect();
|
||||
int width = rect.width();
|
||||
int width = rect.width();
|
||||
int height = rect.height();
|
||||
|
||||
handleChannelCofigurationChange();
|
||||
|
@ -992,7 +1005,7 @@ void VolumeMeter::paintEvent(QPaintEvent *event)
|
|||
else
|
||||
tickPaintCacheSize = QSize(width, 9);
|
||||
if (tickPaintCache == nullptr ||
|
||||
tickPaintCache->size() != tickPaintCacheSize) {
|
||||
tickPaintCache->size() != tickPaintCacheSize) {
|
||||
delete tickPaintCache;
|
||||
tickPaintCache = new QPixmap(tickPaintCacheSize);
|
||||
|
||||
|
@ -1004,11 +1017,11 @@ void VolumeMeter::paintEvent(QPaintEvent *event)
|
|||
tickPainter.translate(0, height);
|
||||
tickPainter.scale(1, -1);
|
||||
paintVTicks(tickPainter, 0, 11,
|
||||
tickPaintCacheSize.height() - 11);
|
||||
tickPaintCacheSize.height() - 11);
|
||||
} else {
|
||||
paintHTicks(tickPainter, 6, 0,
|
||||
tickPaintCacheSize.width() - 6,
|
||||
tickPaintCacheSize.height());
|
||||
tickPaintCacheSize.width() - 6,
|
||||
tickPaintCacheSize.height());
|
||||
}
|
||||
tickPainter.end();
|
||||
}
|
||||
|
@ -1020,29 +1033,29 @@ void VolumeMeter::paintEvent(QPaintEvent *event)
|
|||
painter.translate(0, height);
|
||||
painter.scale(1, -1);
|
||||
painter.drawPixmap(displayNrAudioChannels * 4 - 1, 7,
|
||||
*tickPaintCache);
|
||||
*tickPaintCache);
|
||||
} else {
|
||||
painter.drawPixmap(0, height - 9, *tickPaintCache);
|
||||
}
|
||||
|
||||
for (int channelNr = 0; channelNr < displayNrAudioChannels;
|
||||
channelNr++) {
|
||||
channelNr++) {
|
||||
|
||||
int channelNrFixed = (displayNrAudioChannels == 1 &&
|
||||
channels > 2)
|
||||
? 2
|
||||
: channelNr;
|
||||
int channelNrFixed =
|
||||
(displayNrAudioChannels == 1 && channels > 2)
|
||||
? 2
|
||||
: channelNr;
|
||||
|
||||
if (vertical)
|
||||
paintVMeter(painter, channelNr * 4, 8, 3, height - 10,
|
||||
displayMagnitude[channelNrFixed],
|
||||
displayPeak[channelNrFixed],
|
||||
displayPeakHold[channelNrFixed]);
|
||||
displayMagnitude[channelNrFixed],
|
||||
displayPeak[channelNrFixed],
|
||||
displayPeakHold[channelNrFixed]);
|
||||
else
|
||||
paintHMeter(painter, 5, channelNr * 4, width - 5, 3,
|
||||
displayMagnitude[channelNrFixed],
|
||||
displayPeak[channelNrFixed],
|
||||
displayPeakHold[channelNrFixed]);
|
||||
displayMagnitude[channelNrFixed],
|
||||
displayPeak[channelNrFixed],
|
||||
displayPeakHold[channelNrFixed]);
|
||||
|
||||
if (idle)
|
||||
continue;
|
||||
|
@ -1071,7 +1084,7 @@ void VolumeMeterTimer::RemoveVolControl(VolumeMeter *meter)
|
|||
volumeMeters.removeOne(meter);
|
||||
}
|
||||
|
||||
void VolumeMeterTimer::timerEvent(QTimerEvent*)
|
||||
void VolumeMeterTimer::timerEvent(QTimerEvent *)
|
||||
{
|
||||
for (VolumeMeter *meter : volumeMeters)
|
||||
meter->update();
|
||||
|
|
|
@ -11,74 +11,55 @@
|
|||
class QPushButton;
|
||||
class VolumeMeterTimer;
|
||||
|
||||
class VolumeMeter : public QWidget
|
||||
{
|
||||
class VolumeMeter : public QWidget {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QColor backgroundNominalColor
|
||||
READ getBackgroundNominalColor
|
||||
WRITE setBackgroundNominalColor DESIGNABLE true)
|
||||
Q_PROPERTY(QColor backgroundWarningColor
|
||||
READ getBackgroundWarningColor
|
||||
WRITE setBackgroundWarningColor DESIGNABLE true)
|
||||
Q_PROPERTY(QColor backgroundErrorColor
|
||||
READ getBackgroundErrorColor
|
||||
WRITE setBackgroundErrorColor DESIGNABLE true)
|
||||
Q_PROPERTY(QColor foregroundNominalColor
|
||||
READ getForegroundNominalColor
|
||||
WRITE setForegroundNominalColor DESIGNABLE true)
|
||||
Q_PROPERTY(QColor foregroundWarningColor
|
||||
READ getForegroundWarningColor
|
||||
WRITE setForegroundWarningColor DESIGNABLE true)
|
||||
Q_PROPERTY(QColor foregroundErrorColor
|
||||
READ getForegroundErrorColor
|
||||
WRITE setForegroundErrorColor DESIGNABLE true)
|
||||
Q_PROPERTY(QColor clipColor
|
||||
READ getClipColor
|
||||
WRITE setClipColor DESIGNABLE true)
|
||||
Q_PROPERTY(QColor magnitudeColor
|
||||
READ getMagnitudeColor
|
||||
WRITE setMagnitudeColor DESIGNABLE true)
|
||||
Q_PROPERTY(QColor majorTickColor
|
||||
READ getMajorTickColor
|
||||
WRITE setMajorTickColor DESIGNABLE true)
|
||||
Q_PROPERTY(QColor minorTickColor
|
||||
READ getMinorTickColor
|
||||
WRITE setMinorTickColor DESIGNABLE true)
|
||||
Q_PROPERTY(QColor backgroundNominalColor READ getBackgroundNominalColor
|
||||
WRITE setBackgroundNominalColor DESIGNABLE true)
|
||||
Q_PROPERTY(QColor backgroundWarningColor READ getBackgroundWarningColor
|
||||
WRITE setBackgroundWarningColor DESIGNABLE true)
|
||||
Q_PROPERTY(QColor backgroundErrorColor READ getBackgroundErrorColor
|
||||
WRITE setBackgroundErrorColor DESIGNABLE true)
|
||||
Q_PROPERTY(QColor foregroundNominalColor READ getForegroundNominalColor
|
||||
WRITE setForegroundNominalColor DESIGNABLE true)
|
||||
Q_PROPERTY(QColor foregroundWarningColor READ getForegroundWarningColor
|
||||
WRITE setForegroundWarningColor DESIGNABLE true)
|
||||
Q_PROPERTY(QColor foregroundErrorColor READ getForegroundErrorColor
|
||||
WRITE setForegroundErrorColor DESIGNABLE true)
|
||||
Q_PROPERTY(QColor clipColor READ getClipColor WRITE setClipColor
|
||||
DESIGNABLE true)
|
||||
Q_PROPERTY(QColor magnitudeColor READ getMagnitudeColor WRITE
|
||||
setMagnitudeColor DESIGNABLE true)
|
||||
Q_PROPERTY(QColor majorTickColor READ getMajorTickColor WRITE
|
||||
setMajorTickColor DESIGNABLE true)
|
||||
Q_PROPERTY(QColor minorTickColor READ getMinorTickColor WRITE
|
||||
setMinorTickColor DESIGNABLE true)
|
||||
|
||||
// Levels are denoted in dBFS.
|
||||
Q_PROPERTY(qreal minimumLevel
|
||||
READ getMinimumLevel
|
||||
WRITE setMinimumLevel DESIGNABLE true)
|
||||
Q_PROPERTY(qreal warningLevel
|
||||
READ getWarningLevel
|
||||
WRITE setWarningLevel DESIGNABLE true)
|
||||
Q_PROPERTY(qreal errorLevel
|
||||
READ getErrorLevel
|
||||
WRITE setErrorLevel DESIGNABLE true)
|
||||
Q_PROPERTY(qreal clipLevel
|
||||
READ getClipLevel
|
||||
WRITE setClipLevel DESIGNABLE true)
|
||||
Q_PROPERTY(qreal minimumInputLevel
|
||||
READ getMinimumInputLevel
|
||||
WRITE setMinimumInputLevel DESIGNABLE true)
|
||||
Q_PROPERTY(qreal minimumLevel READ getMinimumLevel WRITE setMinimumLevel
|
||||
DESIGNABLE true)
|
||||
Q_PROPERTY(qreal warningLevel READ getWarningLevel WRITE setWarningLevel
|
||||
DESIGNABLE true)
|
||||
Q_PROPERTY(qreal errorLevel READ getErrorLevel WRITE setErrorLevel
|
||||
DESIGNABLE true)
|
||||
Q_PROPERTY(qreal clipLevel READ getClipLevel WRITE setClipLevel
|
||||
DESIGNABLE true)
|
||||
Q_PROPERTY(qreal minimumInputLevel READ getMinimumInputLevel WRITE
|
||||
setMinimumInputLevel DESIGNABLE true)
|
||||
|
||||
// Rates are denoted in dB/second.
|
||||
Q_PROPERTY(qreal peakDecayRate
|
||||
READ getPeakDecayRate
|
||||
WRITE setPeakDecayRate DESIGNABLE true)
|
||||
Q_PROPERTY(qreal peakDecayRate READ getPeakDecayRate WRITE
|
||||
setPeakDecayRate DESIGNABLE true)
|
||||
|
||||
// Time in seconds for the VU meter to integrate over.
|
||||
Q_PROPERTY(qreal magnitudeIntegrationTime
|
||||
READ getMagnitudeIntegrationTime
|
||||
WRITE setMagnitudeIntegrationTime DESIGNABLE true)
|
||||
Q_PROPERTY(
|
||||
qreal magnitudeIntegrationTime READ getMagnitudeIntegrationTime
|
||||
WRITE setMagnitudeIntegrationTime DESIGNABLE true)
|
||||
|
||||
// Duration is denoted in seconds.
|
||||
Q_PROPERTY(qreal peakHoldDuration
|
||||
READ getPeakHoldDuration
|
||||
WRITE setPeakHoldDuration DESIGNABLE true)
|
||||
Q_PROPERTY(qreal inputPeakHoldDuration
|
||||
READ getInputPeakHoldDuration
|
||||
WRITE setInputPeakHoldDuration DESIGNABLE true)
|
||||
Q_PROPERTY(qreal peakHoldDuration READ getPeakHoldDuration WRITE
|
||||
setPeakHoldDuration DESIGNABLE true)
|
||||
Q_PROPERTY(qreal inputPeakHoldDuration READ getInputPeakHoldDuration
|
||||
WRITE setInputPeakHoldDuration DESIGNABLE true)
|
||||
|
||||
private slots:
|
||||
void ClipEnding();
|
||||
|
@ -92,18 +73,18 @@ private:
|
|||
inline void handleChannelCofigurationChange();
|
||||
inline bool detectIdle(uint64_t ts);
|
||||
inline void calculateBallistics(uint64_t ts,
|
||||
qreal timeSinceLastRedraw=0.0);
|
||||
inline void calculateBallisticsForChannel(int channelNr,
|
||||
uint64_t ts, qreal timeSinceLastRedraw);
|
||||
qreal timeSinceLastRedraw = 0.0);
|
||||
inline void calculateBallisticsForChannel(int channelNr, uint64_t ts,
|
||||
qreal timeSinceLastRedraw);
|
||||
|
||||
void paintInputMeter(QPainter &painter, int x, int y, int width,
|
||||
int height, float peakHold);
|
||||
int height, float peakHold);
|
||||
void paintHMeter(QPainter &painter, int x, int y, int width, int height,
|
||||
float magnitude, float peak, float peakHold);
|
||||
float magnitude, float peak, float peakHold);
|
||||
void paintHTicks(QPainter &painter, int x, int y, int width,
|
||||
int height);
|
||||
int height);
|
||||
void paintVMeter(QPainter &painter, int x, int y, int width, int height,
|
||||
float magnitude, float peak, float peakHold);
|
||||
float magnitude, float peak, float peakHold);
|
||||
void paintVTicks(QPainter &painter, int x, int y, int height);
|
||||
|
||||
QMutex dataMutex;
|
||||
|
@ -150,14 +131,13 @@ private:
|
|||
|
||||
public:
|
||||
explicit VolumeMeter(QWidget *parent = nullptr,
|
||||
obs_volmeter_t *obs_volmeter = nullptr,
|
||||
bool vertical = false);
|
||||
obs_volmeter_t *obs_volmeter = nullptr,
|
||||
bool vertical = false);
|
||||
~VolumeMeter();
|
||||
|
||||
void setLevels(
|
||||
const float magnitude[MAX_AUDIO_CHANNELS],
|
||||
const float peak[MAX_AUDIO_CHANNELS],
|
||||
const float inputPeak[MAX_AUDIO_CHANNELS]);
|
||||
void setLevels(const float magnitude[MAX_AUDIO_CHANNELS],
|
||||
const float peak[MAX_AUDIO_CHANNELS],
|
||||
const float inputPeak[MAX_AUDIO_CHANNELS]);
|
||||
|
||||
QColor getBackgroundNominalColor() const;
|
||||
void setBackgroundNominalColor(QColor c);
|
||||
|
@ -216,7 +196,7 @@ public:
|
|||
|
||||
protected:
|
||||
void timerEvent(QTimerEvent *event) override;
|
||||
QList<VolumeMeter*> volumeMeters;
|
||||
QList<VolumeMeter *> volumeMeters;
|
||||
};
|
||||
|
||||
class QLabel;
|
||||
|
@ -228,23 +208,23 @@ class VolControl : public QWidget {
|
|||
|
||||
private:
|
||||
OBSSource source;
|
||||
QLabel *nameLabel;
|
||||
QLabel *volLabel;
|
||||
VolumeMeter *volMeter;
|
||||
QSlider *slider;
|
||||
MuteCheckBox *mute;
|
||||
QPushButton *config = nullptr;
|
||||
float levelTotal;
|
||||
float levelCount;
|
||||
obs_fader_t *obs_fader;
|
||||
obs_volmeter_t *obs_volmeter;
|
||||
bool vertical;
|
||||
QLabel *nameLabel;
|
||||
QLabel *volLabel;
|
||||
VolumeMeter *volMeter;
|
||||
QSlider *slider;
|
||||
MuteCheckBox *mute;
|
||||
QPushButton *config = nullptr;
|
||||
float levelTotal;
|
||||
float levelCount;
|
||||
obs_fader_t *obs_fader;
|
||||
obs_volmeter_t *obs_volmeter;
|
||||
bool vertical;
|
||||
|
||||
static void OBSVolumeChanged(void *param, float db);
|
||||
static void OBSVolumeLevel(void *data,
|
||||
const float magnitude[MAX_AUDIO_CHANNELS],
|
||||
const float peak[MAX_AUDIO_CHANNELS],
|
||||
const float inputPeak[MAX_AUDIO_CHANNELS]);
|
||||
const float magnitude[MAX_AUDIO_CHANNELS],
|
||||
const float peak[MAX_AUDIO_CHANNELS],
|
||||
const float inputPeak[MAX_AUDIO_CHANNELS]);
|
||||
static void OBSVolumeMuted(void *data, calldata_t *calldata);
|
||||
|
||||
void EmitConfigClicked();
|
||||
|
@ -262,10 +242,10 @@ signals:
|
|||
|
||||
public:
|
||||
explicit VolControl(OBSSource source, bool showConfig = false,
|
||||
bool vertical = false);
|
||||
bool vertical = false);
|
||||
~VolControl();
|
||||
|
||||
inline obs_source_t *GetSource() const {return source;}
|
||||
inline obs_source_t *GetSource() const { return source; }
|
||||
|
||||
QString GetName() const;
|
||||
void SetName(const QString &newName);
|
||||
|
|
|
@ -2,10 +2,9 @@
|
|||
#include "obs-app.hpp"
|
||||
|
||||
OBSUpdate::OBSUpdate(QWidget *parent, bool manualUpdate, const QString &text)
|
||||
: QDialog (parent, Qt::WindowSystemMenuHint |
|
||||
Qt::WindowTitleHint |
|
||||
Qt::WindowCloseButtonHint),
|
||||
ui (new Ui_OBSUpdate)
|
||||
: QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint |
|
||||
Qt::WindowCloseButtonHint),
|
||||
ui(new Ui_OBSUpdate)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->text->setHtml(text);
|
||||
|
|
|
@ -9,11 +9,7 @@ class OBSUpdate : public QDialog {
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum ReturnVal {
|
||||
No,
|
||||
Yes,
|
||||
Skip
|
||||
};
|
||||
enum ReturnVal { No, Yes, Skip };
|
||||
|
||||
OBSUpdate(QWidget *parent, bool manualUpdate, const QString &text);
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ void HashToString(const uint8_t *in, wchar_t *out)
|
|||
const wchar_t alphabet[] = L"0123456789abcdef";
|
||||
|
||||
for (int i = 0; i != BLAKE2_HASH_LENGTH; ++i) {
|
||||
out[2 * i] = alphabet[in[i] / 16];
|
||||
out[2 * i] = alphabet[in[i] / 16];
|
||||
out[2 * i + 1] = alphabet[in[i] % 16];
|
||||
}
|
||||
|
||||
|
@ -50,7 +50,7 @@ bool CalculateFileHash(const wchar_t *path, BYTE *hash)
|
|||
return false;
|
||||
|
||||
WinHandle handle = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ,
|
||||
nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
|
||||
|
@ -60,7 +60,7 @@ bool CalculateFileHash(const wchar_t *path, BYTE *hash)
|
|||
for (;;) {
|
||||
DWORD read = 0;
|
||||
if (!ReadFile(handle, buf.data(), (DWORD)buf.size(), &read,
|
||||
nullptr))
|
||||
nullptr))
|
||||
return false;
|
||||
|
||||
if (!read)
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
#define MAX_BUF_SIZE 262144
|
||||
#define MAX_BUF_SIZE 262144
|
||||
#define READ_BUF_SIZE 32768
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
@ -36,8 +36,8 @@ public:
|
|||
inflateEnd(&strm);
|
||||
}
|
||||
|
||||
inline operator z_stream*() {return &strm;}
|
||||
inline z_stream *operator->() {return &strm;}
|
||||
inline operator z_stream *() { return &strm; }
|
||||
inline z_stream *operator->() { return &strm; }
|
||||
|
||||
inline bool inflate()
|
||||
{
|
||||
|
@ -50,14 +50,15 @@ public:
|
|||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
static bool ReadZippedHTTPData(string &responseBuf, z_stream *strm,
|
||||
string &zipBuf, const uint8_t *buffer, DWORD outSize)
|
||||
string &zipBuf, const uint8_t *buffer,
|
||||
DWORD outSize)
|
||||
{
|
||||
strm->avail_in = outSize;
|
||||
strm->next_in = buffer;
|
||||
strm->next_in = buffer;
|
||||
|
||||
do {
|
||||
strm->avail_out = (uInt)zipBuf.size();
|
||||
strm->next_out = (Bytef *)zipBuf.data();
|
||||
strm->next_out = (Bytef *)zipBuf.data();
|
||||
|
||||
int zret = inflate(strm, Z_NO_FLUSH);
|
||||
if (zret != Z_STREAM_END && zret != Z_OK)
|
||||
|
@ -65,7 +66,7 @@ static bool ReadZippedHTTPData(string &responseBuf, z_stream *strm,
|
|||
|
||||
try {
|
||||
responseBuf.append(zipBuf.data(),
|
||||
zipBuf.size() - strm->avail_out);
|
||||
zipBuf.size() - strm->avail_out);
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
|
@ -75,7 +76,7 @@ static bool ReadZippedHTTPData(string &responseBuf, z_stream *strm,
|
|||
}
|
||||
|
||||
static bool ReadHTTPData(string &responseBuf, const uint8_t *buffer,
|
||||
DWORD outSize)
|
||||
DWORD outSize)
|
||||
{
|
||||
try {
|
||||
responseBuf.append((const char *)buffer, outSize);
|
||||
|
@ -85,19 +86,16 @@ static bool ReadHTTPData(string &responseBuf, const uint8_t *buffer,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool HTTPPostData(const wchar_t *url,
|
||||
const BYTE * data,
|
||||
int dataLen,
|
||||
const wchar_t *extraHeaders,
|
||||
int * responseCode,
|
||||
string & responseBuf)
|
||||
bool HTTPPostData(const wchar_t *url, const BYTE *data, int dataLen,
|
||||
const wchar_t *extraHeaders, int *responseCode,
|
||||
string &responseBuf)
|
||||
{
|
||||
HttpHandle hSession;
|
||||
HttpHandle hConnect;
|
||||
HttpHandle hRequest;
|
||||
string zipBuf;
|
||||
HttpHandle hSession;
|
||||
HttpHandle hConnect;
|
||||
HttpHandle hRequest;
|
||||
string zipBuf;
|
||||
URL_COMPONENTS urlComponents = {};
|
||||
bool secure = false;
|
||||
bool secure = false;
|
||||
|
||||
wchar_t hostName[256];
|
||||
wchar_t path[1024];
|
||||
|
@ -113,10 +111,10 @@ bool HTTPPostData(const wchar_t *url,
|
|||
|
||||
urlComponents.dwStructSize = sizeof(urlComponents);
|
||||
|
||||
urlComponents.lpszHostName = hostName;
|
||||
urlComponents.lpszHostName = hostName;
|
||||
urlComponents.dwHostNameLength = _countof(hostName);
|
||||
|
||||
urlComponents.lpszUrlPath = path;
|
||||
urlComponents.lpszUrlPath = path;
|
||||
urlComponents.dwUrlPathLength = _countof(path);
|
||||
|
||||
WinHttpCrackUrl(url, 0, 0, &urlComponents);
|
||||
|
@ -128,22 +126,21 @@ bool HTTPPostData(const wchar_t *url,
|
|||
* connect to server */
|
||||
|
||||
hSession = WinHttpOpen(L"OBS Studio Updater/2.1",
|
||||
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
|
||||
WINHTTP_NO_PROXY_NAME,
|
||||
WINHTTP_NO_PROXY_BYPASS,
|
||||
0);
|
||||
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
|
||||
WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS,
|
||||
0);
|
||||
if (!hSession) {
|
||||
*responseCode = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
WinHttpSetOption(hSession, WINHTTP_OPTION_SECURE_PROTOCOLS,
|
||||
(LPVOID)&tlsProtocols, sizeof(tlsProtocols));
|
||||
(LPVOID)&tlsProtocols, sizeof(tlsProtocols));
|
||||
|
||||
hConnect = WinHttpConnect(hSession, hostName,
|
||||
secure
|
||||
? INTERNET_DEFAULT_HTTPS_PORT
|
||||
: INTERNET_DEFAULT_HTTP_PORT, 0);
|
||||
secure ? INTERNET_DEFAULT_HTTPS_PORT
|
||||
: INTERNET_DEFAULT_HTTP_PORT,
|
||||
0);
|
||||
if (!hConnect) {
|
||||
*responseCode = -2;
|
||||
return false;
|
||||
|
@ -152,24 +149,19 @@ bool HTTPPostData(const wchar_t *url,
|
|||
/* -------------------------------------- *
|
||||
* request data */
|
||||
|
||||
hRequest = WinHttpOpenRequest(hConnect,
|
||||
L"POST",
|
||||
path,
|
||||
nullptr,
|
||||
WINHTTP_NO_REFERER,
|
||||
acceptTypes,
|
||||
secure
|
||||
? WINHTTP_FLAG_SECURE |
|
||||
WINHTTP_FLAG_REFRESH
|
||||
: WINHTTP_FLAG_REFRESH);
|
||||
hRequest = WinHttpOpenRequest(hConnect, L"POST", path, nullptr,
|
||||
WINHTTP_NO_REFERER, acceptTypes,
|
||||
secure ? WINHTTP_FLAG_SECURE |
|
||||
WINHTTP_FLAG_REFRESH
|
||||
: WINHTTP_FLAG_REFRESH);
|
||||
if (!hRequest) {
|
||||
*responseCode = -3;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bResults = !!WinHttpSendRequest(hRequest, extraHeaders,
|
||||
extraHeaders ? -1 : 0,
|
||||
(void *)data, dataLen, dataLen, 0);
|
||||
extraHeaders ? -1 : 0,
|
||||
(void *)data, dataLen, dataLen, 0);
|
||||
|
||||
/* -------------------------------------- *
|
||||
* end request */
|
||||
|
@ -185,18 +177,15 @@ bool HTTPPostData(const wchar_t *url,
|
|||
* get headers */
|
||||
|
||||
wchar_t encoding[64];
|
||||
DWORD encodingLen;
|
||||
DWORD encodingLen;
|
||||
|
||||
wchar_t statusCode[8];
|
||||
DWORD statusCodeLen;
|
||||
DWORD statusCodeLen;
|
||||
|
||||
statusCodeLen = sizeof(statusCode);
|
||||
if (!WinHttpQueryHeaders(hRequest,
|
||||
WINHTTP_QUERY_STATUS_CODE,
|
||||
WINHTTP_HEADER_NAME_BY_INDEX,
|
||||
&statusCode,
|
||||
&statusCodeLen,
|
||||
WINHTTP_NO_HEADER_INDEX)) {
|
||||
if (!WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_STATUS_CODE,
|
||||
WINHTTP_HEADER_NAME_BY_INDEX, &statusCode,
|
||||
&statusCodeLen, WINHTTP_NO_HEADER_INDEX)) {
|
||||
*responseCode = -4;
|
||||
return false;
|
||||
} else {
|
||||
|
@ -204,12 +193,9 @@ bool HTTPPostData(const wchar_t *url,
|
|||
}
|
||||
|
||||
encodingLen = sizeof(encoding);
|
||||
if (!WinHttpQueryHeaders(hRequest,
|
||||
WINHTTP_QUERY_CONTENT_ENCODING,
|
||||
WINHTTP_HEADER_NAME_BY_INDEX,
|
||||
encoding,
|
||||
&encodingLen,
|
||||
WINHTTP_NO_HEADER_INDEX)) {
|
||||
if (!WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_CONTENT_ENCODING,
|
||||
WINHTTP_HEADER_NAME_BY_INDEX, encoding,
|
||||
&encodingLen, WINHTTP_NO_HEADER_INDEX)) {
|
||||
encoding[0] = 0;
|
||||
if (GetLastError() != ERROR_WINHTTP_HEADER_NOT_FOUND) {
|
||||
*responseCode = -5;
|
||||
|
@ -238,11 +224,11 @@ bool HTTPPostData(const wchar_t *url,
|
|||
bool gzip = wcscmp(encoding, L"gzip") == 0;
|
||||
|
||||
if (gzip) {
|
||||
strm->zalloc = Z_NULL;
|
||||
strm->zfree = Z_NULL;
|
||||
strm->opaque = Z_NULL;
|
||||
strm->zalloc = Z_NULL;
|
||||
strm->zfree = Z_NULL;
|
||||
strm->opaque = Z_NULL;
|
||||
strm->avail_in = 0;
|
||||
strm->next_in = Z_NULL;
|
||||
strm->next_in = Z_NULL;
|
||||
|
||||
if (!strm.inflate())
|
||||
return false;
|
||||
|
@ -278,7 +264,7 @@ bool HTTPPostData(const wchar_t *url,
|
|||
dwSize = std::min(dwSize, (DWORD)sizeof(buffer));
|
||||
|
||||
if (!WinHttpReadData(hRequest, (void *)buffer, dwSize,
|
||||
&outSize)) {
|
||||
&outSize)) {
|
||||
*responseCode = -9;
|
||||
return false;
|
||||
}
|
||||
|
@ -311,25 +297,23 @@ bool HTTPPostData(const wchar_t *url,
|
|||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
static bool ReadHTTPZippedFile(z_stream *strm, HANDLE updateFile,
|
||||
string &zipBuf, const uint8_t *buffer, DWORD outSize,
|
||||
int *responseCode)
|
||||
string &zipBuf, const uint8_t *buffer,
|
||||
DWORD outSize, int *responseCode)
|
||||
{
|
||||
strm->avail_in = outSize;
|
||||
strm->next_in = buffer;
|
||||
strm->next_in = buffer;
|
||||
|
||||
do {
|
||||
strm->avail_out = (uInt)zipBuf.size();
|
||||
strm->next_out = (Bytef *)zipBuf.data();
|
||||
strm->next_out = (Bytef *)zipBuf.data();
|
||||
|
||||
int zret = inflate(strm, Z_NO_FLUSH);
|
||||
if (zret != Z_STREAM_END && zret != Z_OK)
|
||||
return false;
|
||||
|
||||
DWORD written;
|
||||
if (!WriteFile(updateFile,
|
||||
zipBuf.data(),
|
||||
MAX_BUF_SIZE - strm->avail_out,
|
||||
&written,
|
||||
if (!WriteFile(updateFile, zipBuf.data(),
|
||||
MAX_BUF_SIZE - strm->avail_out, &written,
|
||||
nullptr)) {
|
||||
*responseCode = -10;
|
||||
return false;
|
||||
|
@ -346,7 +330,7 @@ static bool ReadHTTPZippedFile(z_stream *strm, HANDLE updateFile,
|
|||
}
|
||||
|
||||
static bool ReadHTTPFile(HANDLE updateFile, const uint8_t *buffer,
|
||||
DWORD outSize, int *responseCode)
|
||||
DWORD outSize, int *responseCode)
|
||||
{
|
||||
DWORD written;
|
||||
if (!WriteFile(updateFile, buffer, outSize, &written, nullptr)) {
|
||||
|
@ -363,20 +347,18 @@ static bool ReadHTTPFile(HANDLE updateFile, const uint8_t *buffer,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool HTTPGetFile(HINTERNET hConnect,
|
||||
const wchar_t *url,
|
||||
const wchar_t *outputPath,
|
||||
const wchar_t *extraHeaders,
|
||||
int * responseCode)
|
||||
bool HTTPGetFile(HINTERNET hConnect, const wchar_t *url,
|
||||
const wchar_t *outputPath, const wchar_t *extraHeaders,
|
||||
int *responseCode)
|
||||
{
|
||||
HttpHandle hRequest;
|
||||
|
||||
const wchar_t *acceptTypes[] = {L"*/*", nullptr};
|
||||
|
||||
URL_COMPONENTS urlComponents = {};
|
||||
bool secure = false;
|
||||
bool secure = false;
|
||||
|
||||
string zipBuf;
|
||||
string zipBuf;
|
||||
wchar_t hostName[256];
|
||||
wchar_t path[1024];
|
||||
|
||||
|
@ -385,10 +367,10 @@ bool HTTPGetFile(HINTERNET hConnect,
|
|||
|
||||
urlComponents.dwStructSize = sizeof(urlComponents);
|
||||
|
||||
urlComponents.lpszHostName = hostName;
|
||||
urlComponents.lpszHostName = hostName;
|
||||
urlComponents.dwHostNameLength = _countof(hostName);
|
||||
|
||||
urlComponents.lpszUrlPath = path;
|
||||
urlComponents.lpszUrlPath = path;
|
||||
urlComponents.dwUrlPathLength = _countof(path);
|
||||
|
||||
WinHttpCrackUrl(url, 0, 0, &urlComponents);
|
||||
|
@ -399,23 +381,19 @@ bool HTTPGetFile(HINTERNET hConnect,
|
|||
/* -------------------------------------- *
|
||||
* request data */
|
||||
|
||||
hRequest = WinHttpOpenRequest(hConnect,
|
||||
L"GET",
|
||||
path,
|
||||
nullptr,
|
||||
WINHTTP_NO_REFERER,
|
||||
acceptTypes,
|
||||
secure
|
||||
? WINHTTP_FLAG_SECURE |
|
||||
WINHTTP_FLAG_REFRESH
|
||||
: WINHTTP_FLAG_REFRESH);
|
||||
hRequest = WinHttpOpenRequest(hConnect, L"GET", path, nullptr,
|
||||
WINHTTP_NO_REFERER, acceptTypes,
|
||||
secure ? WINHTTP_FLAG_SECURE |
|
||||
WINHTTP_FLAG_REFRESH
|
||||
: WINHTTP_FLAG_REFRESH);
|
||||
if (!hRequest) {
|
||||
*responseCode = -3;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bResults = !!WinHttpSendRequest(hRequest, extraHeaders,
|
||||
extraHeaders ? -1 : 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
|
||||
extraHeaders ? -1 : 0,
|
||||
WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
|
||||
|
||||
/* -------------------------------------- *
|
||||
* end request */
|
||||
|
@ -431,18 +409,15 @@ bool HTTPGetFile(HINTERNET hConnect,
|
|||
* get headers */
|
||||
|
||||
wchar_t encoding[64];
|
||||
DWORD encodingLen;
|
||||
DWORD encodingLen;
|
||||
|
||||
wchar_t statusCode[8];
|
||||
DWORD statusCodeLen;
|
||||
DWORD statusCodeLen;
|
||||
|
||||
statusCodeLen = sizeof(statusCode);
|
||||
if (!WinHttpQueryHeaders(hRequest,
|
||||
WINHTTP_QUERY_STATUS_CODE,
|
||||
WINHTTP_HEADER_NAME_BY_INDEX,
|
||||
&statusCode,
|
||||
&statusCodeLen,
|
||||
WINHTTP_NO_HEADER_INDEX)) {
|
||||
if (!WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_STATUS_CODE,
|
||||
WINHTTP_HEADER_NAME_BY_INDEX, &statusCode,
|
||||
&statusCodeLen, WINHTTP_NO_HEADER_INDEX)) {
|
||||
*responseCode = -4;
|
||||
return false;
|
||||
} else {
|
||||
|
@ -450,12 +425,9 @@ bool HTTPGetFile(HINTERNET hConnect,
|
|||
}
|
||||
|
||||
encodingLen = sizeof(encoding);
|
||||
if (!WinHttpQueryHeaders(hRequest,
|
||||
WINHTTP_QUERY_CONTENT_ENCODING,
|
||||
WINHTTP_HEADER_NAME_BY_INDEX,
|
||||
encoding,
|
||||
&encodingLen,
|
||||
WINHTTP_NO_HEADER_INDEX)) {
|
||||
if (!WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_CONTENT_ENCODING,
|
||||
WINHTTP_HEADER_NAME_BY_INDEX, encoding,
|
||||
&encodingLen, WINHTTP_NO_HEADER_INDEX)) {
|
||||
encoding[0] = 0;
|
||||
if (GetLastError() != ERROR_WINHTTP_HEADER_NOT_FOUND) {
|
||||
*responseCode = -5;
|
||||
|
@ -472,11 +444,11 @@ bool HTTPGetFile(HINTERNET hConnect,
|
|||
bool gzip = wcscmp(encoding, L"gzip") == 0;
|
||||
|
||||
if (gzip) {
|
||||
strm->zalloc = Z_NULL;
|
||||
strm->zfree = Z_NULL;
|
||||
strm->opaque = Z_NULL;
|
||||
strm->zalloc = Z_NULL;
|
||||
strm->zfree = Z_NULL;
|
||||
strm->opaque = Z_NULL;
|
||||
strm->avail_in = 0;
|
||||
strm->next_in = Z_NULL;
|
||||
strm->next_in = Z_NULL;
|
||||
|
||||
if (!strm.inflate())
|
||||
return false;
|
||||
|
@ -498,12 +470,12 @@ bool HTTPGetFile(HINTERNET hConnect,
|
|||
if (!bResults || *responseCode != 200)
|
||||
return true;
|
||||
|
||||
BYTE buffer[READ_BUF_SIZE];
|
||||
BYTE buffer[READ_BUF_SIZE];
|
||||
DWORD dwSize, outSize;
|
||||
int lastPosition = 0;
|
||||
int lastPosition = 0;
|
||||
|
||||
WinHandle updateFile = CreateFile(outputPath, GENERIC_WRITE, 0,
|
||||
nullptr, CREATE_ALWAYS, 0, nullptr);
|
||||
WinHandle updateFile = CreateFile(outputPath, GENERIC_WRITE, 0, nullptr,
|
||||
CREATE_ALWAYS, 0, nullptr);
|
||||
if (!updateFile.Valid()) {
|
||||
*responseCode = -7;
|
||||
return false;
|
||||
|
@ -520,7 +492,7 @@ bool HTTPGetFile(HINTERNET hConnect,
|
|||
dwSize = std::min(dwSize, (DWORD)sizeof(buffer));
|
||||
|
||||
if (!WinHttpReadData(hRequest, (void *)buffer, dwSize,
|
||||
&outSize)) {
|
||||
&outSize)) {
|
||||
*responseCode = -9;
|
||||
return false;
|
||||
} else {
|
||||
|
@ -529,21 +501,22 @@ bool HTTPGetFile(HINTERNET hConnect,
|
|||
|
||||
if (gzip) {
|
||||
if (!ReadHTTPZippedFile(strm, updateFile,
|
||||
zipBuf, buffer,
|
||||
outSize, responseCode))
|
||||
zipBuf, buffer, outSize,
|
||||
responseCode))
|
||||
return false;
|
||||
} else {
|
||||
if (!ReadHTTPFile(updateFile, buffer,
|
||||
outSize, responseCode))
|
||||
if (!ReadHTTPFile(updateFile, buffer, outSize,
|
||||
responseCode))
|
||||
return false;
|
||||
}
|
||||
|
||||
int position = (int)(((float)completedFileSize /
|
||||
(float)totalFileSize) * 100.0f);
|
||||
(float)totalFileSize) *
|
||||
100.0f);
|
||||
if (position > lastPosition) {
|
||||
lastPosition = position;
|
||||
SendDlgItemMessage(hwndMain, IDC_PROGRESS,
|
||||
PBM_SETPOS, position, 0);
|
||||
PBM_SETPOS, position, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,16 +20,16 @@
|
|||
#include <vector>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define restrict __restrict
|
||||
# include <lzma.h>
|
||||
# undef restrict
|
||||
#define restrict __restrict
|
||||
#include <lzma.h>
|
||||
#undef restrict
|
||||
#else
|
||||
# include <lzma.h>
|
||||
#include <lzma.h>
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define MAX_BUF_SIZE 262144
|
||||
#define MAX_BUF_SIZE 262144
|
||||
#define READ_BUF_SIZE 32768
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
@ -48,10 +48,7 @@ public:
|
|||
|
||||
inline bool init_decoder()
|
||||
{
|
||||
lzma_ret ret = lzma_stream_decoder(
|
||||
&strm,
|
||||
200 * 1024 * 1024,
|
||||
0);
|
||||
lzma_ret ret = lzma_stream_decoder(&strm, 200 * 1024 * 1024, 0);
|
||||
initialized = (ret == LZMA_OK);
|
||||
return initialized;
|
||||
}
|
||||
|
@ -82,7 +79,7 @@ public:
|
|||
struct bspatch_stream {
|
||||
void *opaque;
|
||||
int (*read)(const struct bspatch_stream *stream, void *buffer,
|
||||
int length);
|
||||
int length);
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
@ -116,7 +113,7 @@ static int64_t offtin(const uint8_t *buf)
|
|||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
static int bspatch(const uint8_t *old, int64_t oldsize, uint8_t *newp,
|
||||
int64_t newsize, struct bspatch_stream *stream)
|
||||
int64_t newsize, struct bspatch_stream *stream)
|
||||
{
|
||||
uint8_t buf[8];
|
||||
int64_t oldpos, newpos;
|
||||
|
@ -169,9 +166,9 @@ static int bspatch(const uint8_t *old, int64_t oldsize, uint8_t *newp,
|
|||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
struct patch_data {
|
||||
HANDLE h;
|
||||
lzma_stream *strm;
|
||||
uint8_t buf[READ_BUF_SIZE];
|
||||
HANDLE h;
|
||||
lzma_stream *strm;
|
||||
uint8_t buf[READ_BUF_SIZE];
|
||||
};
|
||||
|
||||
static int read_lzma(const struct bspatch_stream *stream, void *buffer, int len)
|
||||
|
@ -179,24 +176,24 @@ static int read_lzma(const struct bspatch_stream *stream, void *buffer, int len)
|
|||
if (!len)
|
||||
return 0;
|
||||
|
||||
patch_data *data = (patch_data*)stream->opaque;
|
||||
HANDLE h = data->h;
|
||||
lzma_stream *strm = data->strm;
|
||||
patch_data *data = (patch_data *)stream->opaque;
|
||||
HANDLE h = data->h;
|
||||
lzma_stream *strm = data->strm;
|
||||
|
||||
strm->avail_out = (size_t)len;
|
||||
strm->next_out = (uint8_t *)buffer;
|
||||
strm->next_out = (uint8_t *)buffer;
|
||||
|
||||
for (;;) {
|
||||
if (strm->avail_in == 0) {
|
||||
DWORD read_size;
|
||||
if (!ReadFile(h, data->buf, READ_BUF_SIZE, &read_size,
|
||||
nullptr))
|
||||
nullptr))
|
||||
return -1;
|
||||
if (read_size == 0)
|
||||
return -1;
|
||||
|
||||
strm->avail_in = (size_t)read_size;
|
||||
strm->next_in = data->buf;
|
||||
strm->next_in = data->buf;
|
||||
}
|
||||
|
||||
lzma_ret ret = lzma_code(strm, LZMA_RUN);
|
||||
|
@ -213,25 +210,25 @@ static int read_lzma(const struct bspatch_stream *stream, void *buffer, int len)
|
|||
|
||||
int ApplyPatch(const wchar_t *patchFile, const wchar_t *targetFile)
|
||||
try {
|
||||
uint8_t header[24];
|
||||
int64_t newsize;
|
||||
uint8_t header[24];
|
||||
int64_t newsize;
|
||||
struct bspatch_stream stream;
|
||||
bool success;
|
||||
bool success;
|
||||
|
||||
WinHandle hPatch;
|
||||
WinHandle hTarget;
|
||||
WinHandle hPatch;
|
||||
WinHandle hTarget;
|
||||
LZMAStream strm;
|
||||
|
||||
/* --------------------------------- *
|
||||
* open patch and file to patch */
|
||||
|
||||
hPatch = CreateFile(patchFile, GENERIC_READ, 0, nullptr,
|
||||
OPEN_EXISTING, 0, nullptr);
|
||||
hPatch = CreateFile(patchFile, GENERIC_READ, 0, nullptr, OPEN_EXISTING,
|
||||
0, nullptr);
|
||||
if (!hPatch.Valid())
|
||||
throw int(GetLastError());
|
||||
|
||||
hTarget = CreateFile(targetFile, GENERIC_READ, 0, nullptr,
|
||||
OPEN_EXISTING, 0, nullptr);
|
||||
OPEN_EXISTING, 0, nullptr);
|
||||
if (!hTarget.Valid())
|
||||
throw int(GetLastError());
|
||||
|
||||
|
@ -289,14 +286,14 @@ try {
|
|||
throw int(-10);
|
||||
|
||||
patch_data data;
|
||||
data.h = hPatch;
|
||||
data.h = hPatch;
|
||||
data.strm = strm.get();
|
||||
|
||||
stream.read = read_lzma;
|
||||
stream.read = read_lzma;
|
||||
stream.opaque = &data;
|
||||
|
||||
int ret = bspatch(oldData.data(), oldData.size(), newData.data(),
|
||||
newData.size(), &stream);
|
||||
newData.size(), &stream);
|
||||
if (ret != 0)
|
||||
throw int(-9);
|
||||
|
||||
|
@ -305,14 +302,14 @@ try {
|
|||
|
||||
hTarget = nullptr;
|
||||
hTarget = CreateFile(targetFile, GENERIC_WRITE, 0, nullptr,
|
||||
CREATE_ALWAYS, 0, nullptr);
|
||||
CREATE_ALWAYS, 0, nullptr);
|
||||
if (!hTarget.Valid())
|
||||
throw int(GetLastError());
|
||||
|
||||
DWORD written;
|
||||
|
||||
success = !!WriteFile(hTarget, newData.data(), (DWORD)newsize,
|
||||
&written, nullptr);
|
||||
success = !!WriteFile(hTarget, newData.data(), (DWORD)newsize, &written,
|
||||
nullptr);
|
||||
if (!success || written != newsize)
|
||||
throw int(GetLastError());
|
||||
|
||||
|
|
|
@ -2,20 +2,20 @@
|
|||
// Microsoft Visual C++ generated include file.
|
||||
// Used by updater.rc
|
||||
//
|
||||
#define IDD_UPDATEDIALOG 101
|
||||
#define IDI_ICON1 103
|
||||
#define IDC_PROGRESS 1001
|
||||
#define IDC_STATUS 1002
|
||||
#define IDCBUTTON 1004
|
||||
#define IDC_BUTTON 1004
|
||||
#define IDD_UPDATEDIALOG 101
|
||||
#define IDI_ICON1 103
|
||||
#define IDC_PROGRESS 1001
|
||||
#define IDC_STATUS 1002
|
||||
#define IDCBUTTON 1004
|
||||
#define IDC_BUTTON 1004
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 104
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1005
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#define _APS_NEXT_RESOURCE_VALUE 104
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1005
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -45,53 +45,44 @@
|
|||
#define BLAKE2_HASH_STR_LENGTH ((BLAKE2_HASH_LENGTH * 2) + 1)
|
||||
|
||||
#if defined _M_IX86
|
||||
#pragma comment(linker, \
|
||||
"/manifestdependency:\"type='win32' " \
|
||||
"name='Microsoft.Windows.Common-Controls' " \
|
||||
"version='6.0.0.0' " \
|
||||
"processorArchitecture='x86' " \
|
||||
"publicKeyToken='6595b64144ccf1df' " \
|
||||
"language='*'\"")
|
||||
#pragma comment(linker, "/manifestdependency:\"type='win32' " \
|
||||
"name='Microsoft.Windows.Common-Controls' " \
|
||||
"version='6.0.0.0' " \
|
||||
"processorArchitecture='x86' " \
|
||||
"publicKeyToken='6595b64144ccf1df' " \
|
||||
"language='*'\"")
|
||||
#elif defined _M_IA64
|
||||
#pragma comment(linker, \
|
||||
"/manifestdependency:\"type='win32' " \
|
||||
"name='Microsoft.Windows.Common-Controls' " \
|
||||
"version='6.0.0.0' " \
|
||||
"processorArchitecture='ia64' " \
|
||||
"publicKeyToken='6595b64144ccf1df' " \
|
||||
"language='*'\"")
|
||||
#pragma comment(linker, "/manifestdependency:\"type='win32' " \
|
||||
"name='Microsoft.Windows.Common-Controls' " \
|
||||
"version='6.0.0.0' " \
|
||||
"processorArchitecture='ia64' " \
|
||||
"publicKeyToken='6595b64144ccf1df' " \
|
||||
"language='*'\"")
|
||||
#elif defined _M_X64
|
||||
#pragma comment(linker, \
|
||||
"/manifestdependency:\"type='win32' " \
|
||||
"name='Microsoft.Windows.Common-Controls' " \
|
||||
"version='6.0.0.0' " \
|
||||
"processorArchitecture='amd64' " \
|
||||
"publicKeyToken='6595b64144ccf1df' " \
|
||||
"language='*'\"")
|
||||
#pragma comment(linker, "/manifestdependency:\"type='win32' " \
|
||||
"name='Microsoft.Windows.Common-Controls' " \
|
||||
"version='6.0.0.0' " \
|
||||
"processorArchitecture='amd64' " \
|
||||
"publicKeyToken='6595b64144ccf1df' " \
|
||||
"language='*'\"")
|
||||
#else
|
||||
#pragma comment(linker, \
|
||||
"/manifestdependency:\"type='win32' " \
|
||||
"name='Microsoft.Windows.Common-Controls' " \
|
||||
"version='6.0.0.0' processorArchitecture='*' " \
|
||||
"publicKeyToken='6595b64144ccf1df' " \
|
||||
"language='*'\"")
|
||||
#pragma comment(linker, "/manifestdependency:\"type='win32' " \
|
||||
"name='Microsoft.Windows.Common-Controls' " \
|
||||
"version='6.0.0.0' processorArchitecture='*' " \
|
||||
"publicKeyToken='6595b64144ccf1df' " \
|
||||
"language='*'\"")
|
||||
#endif
|
||||
|
||||
#include <util/windows/WinHandle.hpp>
|
||||
#include <jansson.h>
|
||||
#include "resource.h"
|
||||
|
||||
bool HTTPGetFile(HINTERNET hConnect,
|
||||
const wchar_t *url,
|
||||
const wchar_t *outputPath,
|
||||
const wchar_t *extraHeaders,
|
||||
int * responseCode);
|
||||
bool HTTPPostData(const wchar_t *url,
|
||||
const BYTE * data,
|
||||
int dataLen,
|
||||
const wchar_t *extraHeaders,
|
||||
int * responseCode,
|
||||
std::string & response);
|
||||
bool HTTPGetFile(HINTERNET hConnect, const wchar_t *url,
|
||||
const wchar_t *outputPath, const wchar_t *extraHeaders,
|
||||
int *responseCode);
|
||||
bool HTTPPostData(const wchar_t *url, const BYTE *data, int dataLen,
|
||||
const wchar_t *extraHeaders, int *responseCode,
|
||||
std::string &response);
|
||||
|
||||
void HashToString(const BYTE *in, wchar_t *out);
|
||||
void StringToHash(const wchar_t *in, BYTE *out);
|
||||
|
@ -100,17 +91,17 @@ bool CalculateFileHash(const wchar_t *path, BYTE *hash);
|
|||
|
||||
int ApplyPatch(LPCTSTR patchFile, LPCTSTR targetFile);
|
||||
|
||||
extern HWND hwndMain;
|
||||
extern HWND hwndMain;
|
||||
extern HCRYPTPROV hProvider;
|
||||
extern int totalFileSize;
|
||||
extern int completedFileSize;
|
||||
extern HANDLE cancelRequested;
|
||||
extern int totalFileSize;
|
||||
extern int completedFileSize;
|
||||
extern HANDLE cancelRequested;
|
||||
|
||||
#pragma pack(push, r1, 1)
|
||||
|
||||
typedef struct {
|
||||
BLOBHEADER blobheader;
|
||||
RSAPUBKEY rsapubkey;
|
||||
RSAPUBKEY rsapubkey;
|
||||
} PUBLICKEYHEADER;
|
||||
|
||||
#pragma pack(pop, r1)
|
||||
|
|
|
@ -23,9 +23,9 @@ public:
|
|||
freefunc(handle);
|
||||
}
|
||||
|
||||
inline T *operator&() {return &handle;}
|
||||
inline operator T() const {return handle;}
|
||||
inline T get() const {return handle;}
|
||||
inline T *operator&() { return &handle; }
|
||||
inline operator T() const { return handle; }
|
||||
inline T get() const { return handle; }
|
||||
|
||||
inline CustomHandle<T, freefunc> &operator=(T in)
|
||||
{
|
||||
|
@ -35,7 +35,7 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
inline bool operator!() const {return !handle;}
|
||||
inline bool operator!() const { return !handle; }
|
||||
};
|
||||
|
||||
void FreeProvider(HCRYPTPROV prov);
|
||||
|
@ -43,8 +43,8 @@ void FreeHash(HCRYPTHASH hash);
|
|||
void FreeKey(HCRYPTKEY key);
|
||||
|
||||
using CryptProvider = CustomHandle<HCRYPTPROV, FreeProvider>;
|
||||
using CryptHash = CustomHandle<HCRYPTHASH, FreeHash>;
|
||||
using CryptKey = CustomHandle<HCRYPTKEY, FreeKey>;
|
||||
using CryptHash = CustomHandle<HCRYPTHASH, FreeHash>;
|
||||
using CryptKey = CustomHandle<HCRYPTKEY, FreeKey>;
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
|
@ -58,13 +58,13 @@ public:
|
|||
LocalFree(ptr);
|
||||
}
|
||||
|
||||
inline T **operator&() {return &ptr;}
|
||||
inline operator T() const {return ptr;}
|
||||
inline T *get() const {return ptr;}
|
||||
inline T **operator&() { return &ptr; }
|
||||
inline operator T() const { return ptr; }
|
||||
inline T *get() const { return ptr; }
|
||||
|
||||
inline bool operator!() const {return !ptr;}
|
||||
inline bool operator!() const { return !ptr; }
|
||||
|
||||
inline T *operator->() {return ptr;}
|
||||
inline T *operator->() { return ptr; }
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
@ -76,9 +76,10 @@ public:
|
|||
inline Json() : json(nullptr) {}
|
||||
explicit inline Json(json_t *json_) : json(json_) {}
|
||||
inline Json(const Json &from) : json(json_incref(from.json)) {}
|
||||
inline Json(Json &&from) : json(from.json) {from.json = nullptr;}
|
||||
inline Json(Json &&from) : json(from.json) { from.json = nullptr; }
|
||||
|
||||
inline ~Json() {
|
||||
inline ~Json()
|
||||
{
|
||||
if (json)
|
||||
json_decref(json);
|
||||
}
|
||||
|
@ -106,12 +107,12 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
inline operator json_t *() const {return json;}
|
||||
inline operator json_t *() const { return json; }
|
||||
|
||||
inline bool operator!() const {return !json;}
|
||||
inline bool operator!() const { return !json; }
|
||||
|
||||
inline const char *GetString(const char *name,
|
||||
const char *def = nullptr) const
|
||||
const char *def = nullptr) const
|
||||
{
|
||||
json_t *obj(json_object_get(json, name));
|
||||
if (!obj)
|
||||
|
@ -130,7 +131,7 @@ public:
|
|||
return json_object_get(json, name);
|
||||
}
|
||||
|
||||
inline json_t *get() const {return json;}
|
||||
inline json_t *get() const { return json; }
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
|
|
@ -42,7 +42,7 @@ static __declspec(thread) HCRYPTPROV provider = 0;
|
|||
|
||||
typedef struct {
|
||||
BLOBHEADER blobheader;
|
||||
RSAPUBKEY rsapubkey;
|
||||
RSAPUBKEY rsapubkey;
|
||||
} PUBLICKEYHEADER;
|
||||
|
||||
#pragma pack(pop, r1)
|
||||
|
@ -120,8 +120,7 @@ static const unsigned char obs_pub[] = {
|
|||
0x42, 0x61, 0x35, 0x66, 0x37, 0x4c, 0x6f, 0x4b, 0x38, 0x43, 0x41, 0x77,
|
||||
0x45, 0x41, 0x41, 0x51, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
|
||||
0x45, 0x4e, 0x44, 0x20, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x20, 0x4b,
|
||||
0x45, 0x59, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a
|
||||
};
|
||||
0x45, 0x59, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a};
|
||||
static const unsigned int obs_pub_len = 800;
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
@ -132,23 +131,18 @@ try {
|
|||
if (os_utf8_to_wcs_ptr(file, 0, &w_file) == 0)
|
||||
return false;
|
||||
|
||||
WinHandle handle = CreateFileW(
|
||||
w_file,
|
||||
GENERIC_WRITE,
|
||||
0,
|
||||
nullptr,
|
||||
CREATE_ALWAYS,
|
||||
FILE_FLAG_WRITE_THROUGH,
|
||||
nullptr);
|
||||
WinHandle handle = CreateFileW(w_file, GENERIC_WRITE, 0, nullptr,
|
||||
CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH,
|
||||
nullptr);
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
throw strprintf("Failed to open file '%s': %lu",
|
||||
file, GetLastError());
|
||||
throw strprintf("Failed to open file '%s': %lu", file,
|
||||
GetLastError());
|
||||
|
||||
DWORD written;
|
||||
if (!WriteFile(handle, data, (DWORD)size, &written, nullptr))
|
||||
throw strprintf("Failed to write file '%s': %lu",
|
||||
file, GetLastError());
|
||||
throw strprintf("Failed to write file '%s': %lu", file,
|
||||
GetLastError());
|
||||
|
||||
return true;
|
||||
|
||||
|
@ -163,26 +157,20 @@ try {
|
|||
if (os_utf8_to_wcs_ptr(file, 0, &w_file) == 0)
|
||||
return false;
|
||||
|
||||
WinHandle handle = CreateFileW(
|
||||
w_file,
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ,
|
||||
nullptr,
|
||||
OPEN_EXISTING,
|
||||
0,
|
||||
nullptr);
|
||||
WinHandle handle = CreateFileW(w_file, GENERIC_READ, FILE_SHARE_READ,
|
||||
nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
throw strprintf("Failed to open file '%s': %lu",
|
||||
file, GetLastError());
|
||||
throw strprintf("Failed to open file '%s': %lu", file,
|
||||
GetLastError());
|
||||
|
||||
DWORD size = GetFileSize(handle, nullptr);
|
||||
data.resize(size);
|
||||
|
||||
DWORD read;
|
||||
if (!ReadFile(handle, &data[0], size, &read, nullptr))
|
||||
throw strprintf("Failed to write file '%s': %lu",
|
||||
file, GetLastError());
|
||||
throw strprintf("Failed to write file '%s': %lu", file,
|
||||
GetLastError());
|
||||
|
||||
return true;
|
||||
|
||||
|
@ -196,7 +184,7 @@ static void HashToString(const uint8_t *in, char *out)
|
|||
const char alphabet[] = "0123456789abcdef";
|
||||
|
||||
for (int i = 0; i != BLAKE2_HASH_LENGTH; ++i) {
|
||||
out[2 * i] = alphabet[in[i] / 16];
|
||||
out[2 * i] = alphabet[in[i] / 16];
|
||||
out[2 * i + 1] = alphabet[in[i] % 16];
|
||||
}
|
||||
|
||||
|
@ -214,10 +202,10 @@ try {
|
|||
return false;
|
||||
|
||||
WinHandle handle = CreateFileW(w_path, GENERIC_READ, FILE_SHARE_READ,
|
||||
nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
throw strprintf("Failed to open file '%s': %lu",
|
||||
path, GetLastError());
|
||||
throw strprintf("Failed to open file '%s': %lu", path,
|
||||
GetLastError());
|
||||
|
||||
vector<BYTE> buf;
|
||||
buf.resize(65536);
|
||||
|
@ -225,9 +213,9 @@ try {
|
|||
for (;;) {
|
||||
DWORD read = 0;
|
||||
if (!ReadFile(handle, buf.data(), (DWORD)buf.size(), &read,
|
||||
nullptr))
|
||||
throw strprintf("Failed to read file '%s': %lu",
|
||||
path, GetLastError());
|
||||
nullptr))
|
||||
throw strprintf("Failed to read file '%s': %lu", path,
|
||||
GetLastError());
|
||||
|
||||
if (!read)
|
||||
break;
|
||||
|
@ -249,19 +237,19 @@ try {
|
|||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
static bool VerifyDigitalSignature(uint8_t *buf, size_t len, uint8_t *sig,
|
||||
size_t sigLen)
|
||||
size_t sigLen)
|
||||
{
|
||||
/* ASN of PEM public key */
|
||||
BYTE binaryKey[1024];
|
||||
BYTE binaryKey[1024];
|
||||
DWORD binaryKeyLen = sizeof(binaryKey);
|
||||
|
||||
/* Windows X509 public key info from ASN */
|
||||
LocalPtr<CERT_PUBLIC_KEY_INFO> publicPBLOB;
|
||||
DWORD iPBLOBSize;
|
||||
DWORD iPBLOBSize;
|
||||
|
||||
/* RSA BLOB info from X509 public key */
|
||||
LocalPtr<PUBLICKEYHEADER> rsaPublicBLOB;
|
||||
DWORD rsaPublicBLOBSize;
|
||||
DWORD rsaPublicBLOBSize;
|
||||
|
||||
/* Handle to public key */
|
||||
CryptKey keyOut;
|
||||
|
@ -272,41 +260,26 @@ static bool VerifyDigitalSignature(uint8_t *buf, size_t len, uint8_t *sig,
|
|||
/* Signature in little-endian format */
|
||||
vector<BYTE> reversedSig;
|
||||
|
||||
if (!CryptStringToBinaryA((LPCSTR)obs_pub,
|
||||
obs_pub_len,
|
||||
CRYPT_STRING_BASE64HEADER,
|
||||
binaryKey,
|
||||
&binaryKeyLen,
|
||||
nullptr,
|
||||
nullptr))
|
||||
if (!CryptStringToBinaryA((LPCSTR)obs_pub, obs_pub_len,
|
||||
CRYPT_STRING_BASE64HEADER, binaryKey,
|
||||
&binaryKeyLen, nullptr, nullptr))
|
||||
return false;
|
||||
|
||||
if (!CryptDecodeObjectEx(X509_ASN_ENCODING,
|
||||
X509_PUBLIC_KEY_INFO,
|
||||
binaryKey,
|
||||
binaryKeyLen,
|
||||
CRYPT_ENCODE_ALLOC_FLAG,
|
||||
nullptr,
|
||||
&publicPBLOB,
|
||||
&iPBLOBSize))
|
||||
if (!CryptDecodeObjectEx(X509_ASN_ENCODING, X509_PUBLIC_KEY_INFO,
|
||||
binaryKey, binaryKeyLen,
|
||||
CRYPT_ENCODE_ALLOC_FLAG, nullptr, &publicPBLOB,
|
||||
&iPBLOBSize))
|
||||
return false;
|
||||
|
||||
if (!CryptDecodeObjectEx(X509_ASN_ENCODING,
|
||||
RSA_CSP_PUBLICKEYBLOB,
|
||||
publicPBLOB->PublicKey.pbData,
|
||||
publicPBLOB->PublicKey.cbData,
|
||||
CRYPT_ENCODE_ALLOC_FLAG,
|
||||
nullptr,
|
||||
&rsaPublicBLOB,
|
||||
&rsaPublicBLOBSize))
|
||||
if (!CryptDecodeObjectEx(X509_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB,
|
||||
publicPBLOB->PublicKey.pbData,
|
||||
publicPBLOB->PublicKey.cbData,
|
||||
CRYPT_ENCODE_ALLOC_FLAG, nullptr,
|
||||
&rsaPublicBLOB, &rsaPublicBLOBSize))
|
||||
return false;
|
||||
|
||||
if (!CryptImportKey(provider,
|
||||
(const BYTE *)rsaPublicBLOB.get(),
|
||||
rsaPublicBLOBSize,
|
||||
0,
|
||||
0,
|
||||
&keyOut))
|
||||
if (!CryptImportKey(provider, (const BYTE *)rsaPublicBLOB.get(),
|
||||
rsaPublicBLOBSize, 0, 0, &keyOut))
|
||||
return false;
|
||||
|
||||
if (!CryptCreateHash(provider, CALG_SHA_512, 0, 0, &hash))
|
||||
|
@ -321,19 +294,15 @@ static bool VerifyDigitalSignature(uint8_t *buf, size_t len, uint8_t *sig,
|
|||
for (size_t i = 0; i < sigLen; i++)
|
||||
reversedSig[i] = sig[sigLen - i - 1];
|
||||
|
||||
if (!CryptVerifySignature(hash,
|
||||
reversedSig.data(),
|
||||
(DWORD)sigLen,
|
||||
keyOut,
|
||||
nullptr,
|
||||
0))
|
||||
if (!CryptVerifySignature(hash, reversedSig.data(), (DWORD)sigLen,
|
||||
keyOut, nullptr, 0))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void HexToByteArray(const char *hexStr, size_t hexLen,
|
||||
vector<uint8_t> &out)
|
||||
vector<uint8_t> &out)
|
||||
{
|
||||
char ptr[3];
|
||||
|
||||
|
@ -347,7 +316,7 @@ static inline void HexToByteArray(const char *hexStr, size_t hexLen,
|
|||
}
|
||||
|
||||
static bool CheckDataSignature(const string &data, const char *name,
|
||||
const char *hexSig, size_t sigLen)
|
||||
const char *hexSig, size_t sigLen)
|
||||
try {
|
||||
if (sigLen == 0 || sigLen > 0xFFFF || (sigLen & 1) != 0)
|
||||
throw strprintf("Missing or invalid signature for %s", name);
|
||||
|
@ -357,10 +326,8 @@ try {
|
|||
signature.reserve(sigLen);
|
||||
HexToByteArray(hexSig, sigLen, signature);
|
||||
|
||||
if (!VerifyDigitalSignature((uint8_t*)data.data(),
|
||||
data.size(),
|
||||
signature.data(),
|
||||
signature.size()))
|
||||
if (!VerifyDigitalSignature((uint8_t *)data.data(), data.size(),
|
||||
signature.data(), signature.size()))
|
||||
throw strprintf("Signature check failed for %s", name);
|
||||
|
||||
return true;
|
||||
|
@ -374,12 +341,12 @@ try {
|
|||
|
||||
static bool FetchUpdaterModule(const char *url)
|
||||
try {
|
||||
long responseCode;
|
||||
uint8_t updateFileHash[BLAKE2_HASH_LENGTH];
|
||||
long responseCode;
|
||||
uint8_t updateFileHash[BLAKE2_HASH_LENGTH];
|
||||
vector<string> extraHeaders;
|
||||
|
||||
BPtr<char> updateFilePath = GetConfigPathPtr(
|
||||
"obs-studio\\updates\\updater.exe");
|
||||
BPtr<char> updateFilePath =
|
||||
GetConfigPathPtr("obs-studio\\updates\\updater.exe");
|
||||
|
||||
if (CalculateFileHash(updateFilePath, updateFileHash)) {
|
||||
char hashString[BLAKE2_HASH_STR_LENGTH];
|
||||
|
@ -394,8 +361,8 @@ try {
|
|||
string error;
|
||||
string data;
|
||||
|
||||
bool success = GetRemoteFile(url, data, error, &responseCode,
|
||||
nullptr, nullptr, extraHeaders, &signature);
|
||||
bool success = GetRemoteFile(url, data, error, &responseCode, nullptr,
|
||||
nullptr, extraHeaders, &signature);
|
||||
|
||||
if (!success || (responseCode != 200 && responseCode != 304)) {
|
||||
if (responseCode == 404)
|
||||
|
@ -407,7 +374,7 @@ try {
|
|||
/* A new file must be digitally signed */
|
||||
if (responseCode == 200) {
|
||||
bool valid = CheckDataSignature(data, url, signature.data(),
|
||||
signature.size());
|
||||
signature.size());
|
||||
if (!valid)
|
||||
throw string("Invalid updater module signature");
|
||||
|
||||
|
@ -425,7 +392,7 @@ try {
|
|||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
static bool ParseUpdateManifest(const char *manifest, bool *updatesAvailable,
|
||||
string ¬es_str, int &updateVer)
|
||||
string ¬es_str, int &updateVer)
|
||||
try {
|
||||
|
||||
json_error_t error;
|
||||
|
@ -442,10 +409,8 @@ try {
|
|||
int patch = root.GetInt("version_patch");
|
||||
|
||||
if (major == 0)
|
||||
throw strprintf("Invalid version number: %d.%d.%d",
|
||||
major,
|
||||
minor,
|
||||
patch);
|
||||
throw strprintf("Invalid version number: %d.%d.%d", major,
|
||||
minor, patch);
|
||||
|
||||
json_t *notes = json_object_get(root, "notes");
|
||||
if (!json_is_string(notes))
|
||||
|
@ -491,8 +456,8 @@ string GetProgramGUID()
|
|||
/* NOTE: this is an arbitrary random number that we use to count the
|
||||
* number of unique OBS installations and is not associated with any
|
||||
* kind of identifiable information */
|
||||
const char *pguid = config_get_string(GetGlobalConfig(),
|
||||
"General", "InstallGUID");
|
||||
const char *pguid =
|
||||
config_get_string(GetGlobalConfig(), "General", "InstallGUID");
|
||||
string guid;
|
||||
if (pguid)
|
||||
guid = pguid;
|
||||
|
@ -501,9 +466,8 @@ string GetProgramGUID()
|
|||
GenerateGUID(guid);
|
||||
|
||||
if (!guid.empty())
|
||||
config_set_string(GetGlobalConfig(),
|
||||
"General", "InstallGUID",
|
||||
guid.c_str());
|
||||
config_set_string(GetGlobalConfig(), "General",
|
||||
"InstallGUID", guid.c_str());
|
||||
}
|
||||
|
||||
return guid;
|
||||
|
@ -516,13 +480,12 @@ void AutoUpdateThread::infoMsg(const QString &title, const QString &text)
|
|||
|
||||
void AutoUpdateThread::info(const QString &title, const QString &text)
|
||||
{
|
||||
QMetaObject::invokeMethod(this, "infoMsg",
|
||||
Qt::BlockingQueuedConnection,
|
||||
Q_ARG(QString, title),
|
||||
Q_ARG(QString, text));
|
||||
QMetaObject::invokeMethod(this, "infoMsg", Qt::BlockingQueuedConnection,
|
||||
Q_ARG(QString, title), Q_ARG(QString, text));
|
||||
}
|
||||
|
||||
int AutoUpdateThread::queryUpdateSlot(bool localManualUpdate, const QString &text)
|
||||
int AutoUpdateThread::queryUpdateSlot(bool localManualUpdate,
|
||||
const QString &text)
|
||||
{
|
||||
OBSUpdate updateDlg(App()->GetMainWindow(), localManualUpdate, text);
|
||||
return updateDlg.exec();
|
||||
|
@ -533,17 +496,17 @@ int AutoUpdateThread::queryUpdate(bool localManualUpdate, const char *text_utf8)
|
|||
int ret = OBSUpdate::No;
|
||||
QString text = text_utf8;
|
||||
QMetaObject::invokeMethod(this, "queryUpdateSlot",
|
||||
Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(int, ret),
|
||||
Q_ARG(bool, localManualUpdate),
|
||||
Q_ARG(QString, text));
|
||||
Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(int, ret),
|
||||
Q_ARG(bool, localManualUpdate),
|
||||
Q_ARG(QString, text));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool IsFileInUse(const wstring &file)
|
||||
{
|
||||
WinHandle f = CreateFile(file.c_str(), GENERIC_WRITE, 0, nullptr,
|
||||
OPEN_EXISTING, 0, nullptr);
|
||||
OPEN_EXISTING, 0, nullptr);
|
||||
if (!f.Valid()) {
|
||||
int err = GetLastError();
|
||||
if (err == ERROR_SHARING_VIOLATION ||
|
||||
|
@ -557,35 +520,33 @@ static bool IsFileInUse(const wstring &file)
|
|||
static bool IsGameCaptureInUse()
|
||||
{
|
||||
wstring path = L"..\\..\\data\\obs-plugins\\win-capture\\graphics-hook";
|
||||
return IsFileInUse(path + L"32.dll") ||
|
||||
IsFileInUse(path + L"64.dll");
|
||||
return IsFileInUse(path + L"32.dll") || IsFileInUse(path + L"64.dll");
|
||||
}
|
||||
|
||||
void AutoUpdateThread::run()
|
||||
try {
|
||||
long responseCode;
|
||||
long responseCode;
|
||||
vector<string> extraHeaders;
|
||||
string text;
|
||||
string error;
|
||||
string signature;
|
||||
CryptProvider localProvider;
|
||||
BYTE manifestHash[BLAKE2_HASH_LENGTH];
|
||||
bool updatesAvailable = false;
|
||||
bool success;
|
||||
string text;
|
||||
string error;
|
||||
string signature;
|
||||
CryptProvider localProvider;
|
||||
BYTE manifestHash[BLAKE2_HASH_LENGTH];
|
||||
bool updatesAvailable = false;
|
||||
bool success;
|
||||
|
||||
struct FinishedTrigger {
|
||||
inline ~FinishedTrigger()
|
||||
{
|
||||
QMetaObject::invokeMethod(App()->GetMainWindow(),
|
||||
"updateCheckFinished");
|
||||
"updateCheckFinished");
|
||||
}
|
||||
} finishedTrigger;
|
||||
|
||||
BPtr<char> manifestPath = GetConfigPathPtr(
|
||||
"obs-studio\\updates\\manifest.json");
|
||||
BPtr<char> manifestPath =
|
||||
GetConfigPathPtr("obs-studio\\updates\\manifest.json");
|
||||
|
||||
auto ActiveOrGameCaptureLocked = [this] ()
|
||||
{
|
||||
auto ActiveOrGameCaptureLocked = [this]() {
|
||||
if (obs_video_active()) {
|
||||
if (manualUpdate)
|
||||
info(QTStr("Updater.Running.Title"),
|
||||
|
@ -611,11 +572,8 @@ try {
|
|||
/* ----------------------------------- *
|
||||
* create signature provider */
|
||||
|
||||
if (!CryptAcquireContext(&localProvider,
|
||||
nullptr,
|
||||
MS_ENH_RSA_AES_PROV,
|
||||
PROV_RSA_AES,
|
||||
CRYPT_VERIFYCONTEXT))
|
||||
if (!CryptAcquireContext(&localProvider, nullptr, MS_ENH_RSA_AES_PROV,
|
||||
PROV_RSA_AES, CRYPT_VERIFYCONTEXT))
|
||||
throw strprintf("CryptAcquireContext failed: %lu",
|
||||
GetLastError());
|
||||
|
||||
|
@ -647,13 +605,14 @@ try {
|
|||
* get manifest from server */
|
||||
|
||||
success = GetRemoteFile(WIN_MANIFEST_URL, text, error, &responseCode,
|
||||
nullptr, nullptr, extraHeaders, &signature);
|
||||
nullptr, nullptr, extraHeaders, &signature);
|
||||
|
||||
if (!success || (responseCode != 200 && responseCode != 304)) {
|
||||
if (responseCode == 404)
|
||||
return;
|
||||
|
||||
throw strprintf("Failed to fetch manifest file: %s", error.c_str());
|
||||
throw strprintf("Failed to fetch manifest file: %s",
|
||||
error.c_str());
|
||||
}
|
||||
|
||||
/* ----------------------------------- *
|
||||
|
@ -661,8 +620,8 @@ try {
|
|||
|
||||
/* a new file must be digitally signed */
|
||||
if (responseCode == 200) {
|
||||
success = CheckDataSignature(text, "manifest",
|
||||
signature.data(), signature.size());
|
||||
success = CheckDataSignature(text, "manifest", signature.data(),
|
||||
signature.size());
|
||||
if (!success)
|
||||
throw string("Invalid manifest signature");
|
||||
}
|
||||
|
@ -687,7 +646,7 @@ try {
|
|||
int updateVer = 0;
|
||||
|
||||
success = ParseUpdateManifest(text.c_str(), &updatesAvailable, notes,
|
||||
updateVer);
|
||||
updateVer);
|
||||
if (!success)
|
||||
throw string("Failed to parse manifest");
|
||||
|
||||
|
@ -702,7 +661,7 @@ try {
|
|||
* skip this version if set to skip */
|
||||
|
||||
int skipUpdateVer = config_get_int(GetGlobalConfig(), "General",
|
||||
"SkipUpdateVersion");
|
||||
"SkipUpdateVersion");
|
||||
if (!manualUpdate && updateVer == skipUpdateVer)
|
||||
return;
|
||||
|
||||
|
@ -727,13 +686,13 @@ try {
|
|||
if (!manualUpdate) {
|
||||
long long t = (long long)time(nullptr);
|
||||
config_set_int(GetGlobalConfig(), "General",
|
||||
"LastUpdateCheck", t);
|
||||
"LastUpdateCheck", t);
|
||||
}
|
||||
return;
|
||||
|
||||
} else if (queryResult == OBSUpdate::Skip) {
|
||||
config_set_int(GetGlobalConfig(), "General",
|
||||
"SkipUpdateVersion", updateVer);
|
||||
"SkipUpdateVersion", updateVer);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -749,8 +708,8 @@ try {
|
|||
/* ----------------------------------- *
|
||||
* execute updater */
|
||||
|
||||
BPtr<char> updateFilePath = GetConfigPathPtr(
|
||||
"obs-studio\\updates\\updater.exe");
|
||||
BPtr<char> updateFilePath =
|
||||
GetConfigPathPtr("obs-studio\\updates\\updater.exe");
|
||||
BPtr<wchar_t> wUpdateFilePath;
|
||||
|
||||
size_t size = os_utf8_to_wcs_ptr(updateFilePath, 0, &wUpdateFilePath);
|
||||
|
@ -773,7 +732,7 @@ try {
|
|||
execInfo.lpParameters = UPDATE_ARG_SUFFIX;
|
||||
|
||||
execInfo.lpDirectory = cwd;
|
||||
execInfo.nShow = SW_SHOWNORMAL;
|
||||
execInfo.nShow = SW_SHOWNORMAL;
|
||||
|
||||
if (!ShellExecuteEx(&execInfo)) {
|
||||
QString msg = QTStr("Updater.FailedToLaunch");
|
||||
|
@ -787,7 +746,7 @@ try {
|
|||
config_set_int(GetGlobalConfig(), "General", "LastUpdateCheck", 0);
|
||||
config_set_int(GetGlobalConfig(), "General", "SkipUpdateVersion", 0);
|
||||
config_set_string(GetGlobalConfig(), "General", "InstallGUID",
|
||||
guid.c_str());
|
||||
guid.c_str());
|
||||
|
||||
QMetaObject::invokeMethod(App()->GetMainWindow(), "close");
|
||||
|
||||
|
@ -799,26 +758,23 @@ try {
|
|||
|
||||
void WhatsNewInfoThread::run()
|
||||
try {
|
||||
long responseCode;
|
||||
long responseCode;
|
||||
vector<string> extraHeaders;
|
||||
string text;
|
||||
string error;
|
||||
string signature;
|
||||
CryptProvider localProvider;
|
||||
BYTE whatsnewHash[BLAKE2_HASH_LENGTH];
|
||||
bool success;
|
||||
string text;
|
||||
string error;
|
||||
string signature;
|
||||
CryptProvider localProvider;
|
||||
BYTE whatsnewHash[BLAKE2_HASH_LENGTH];
|
||||
bool success;
|
||||
|
||||
BPtr<char> whatsnewPath = GetConfigPathPtr(
|
||||
"obs-studio\\updates\\whatsnew.json");
|
||||
BPtr<char> whatsnewPath =
|
||||
GetConfigPathPtr("obs-studio\\updates\\whatsnew.json");
|
||||
|
||||
/* ----------------------------------- *
|
||||
* create signature provider */
|
||||
|
||||
if (!CryptAcquireContext(&localProvider,
|
||||
nullptr,
|
||||
MS_ENH_RSA_AES_PROV,
|
||||
PROV_RSA_AES,
|
||||
CRYPT_VERIFYCONTEXT))
|
||||
if (!CryptAcquireContext(&localProvider, nullptr, MS_ENH_RSA_AES_PROV,
|
||||
PROV_RSA_AES, CRYPT_VERIFYCONTEXT))
|
||||
throw strprintf("CryptAcquireContext failed: %lu",
|
||||
GetLastError());
|
||||
|
||||
|
@ -851,7 +807,7 @@ try {
|
|||
* get json from server */
|
||||
|
||||
success = GetRemoteFile(WIN_WHATSNEW_URL, text, error, &responseCode,
|
||||
nullptr, nullptr, extraHeaders, &signature);
|
||||
nullptr, nullptr, extraHeaders, &signature);
|
||||
|
||||
if (!success || (responseCode != 200 && responseCode != 304)) {
|
||||
if (responseCode == 404)
|
||||
|
@ -865,8 +821,8 @@ try {
|
|||
* verify file signature */
|
||||
|
||||
if (responseCode == 200) {
|
||||
success = CheckDataSignature(text, "whatsnew",
|
||||
signature.data(), signature.size());
|
||||
success = CheckDataSignature(text, "whatsnew", signature.data(),
|
||||
signature.size());
|
||||
if (!success)
|
||||
throw string("Invalid whatsnew signature");
|
||||
}
|
||||
|
|
|
@ -9,9 +9,7 @@
|
|||
|
||||
using namespace json11;
|
||||
|
||||
OBSAbout::OBSAbout(QWidget *parent)
|
||||
: QDialog(parent),
|
||||
ui(new Ui::OBSAbout)
|
||||
OBSAbout::OBSAbout(QWidget *parent) : QDialog(parent), ui(new Ui::OBSAbout)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
|
@ -20,29 +18,30 @@ OBSAbout::OBSAbout(QWidget *parent)
|
|||
QString bitness;
|
||||
QString ver;
|
||||
|
||||
if(sizeof(void*) == 4)
|
||||
if (sizeof(void *) == 4)
|
||||
bitness = " (32 bit)";
|
||||
else if(sizeof(void*) == 8)
|
||||
else if (sizeof(void *) == 8)
|
||||
bitness = " (64 bit)";
|
||||
|
||||
#ifdef HAVE_OBSCONFIG_H
|
||||
ver += OBS_VERSION;
|
||||
ver += OBS_VERSION;
|
||||
#else
|
||||
ver += LIBOBS_API_MAJOR_VER + "." +
|
||||
LIBOBS_API_MINOR_VER + "." +
|
||||
LIBOBS_API_PATCH_VER;
|
||||
ver += LIBOBS_API_MAJOR_VER + "." + LIBOBS_API_MINOR_VER + "." +
|
||||
LIBOBS_API_PATCH_VER;
|
||||
#endif
|
||||
|
||||
ui->version->setText(ver + bitness);
|
||||
|
||||
ui->contribute->setText(QTStr("About.Contribute"));
|
||||
ui->donate->setText(" <a href='https://obsproject.com/donate'>" +
|
||||
QTStr("About.Donate") + "</a>");
|
||||
ui->donate->setText(
|
||||
" <a href='https://obsproject.com/donate'>" +
|
||||
QTStr("About.Donate") + "</a>");
|
||||
ui->donate->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
ui->donate->setOpenExternalLinks(true);
|
||||
|
||||
ui->getInvolved->setText(" <a href='https://github.com/obsproject/obs-studio/blob/master/CONTRIBUTING.rst'>" +
|
||||
QTStr("About.GetInvolved") + "</a>");
|
||||
ui->getInvolved->setText(
|
||||
" <a href='https://github.com/obsproject/obs-studio/blob/master/CONTRIBUTING.rst'>" +
|
||||
QTStr("About.GetInvolved") + "</a>");
|
||||
ui->getInvolved->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
ui->getInvolved->setOpenExternalLinks(true);
|
||||
|
||||
|
@ -66,12 +65,14 @@ OBSAbout::OBSAbout(QWidget *parent)
|
|||
OBSBasic *main = OBSBasic::Get();
|
||||
if (main->patronJson.empty() && !main->patronJsonThread) {
|
||||
RemoteTextThread *thread = new RemoteTextThread(
|
||||
"https://obsproject.com/patreon/about-box.json",
|
||||
"application/json");
|
||||
QObject::connect(thread, &RemoteTextThread::Result,
|
||||
main, &OBSBasic::UpdatePatronJson);
|
||||
QObject::connect(thread, SIGNAL(Result(const QString &, const QString &)),
|
||||
this, SLOT(ShowAbout()));
|
||||
"https://obsproject.com/patreon/about-box.json",
|
||||
"application/json");
|
||||
QObject::connect(thread, &RemoteTextThread::Result, main,
|
||||
&OBSBasic::UpdatePatronJson);
|
||||
QObject::connect(
|
||||
thread,
|
||||
SIGNAL(Result(const QString &, const QString &)), this,
|
||||
SLOT(ShowAbout()));
|
||||
main->patronJsonThread.reset(thread);
|
||||
thread->start();
|
||||
} else {
|
||||
|
|
|
@ -16,9 +16,9 @@ Q_DECLARE_METATYPE(OBSSource);
|
|||
OBSBasicAdvAudio::OBSBasicAdvAudio(QWidget *parent)
|
||||
: QDialog(parent),
|
||||
sourceAddedSignal(obs_get_signal_handler(), "source_activate",
|
||||
OBSSourceAdded, this),
|
||||
OBSSourceAdded, this),
|
||||
sourceRemovedSignal(obs_get_signal_handler(), "source_deactivate",
|
||||
OBSSourceRemoved, this)
|
||||
OBSSourceRemoved, this)
|
||||
{
|
||||
QScrollArea *scrollArea;
|
||||
QVBoxLayout *vlayout;
|
||||
|
@ -55,7 +55,7 @@ OBSBasicAdvAudio::OBSBasicAdvAudio(QWidget *parent)
|
|||
controlArea = new QWidget;
|
||||
controlArea->setLayout(mainLayout);
|
||||
controlArea->setSizePolicy(QSizePolicy::Preferred,
|
||||
QSizePolicy::Preferred);
|
||||
QSizePolicy::Preferred);
|
||||
|
||||
vlayout = new QVBoxLayout;
|
||||
vlayout->addWidget(controlArea);
|
||||
|
@ -80,7 +80,7 @@ OBSBasicAdvAudio::OBSBasicAdvAudio(QWidget *parent)
|
|||
vlayout->addLayout(buttonLayout);
|
||||
setLayout(vlayout);
|
||||
|
||||
connect(closeButton, &QPushButton::clicked, [this] () {close();});
|
||||
connect(closeButton, &QPushButton::clicked, [this]() { close(); });
|
||||
|
||||
installEventFilter(CreateShortcutFilter());
|
||||
|
||||
|
@ -97,7 +97,7 @@ OBSBasicAdvAudio::OBSBasicAdvAudio(QWidget *parent)
|
|||
|
||||
OBSBasicAdvAudio::~OBSBasicAdvAudio()
|
||||
{
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic*>(parent());
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic *>(parent());
|
||||
|
||||
for (size_t i = 0; i < controls.size(); ++i)
|
||||
delete controls[i];
|
||||
|
@ -107,7 +107,7 @@ OBSBasicAdvAudio::~OBSBasicAdvAudio()
|
|||
|
||||
bool OBSBasicAdvAudio::EnumSources(void *param, obs_source_t *source)
|
||||
{
|
||||
OBSBasicAdvAudio *dialog = reinterpret_cast<OBSBasicAdvAudio*>(param);
|
||||
OBSBasicAdvAudio *dialog = reinterpret_cast<OBSBasicAdvAudio *>(param);
|
||||
uint32_t flags = obs_source_get_output_flags(source);
|
||||
|
||||
if ((flags & OBS_SOURCE_AUDIO) != 0 && obs_source_active(source))
|
||||
|
@ -118,18 +118,18 @@ bool OBSBasicAdvAudio::EnumSources(void *param, obs_source_t *source)
|
|||
|
||||
void OBSBasicAdvAudio::OBSSourceAdded(void *param, calldata_t *calldata)
|
||||
{
|
||||
OBSSource source((obs_source_t*)calldata_ptr(calldata, "source"));
|
||||
OBSSource source((obs_source_t *)calldata_ptr(calldata, "source"));
|
||||
|
||||
QMetaObject::invokeMethod(reinterpret_cast<OBSBasicAdvAudio*>(param),
|
||||
"SourceAdded", Q_ARG(OBSSource, source));
|
||||
QMetaObject::invokeMethod(reinterpret_cast<OBSBasicAdvAudio *>(param),
|
||||
"SourceAdded", Q_ARG(OBSSource, source));
|
||||
}
|
||||
|
||||
void OBSBasicAdvAudio::OBSSourceRemoved(void *param, calldata_t *calldata)
|
||||
{
|
||||
OBSSource source((obs_source_t*)calldata_ptr(calldata, "source"));
|
||||
OBSSource source((obs_source_t *)calldata_ptr(calldata, "source"));
|
||||
|
||||
QMetaObject::invokeMethod(reinterpret_cast<OBSBasicAdvAudio*>(param),
|
||||
"SourceRemoved", Q_ARG(OBSSource, source));
|
||||
QMetaObject::invokeMethod(reinterpret_cast<OBSBasicAdvAudio *>(param),
|
||||
"SourceRemoved", Q_ARG(OBSSource, source));
|
||||
}
|
||||
|
||||
inline void OBSBasicAdvAudio::AddAudioSource(obs_source_t *source)
|
||||
|
|
|
@ -18,7 +18,7 @@ private:
|
|||
OBSSignal sourceAddedSignal;
|
||||
OBSSignal sourceRemovedSignal;
|
||||
|
||||
std::vector<OBSAdvAudioCtrl*> controls;
|
||||
std::vector<OBSAdvAudioCtrl *> controls;
|
||||
|
||||
inline void AddAudioSource(obs_source_t *source);
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
#include "ui_AutoConfigTestPage.h"
|
||||
|
||||
#define wiz reinterpret_cast<AutoConfig*>(wizard())
|
||||
#define wiz reinterpret_cast<AutoConfig *>(wizard())
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -31,17 +31,14 @@ class TestMode {
|
|||
gs_eparam_t *randomvals[3] = {
|
||||
gs_effect_get_param_by_name(solid, "randomvals1"),
|
||||
gs_effect_get_param_by_name(solid, "randomvals2"),
|
||||
gs_effect_get_param_by_name(solid, "randomvals3")
|
||||
};
|
||||
gs_effect_get_param_by_name(solid, "randomvals3")};
|
||||
|
||||
struct vec4 r;
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
vec4_set(&r,
|
||||
rand_float(true) * 100.0f,
|
||||
rand_float(true) * 100.0f,
|
||||
rand_float(true) * 50000.0f + 10000.0f,
|
||||
0.0f);
|
||||
vec4_set(&r, rand_float(true) * 100.0f,
|
||||
rand_float(true) * 100.0f,
|
||||
rand_float(true) * 50000.0f + 10000.0f, 0.0f);
|
||||
gs_effect_set_vec4(randomvals[i], &r);
|
||||
}
|
||||
|
||||
|
@ -86,37 +83,37 @@ public:
|
|||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#define TEST_STR(x) "Basic.AutoConfig.TestPage." x
|
||||
#define SUBTITLE_TESTING TEST_STR("Subtitle.Testing")
|
||||
#define SUBTITLE_COMPLETE TEST_STR("Subtitle.Complete")
|
||||
#define TEST_BW TEST_STR("TestingBandwidth")
|
||||
#define TEST_BW_CONNECTING TEST_STR("TestingBandwidth.Connecting")
|
||||
#define TEST_BW_CONNECT_FAIL TEST_STR("TestingBandwidth.ConnectFailed")
|
||||
#define TEST_BW_SERVER TEST_STR("TestingBandwidth.Server")
|
||||
#define TEST_RES TEST_STR("TestingRes")
|
||||
#define TEST_RES_VAL TEST_STR("TestingRes.Resolution")
|
||||
#define TEST_RES_FAIL TEST_STR("TestingRes.Fail")
|
||||
#define TEST_SE TEST_STR("TestingStreamEncoder")
|
||||
#define TEST_RE TEST_STR("TestingRecordingEncoder")
|
||||
#define TEST_RESULT_SE TEST_STR("Result.StreamingEncoder")
|
||||
#define TEST_RESULT_RE TEST_STR("Result.RecordingEncoder")
|
||||
#define TEST_STR(x) "Basic.AutoConfig.TestPage." x
|
||||
#define SUBTITLE_TESTING TEST_STR("Subtitle.Testing")
|
||||
#define SUBTITLE_COMPLETE TEST_STR("Subtitle.Complete")
|
||||
#define TEST_BW TEST_STR("TestingBandwidth")
|
||||
#define TEST_BW_CONNECTING TEST_STR("TestingBandwidth.Connecting")
|
||||
#define TEST_BW_CONNECT_FAIL TEST_STR("TestingBandwidth.ConnectFailed")
|
||||
#define TEST_BW_SERVER TEST_STR("TestingBandwidth.Server")
|
||||
#define TEST_RES TEST_STR("TestingRes")
|
||||
#define TEST_RES_VAL TEST_STR("TestingRes.Resolution")
|
||||
#define TEST_RES_FAIL TEST_STR("TestingRes.Fail")
|
||||
#define TEST_SE TEST_STR("TestingStreamEncoder")
|
||||
#define TEST_RE TEST_STR("TestingRecordingEncoder")
|
||||
#define TEST_RESULT_SE TEST_STR("Result.StreamingEncoder")
|
||||
#define TEST_RESULT_RE TEST_STR("Result.RecordingEncoder")
|
||||
|
||||
void AutoConfigTestPage::StartBandwidthStage()
|
||||
{
|
||||
ui->progressLabel->setText(QTStr(TEST_BW));
|
||||
testThread = std::thread([this] () {TestBandwidthThread();});
|
||||
testThread = std::thread([this]() { TestBandwidthThread(); });
|
||||
}
|
||||
|
||||
void AutoConfigTestPage::StartStreamEncoderStage()
|
||||
{
|
||||
ui->progressLabel->setText(QTStr(TEST_SE));
|
||||
testThread = std::thread([this] () {TestStreamEncoderThread();});
|
||||
testThread = std::thread([this]() { TestStreamEncoderThread(); });
|
||||
}
|
||||
|
||||
void AutoConfigTestPage::StartRecordingEncoderStage()
|
||||
{
|
||||
ui->progressLabel->setText(QTStr(TEST_RE));
|
||||
testThread = std::thread([this] () {TestRecordingEncoderThread();});
|
||||
testThread = std::thread([this]() { TestRecordingEncoderThread(); });
|
||||
}
|
||||
|
||||
void AutoConfigTestPage::GetServers(std::vector<ServerInfo> &servers)
|
||||
|
@ -176,21 +173,20 @@ void AutoConfigTestPage::TestBandwidthThread()
|
|||
*/
|
||||
|
||||
QMetaObject::invokeMethod(this, "UpdateMessage",
|
||||
Q_ARG(QString, QStringLiteral("")));
|
||||
Q_ARG(QString, QStringLiteral("")));
|
||||
|
||||
/* -----------------------------------*/
|
||||
/* create obs objects */
|
||||
|
||||
const char *serverType = wiz->customServer
|
||||
? "rtmp_custom"
|
||||
: "rtmp_common";
|
||||
const char *serverType = wiz->customServer ? "rtmp_custom"
|
||||
: "rtmp_common";
|
||||
|
||||
OBSEncoder vencoder = obs_video_encoder_create("obs_x264",
|
||||
"test_x264", nullptr, nullptr);
|
||||
OBSEncoder aencoder = obs_audio_encoder_create("ffmpeg_aac",
|
||||
"test_aac", nullptr, 0, nullptr);
|
||||
OBSService service = obs_service_create(serverType,
|
||||
"test_service", nullptr, nullptr);
|
||||
OBSEncoder vencoder = obs_video_encoder_create("obs_x264", "test_x264",
|
||||
nullptr, nullptr);
|
||||
OBSEncoder aencoder = obs_audio_encoder_create("ffmpeg_aac", "test_aac",
|
||||
nullptr, 0, nullptr);
|
||||
OBSService service = obs_service_create(serverType, "test_service",
|
||||
nullptr, nullptr);
|
||||
obs_encoder_release(vencoder);
|
||||
obs_encoder_release(aencoder);
|
||||
obs_service_release(service);
|
||||
|
@ -218,14 +214,14 @@ void AutoConfigTestPage::TestBandwidthThread()
|
|||
if (wiz->service == AutoConfig::Service::Twitch) {
|
||||
string_depad_key(key);
|
||||
key += "?bandwidthtest";
|
||||
}
|
||||
else if(wiz->serviceName == "Restream.io" || wiz->serviceName == "Restream.io - RTMP") {
|
||||
} else if (wiz->serviceName == "Restream.io" ||
|
||||
wiz->serviceName == "Restream.io - RTMP") {
|
||||
string_depad_key(key);
|
||||
key += "?test=true";
|
||||
}
|
||||
|
||||
obs_data_set_string(service_settings, "service",
|
||||
wiz->serviceName.c_str());
|
||||
wiz->serviceName.c_str());
|
||||
obs_data_set_string(service_settings, "key", key.c_str());
|
||||
|
||||
obs_data_set_int(vencoder_settings, "bitrate", wiz->startingBitrate);
|
||||
|
@ -235,9 +231,9 @@ void AutoConfigTestPage::TestBandwidthThread()
|
|||
|
||||
obs_data_set_int(aencoder_settings, "bitrate", 32);
|
||||
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
||||
const char *bind_ip = config_get_string(main->Config(), "Output",
|
||||
"BindIP");
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
|
||||
const char *bind_ip =
|
||||
config_get_string(main->Config(), "Output", "BindIP");
|
||||
obs_data_set_string(output_settings, "bind_ip", bind_ip);
|
||||
|
||||
/* -----------------------------------*/
|
||||
|
@ -252,11 +248,11 @@ void AutoConfigTestPage::TestBandwidthThread()
|
|||
/* just use the first server if it only has one alternate server,
|
||||
* or if using Mixer or Restream due to their "auto" servers */
|
||||
if (servers.size() < 3 || wiz->serviceName == "Mixer.com - FTL" ||
|
||||
wiz->serviceName.substr(0, 11)=="Restream.io") {
|
||||
wiz->serviceName.substr(0, 11) == "Restream.io") {
|
||||
servers.resize(1);
|
||||
|
||||
} else if (wiz->service == AutoConfig::Service::Twitch &&
|
||||
wiz->twitchAuto) {
|
||||
wiz->twitchAuto) {
|
||||
/* if using Twitch and "Auto" is available, test 3 closest
|
||||
* server */
|
||||
servers.erase(servers.begin() + 1);
|
||||
|
@ -267,8 +263,8 @@ void AutoConfigTestPage::TestBandwidthThread()
|
|||
/* apply service settings */
|
||||
|
||||
obs_service_update(service, service_settings);
|
||||
obs_service_apply_encoder_settings(service,
|
||||
vencoder_settings, aencoder_settings);
|
||||
obs_service_apply_encoder_settings(service, vencoder_settings,
|
||||
aencoder_settings);
|
||||
|
||||
/* -----------------------------------*/
|
||||
/* create output */
|
||||
|
@ -277,18 +273,17 @@ void AutoConfigTestPage::TestBandwidthThread()
|
|||
if (!output_type)
|
||||
output_type = "rtmp_output";
|
||||
|
||||
OBSOutput output = obs_output_create(output_type,
|
||||
"test_stream", nullptr, nullptr);
|
||||
OBSOutput output =
|
||||
obs_output_create(output_type, "test_stream", nullptr, nullptr);
|
||||
obs_output_release(output);
|
||||
obs_output_update(output, output_settings);
|
||||
|
||||
const char *audio_codec =
|
||||
obs_output_get_supported_audio_codecs(output);
|
||||
const char *audio_codec = obs_output_get_supported_audio_codecs(output);
|
||||
|
||||
if (strcmp(audio_codec, "aac") != 0) {
|
||||
const char *id = FindAudioEncoderFromCodec(audio_codec);
|
||||
aencoder = obs_audio_encoder_create(id,
|
||||
"test_audio", nullptr, 0, nullptr);
|
||||
aencoder = obs_audio_encoder_create(id, "test_audio", nullptr,
|
||||
0, nullptr);
|
||||
obs_encoder_release(aencoder);
|
||||
}
|
||||
|
||||
|
@ -308,16 +303,14 @@ void AutoConfigTestPage::TestBandwidthThread()
|
|||
/* -----------------------------------*/
|
||||
/* connect signals */
|
||||
|
||||
auto on_started = [&] ()
|
||||
{
|
||||
auto on_started = [&]() {
|
||||
unique_lock<mutex> lock(m);
|
||||
connected = true;
|
||||
stopped = false;
|
||||
cv.notify_one();
|
||||
};
|
||||
|
||||
auto on_stopped = [&] ()
|
||||
{
|
||||
auto on_stopped = [&]() {
|
||||
unique_lock<mutex> lock(m);
|
||||
connected = false;
|
||||
stopped = true;
|
||||
|
@ -327,17 +320,15 @@ void AutoConfigTestPage::TestBandwidthThread()
|
|||
using on_started_t = decltype(on_started);
|
||||
using on_stopped_t = decltype(on_stopped);
|
||||
|
||||
auto pre_on_started = [] (void *data, calldata_t *)
|
||||
{
|
||||
auto pre_on_started = [](void *data, calldata_t *) {
|
||||
on_started_t &on_started =
|
||||
*reinterpret_cast<on_started_t*>(data);
|
||||
*reinterpret_cast<on_started_t *>(data);
|
||||
on_started();
|
||||
};
|
||||
|
||||
auto pre_on_stopped = [] (void *data, calldata_t *)
|
||||
{
|
||||
auto pre_on_stopped = [](void *data, calldata_t *) {
|
||||
on_stopped_t &on_stopped =
|
||||
*reinterpret_cast<on_stopped_t*>(data);
|
||||
*reinterpret_cast<on_stopped_t *>(data);
|
||||
on_stopped();
|
||||
};
|
||||
|
||||
|
@ -358,12 +349,13 @@ void AutoConfigTestPage::TestBandwidthThread()
|
|||
|
||||
int per = int((i + 1) * 100 / servers.size());
|
||||
QMetaObject::invokeMethod(this, "Progress", Q_ARG(int, per));
|
||||
QMetaObject::invokeMethod(this, "UpdateMessage",
|
||||
Q_ARG(QString, QTStr(TEST_BW_CONNECTING)
|
||||
.arg(server.name.c_str())));
|
||||
QMetaObject::invokeMethod(
|
||||
this, "UpdateMessage",
|
||||
Q_ARG(QString, QTStr(TEST_BW_CONNECTING)
|
||||
.arg(server.name.c_str())));
|
||||
|
||||
obs_data_set_string(service_settings, "server",
|
||||
server.address.c_str());
|
||||
server.address.c_str());
|
||||
obs_service_update(service, service_settings);
|
||||
|
||||
if (!obs_output_start(output))
|
||||
|
@ -385,9 +377,10 @@ void AutoConfigTestPage::TestBandwidthThread()
|
|||
if (!connected)
|
||||
continue;
|
||||
|
||||
QMetaObject::invokeMethod(this, "UpdateMessage",
|
||||
Q_ARG(QString, QTStr(TEST_BW_SERVER)
|
||||
.arg(server.name.c_str())));
|
||||
QMetaObject::invokeMethod(
|
||||
this, "UpdateMessage",
|
||||
Q_ARG(QString,
|
||||
QTStr(TEST_BW_SERVER).arg(server.name.c_str())));
|
||||
|
||||
/* ignore first 2.5 seconds due to possible buffering skewing
|
||||
* the result */
|
||||
|
@ -418,10 +411,10 @@ void AutoConfigTestPage::TestBandwidthThread()
|
|||
|
||||
uint64_t total_time = os_gettime_ns() - t_start;
|
||||
|
||||
int total_bytes = (int)obs_output_get_total_bytes(output) -
|
||||
start_bytes;
|
||||
uint64_t bitrate = (uint64_t)total_bytes * 8
|
||||
* 1000000000 / total_time / 1000;
|
||||
int total_bytes =
|
||||
(int)obs_output_get_total_bytes(output) - start_bytes;
|
||||
uint64_t bitrate = (uint64_t)total_bytes * 8 * 1000000000 /
|
||||
total_time / 1000;
|
||||
|
||||
if (obs_output_get_frames_dropped(output) ||
|
||||
(int)bitrate < (wiz->startingBitrate * 75 / 100)) {
|
||||
|
@ -436,7 +429,8 @@ void AutoConfigTestPage::TestBandwidthThread()
|
|||
|
||||
if (!success) {
|
||||
QMetaObject::invokeMethod(this, "Failure",
|
||||
Q_ARG(QString, QTStr(TEST_BW_CONNECT_FAIL)));
|
||||
Q_ARG(QString,
|
||||
QTStr(TEST_BW_CONNECT_FAIL)));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -480,7 +474,8 @@ static long double EstimateMinBitrate(int cx, int cy, int fps_num, int fps_den)
|
|||
return EstimateBitrateVal(cx, cy, fps_num, fps_den) / val;
|
||||
}
|
||||
|
||||
static long double EstimateUpperBitrate(int cx, int cy, int fps_num, int fps_den)
|
||||
static long double EstimateUpperBitrate(int cx, int cy, int fps_num,
|
||||
int fps_den)
|
||||
{
|
||||
long double val = EstimateBitrateVal(1280, 720, 30, 1) / 3000.0l;
|
||||
return EstimateBitrateVal(cx, cy, fps_num, fps_den) / val;
|
||||
|
@ -520,17 +515,17 @@ bool AutoConfigTestPage::TestSoftwareEncoding()
|
|||
{
|
||||
TestMode testMode;
|
||||
QMetaObject::invokeMethod(this, "UpdateMessage",
|
||||
Q_ARG(QString, QStringLiteral("")));
|
||||
Q_ARG(QString, QStringLiteral("")));
|
||||
|
||||
/* -----------------------------------*/
|
||||
/* create obs objects */
|
||||
|
||||
OBSEncoder vencoder = obs_video_encoder_create("obs_x264",
|
||||
"test_x264", nullptr, nullptr);
|
||||
OBSEncoder aencoder = obs_audio_encoder_create("ffmpeg_aac",
|
||||
"test_aac", nullptr, 0, nullptr);
|
||||
OBSOutput output = obs_output_create("null_output",
|
||||
"null", nullptr, nullptr);
|
||||
OBSEncoder vencoder = obs_video_encoder_create("obs_x264", "test_x264",
|
||||
nullptr, nullptr);
|
||||
OBSEncoder aencoder = obs_audio_encoder_create("ffmpeg_aac", "test_aac",
|
||||
nullptr, 0, nullptr);
|
||||
OBSOutput output =
|
||||
obs_output_create("null_output", "null", nullptr, nullptr);
|
||||
obs_output_release(output);
|
||||
obs_encoder_release(vencoder);
|
||||
obs_encoder_release(aencoder);
|
||||
|
@ -547,7 +542,7 @@ bool AutoConfigTestPage::TestSoftwareEncoding()
|
|||
if (wiz->type != AutoConfig::Type::Recording) {
|
||||
obs_data_set_int(vencoder_settings, "keyint_sec", 2);
|
||||
obs_data_set_int(vencoder_settings, "bitrate",
|
||||
wiz->idealBitrate);
|
||||
wiz->idealBitrate);
|
||||
obs_data_set_string(vencoder_settings, "rate_control", "CBR");
|
||||
obs_data_set_string(vencoder_settings, "profile", "main");
|
||||
obs_data_set_string(vencoder_settings, "preset", "veryfast");
|
||||
|
@ -573,18 +568,16 @@ bool AutoConfigTestPage::TestSoftwareEncoding()
|
|||
/* -----------------------------------*/
|
||||
/* connect signals */
|
||||
|
||||
auto on_stopped = [&] ()
|
||||
{
|
||||
auto on_stopped = [&]() {
|
||||
unique_lock<mutex> lock(m);
|
||||
cv.notify_one();
|
||||
};
|
||||
|
||||
using on_stopped_t = decltype(on_stopped);
|
||||
|
||||
auto pre_on_stopped = [] (void *data, calldata_t *)
|
||||
{
|
||||
auto pre_on_stopped = [](void *data, calldata_t *) {
|
||||
on_stopped_t &on_stopped =
|
||||
*reinterpret_cast<on_stopped_t*>(data);
|
||||
*reinterpret_cast<on_stopped_t *>(data);
|
||||
on_stopped();
|
||||
};
|
||||
|
||||
|
@ -628,9 +621,8 @@ bool AutoConfigTestPage::TestSoftwareEncoding()
|
|||
int i = 0;
|
||||
int count = 1;
|
||||
|
||||
auto testRes = [&] (long double div, int fps_num, int fps_den,
|
||||
bool force)
|
||||
{
|
||||
auto testRes = [&](long double div, int fps_num, int fps_den,
|
||||
bool force) {
|
||||
int per = ++i * 100 / count;
|
||||
QMetaObject::invokeMethod(this, "Progress", Q_ARG(int, per));
|
||||
|
||||
|
@ -669,13 +661,13 @@ bool AutoConfigTestPage::TestSoftwareEncoding()
|
|||
QString cxStr = QString::number(cx);
|
||||
QString cyStr = QString::number(cy);
|
||||
|
||||
QString fpsStr = (fps_den > 1)
|
||||
? QString::number(fps, 'f', 2)
|
||||
: QString::number(fps, 'g', 2);
|
||||
QString fpsStr = (fps_den > 1) ? QString::number(fps, 'f', 2)
|
||||
: QString::number(fps, 'g', 2);
|
||||
|
||||
QMetaObject::invokeMethod(this, "UpdateMessage",
|
||||
Q_ARG(QString, QTStr(TEST_RES_VAL)
|
||||
.arg(cxStr, cyStr, fpsStr)));
|
||||
QMetaObject::invokeMethod(
|
||||
this, "UpdateMessage",
|
||||
Q_ARG(QString,
|
||||
QTStr(TEST_RES_VAL).arg(cxStr, cyStr, fpsStr)));
|
||||
|
||||
unique_lock<mutex> ul(m);
|
||||
if (cancel)
|
||||
|
@ -683,7 +675,8 @@ bool AutoConfigTestPage::TestSoftwareEncoding()
|
|||
|
||||
if (!obs_output_start(output)) {
|
||||
QMetaObject::invokeMethod(this, "Failure",
|
||||
Q_ARG(QString, QTStr(TEST_RES_FAIL)));
|
||||
Q_ARG(QString,
|
||||
QTStr(TEST_RES_FAIL)));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -692,8 +685,8 @@ bool AutoConfigTestPage::TestSoftwareEncoding()
|
|||
obs_output_stop(output);
|
||||
cv.wait(ul);
|
||||
|
||||
int skipped = (int)video_output_get_skipped_frames(
|
||||
obs_get_video());
|
||||
int skipped =
|
||||
(int)video_output_get_skipped_frames(obs_get_video());
|
||||
if (force || skipped <= 10)
|
||||
results.emplace_back(cx, cy, fps_num, fps_den);
|
||||
|
||||
|
@ -702,23 +695,38 @@ bool AutoConfigTestPage::TestSoftwareEncoding()
|
|||
|
||||
if (wiz->specificFPSNum && wiz->specificFPSDen) {
|
||||
count = 5;
|
||||
if (!testRes(1.0, 0, 0, false)) return false;
|
||||
if (!testRes(1.5, 0, 0, false)) return false;
|
||||
if (!testRes(1.0 / 0.6, 0, 0, false)) return false;
|
||||
if (!testRes(2.0, 0, 0, false)) return false;
|
||||
if (!testRes(2.25, 0, 0, true)) return false;
|
||||
if (!testRes(1.0, 0, 0, false))
|
||||
return false;
|
||||
if (!testRes(1.5, 0, 0, false))
|
||||
return false;
|
||||
if (!testRes(1.0 / 0.6, 0, 0, false))
|
||||
return false;
|
||||
if (!testRes(2.0, 0, 0, false))
|
||||
return false;
|
||||
if (!testRes(2.25, 0, 0, true))
|
||||
return false;
|
||||
} else {
|
||||
count = 10;
|
||||
if (!testRes(1.0, 60, 1, false)) return false;
|
||||
if (!testRes(1.0, 30, 1, false)) return false;
|
||||
if (!testRes(1.5, 60, 1, false)) return false;
|
||||
if (!testRes(1.5, 30, 1, false)) return false;
|
||||
if (!testRes(1.0 / 0.6, 60, 1, false)) return false;
|
||||
if (!testRes(1.0 / 0.6, 30, 1, false)) return false;
|
||||
if (!testRes(2.0, 60, 1, false)) return false;
|
||||
if (!testRes(2.0, 30, 1, false)) return false;
|
||||
if (!testRes(2.25, 60, 1, false)) return false;
|
||||
if (!testRes(2.25, 30, 1, true)) return false;
|
||||
if (!testRes(1.0, 60, 1, false))
|
||||
return false;
|
||||
if (!testRes(1.0, 30, 1, false))
|
||||
return false;
|
||||
if (!testRes(1.5, 60, 1, false))
|
||||
return false;
|
||||
if (!testRes(1.5, 30, 1, false))
|
||||
return false;
|
||||
if (!testRes(1.0 / 0.6, 60, 1, false))
|
||||
return false;
|
||||
if (!testRes(1.0 / 0.6, 30, 1, false))
|
||||
return false;
|
||||
if (!testRes(2.0, 60, 1, false))
|
||||
return false;
|
||||
if (!testRes(2.0, 30, 1, false))
|
||||
return false;
|
||||
if (!testRes(2.25, 60, 1, false))
|
||||
return false;
|
||||
if (!testRes(2.25, 30, 1, true))
|
||||
return false;
|
||||
}
|
||||
|
||||
/* -----------------------------------*/
|
||||
|
@ -744,7 +752,7 @@ bool AutoConfigTestPage::TestSoftwareEncoding()
|
|||
wiz->idealFPSDen = result.fps_den;
|
||||
|
||||
long double fUpperBitrate = EstimateUpperBitrate(
|
||||
result.cx, result.cy, result.fps_num, result.fps_den);
|
||||
result.cx, result.cy, result.fps_num, result.fps_den);
|
||||
|
||||
int upperBitrate = int(floor(fUpperBitrate / 50.0l) * 50.0l);
|
||||
|
||||
|
@ -776,9 +784,8 @@ void AutoConfigTestPage::FindIdealHardwareResolution()
|
|||
maxDataRate = 1280 * 720 * 30 + 1000;
|
||||
}
|
||||
|
||||
auto testRes = [&] (long double div, int fps_num, int fps_den,
|
||||
bool force)
|
||||
{
|
||||
auto testRes = [&](long double div, int fps_num, int fps_den,
|
||||
bool force) {
|
||||
if (results.size() >= 3)
|
||||
return;
|
||||
|
||||
|
@ -805,7 +812,8 @@ void AutoConfigTestPage::FindIdealHardwareResolution()
|
|||
* ratio, so increase the minimum bitrate estimate for them.
|
||||
* NVENC currently is the exception because of the improvements
|
||||
* its made to its quality in recent generations. */
|
||||
if (!nvenc) minBitrate = minBitrate * 114 / 100;
|
||||
if (!nvenc)
|
||||
minBitrate = minBitrate * 114 / 100;
|
||||
|
||||
if (wiz->type == AutoConfig::Type::Recording)
|
||||
force = true;
|
||||
|
@ -919,9 +927,9 @@ void AutoConfigTestPage::TestRecordingEncoderThread()
|
|||
|
||||
#define ENCODER_TEXT(x) "Basic.Settings.Output.Simple.Encoder." x
|
||||
#define ENCODER_SOFTWARE ENCODER_TEXT("Software")
|
||||
#define ENCODER_NVENC ENCODER_TEXT("Hardware.NVENC")
|
||||
#define ENCODER_QSV ENCODER_TEXT("Hardware.QSV")
|
||||
#define ENCODER_AMD ENCODER_TEXT("Hardware.AMD")
|
||||
#define ENCODER_NVENC ENCODER_TEXT("Hardware.NVENC")
|
||||
#define ENCODER_QSV ENCODER_TEXT("Hardware.QSV")
|
||||
#define ENCODER_AMD ENCODER_TEXT("Hardware.AMD")
|
||||
|
||||
#define QUALITY_SAME "Basic.Settings.Output.Simple.RecordingQuality.Stream"
|
||||
#define QUALITY_HIGH "Basic.Settings.Output.Simple.RecordingQuality.Small"
|
||||
|
@ -933,8 +941,7 @@ void AutoConfigTestPage::FinalizeResults()
|
|||
|
||||
QFormLayout *form = results;
|
||||
|
||||
auto encName = [] (AutoConfig::Encoder enc) -> QString
|
||||
{
|
||||
auto encName = [](AutoConfig::Encoder enc) -> QString {
|
||||
switch (enc) {
|
||||
case AutoConfig::Encoder::x264:
|
||||
return QTStr(ENCODER_SOFTWARE);
|
||||
|
@ -951,18 +958,16 @@ void AutoConfigTestPage::FinalizeResults()
|
|||
return QTStr(ENCODER_SOFTWARE);
|
||||
};
|
||||
|
||||
auto newLabel = [this] (const char *str) -> QLabel *
|
||||
{
|
||||
auto newLabel = [this](const char *str) -> QLabel * {
|
||||
return new QLabel(QTStr(str), this);
|
||||
};
|
||||
|
||||
if (wiz->type != AutoConfig::Type::Recording) {
|
||||
const char *serverType = wiz->customServer
|
||||
? "rtmp_custom"
|
||||
: "rtmp_common";
|
||||
const char *serverType = wiz->customServer ? "rtmp_custom"
|
||||
: "rtmp_common";
|
||||
|
||||
OBSService service = obs_service_create(serverType,
|
||||
"temp_service", nullptr, nullptr);
|
||||
OBSService service = obs_service_create(
|
||||
serverType, "temp_service", nullptr, nullptr);
|
||||
obs_service_release(service);
|
||||
|
||||
OBSData service_settings = obs_data_create();
|
||||
|
@ -971,44 +976,45 @@ void AutoConfigTestPage::FinalizeResults()
|
|||
obs_data_release(vencoder_settings);
|
||||
|
||||
obs_data_set_int(vencoder_settings, "bitrate",
|
||||
wiz->idealBitrate);
|
||||
wiz->idealBitrate);
|
||||
|
||||
obs_data_set_string(service_settings, "service",
|
||||
wiz->serviceName.c_str());
|
||||
wiz->serviceName.c_str());
|
||||
obs_service_update(service, service_settings);
|
||||
obs_service_apply_encoder_settings(service,
|
||||
vencoder_settings, nullptr);
|
||||
obs_service_apply_encoder_settings(service, vencoder_settings,
|
||||
nullptr);
|
||||
|
||||
wiz->idealBitrate = (int)obs_data_get_int(vencoder_settings,
|
||||
"bitrate");
|
||||
wiz->idealBitrate =
|
||||
(int)obs_data_get_int(vencoder_settings, "bitrate");
|
||||
|
||||
if (!wiz->customServer)
|
||||
form->addRow(
|
||||
newLabel("Basic.AutoConfig.StreamPage.Service"),
|
||||
new QLabel(wiz->serviceName.c_str(),
|
||||
ui->finishPage));
|
||||
ui->finishPage));
|
||||
form->addRow(newLabel("Basic.AutoConfig.StreamPage.Server"),
|
||||
new QLabel(wiz->serverName.c_str(), ui->finishPage));
|
||||
new QLabel(wiz->serverName.c_str(),
|
||||
ui->finishPage));
|
||||
form->addRow(newLabel("Basic.Settings.Output.VideoBitrate"),
|
||||
new QLabel(QString::number(wiz->idealBitrate),
|
||||
ui->finishPage));
|
||||
new QLabel(QString::number(wiz->idealBitrate),
|
||||
ui->finishPage));
|
||||
form->addRow(newLabel(TEST_RESULT_SE),
|
||||
new QLabel(encName(wiz->streamingEncoder),
|
||||
ui->finishPage));
|
||||
new QLabel(encName(wiz->streamingEncoder),
|
||||
ui->finishPage));
|
||||
}
|
||||
|
||||
QString baseRes = QString("%1x%2").arg(
|
||||
QString::number(wiz->baseResolutionCX),
|
||||
QString::number(wiz->baseResolutionCY));
|
||||
QString scaleRes = QString("%1x%2").arg(
|
||||
QString::number(wiz->idealResolutionCX),
|
||||
QString::number(wiz->idealResolutionCY));
|
||||
QString baseRes =
|
||||
QString("%1x%2").arg(QString::number(wiz->baseResolutionCX),
|
||||
QString::number(wiz->baseResolutionCY));
|
||||
QString scaleRes =
|
||||
QString("%1x%2").arg(QString::number(wiz->idealResolutionCX),
|
||||
QString::number(wiz->idealResolutionCY));
|
||||
|
||||
if (wiz->recordingEncoder != AutoConfig::Encoder::Stream ||
|
||||
wiz->recordingQuality != AutoConfig::Quality::Stream)
|
||||
form->addRow(newLabel(TEST_RESULT_RE),
|
||||
new QLabel(encName(wiz->recordingEncoder),
|
||||
ui->finishPage));
|
||||
new QLabel(encName(wiz->recordingEncoder),
|
||||
ui->finishPage));
|
||||
|
||||
QString recQuality;
|
||||
|
||||
|
@ -1022,21 +1028,20 @@ void AutoConfigTestPage::FinalizeResults()
|
|||
}
|
||||
|
||||
form->addRow(newLabel("Basic.Settings.Output.Simple.RecordingQuality"),
|
||||
new QLabel(recQuality, ui->finishPage));
|
||||
new QLabel(recQuality, ui->finishPage));
|
||||
|
||||
long double fps =
|
||||
(long double)wiz->idealFPSNum / (long double)wiz->idealFPSDen;
|
||||
|
||||
QString fpsStr = (wiz->idealFPSDen > 1)
|
||||
? QString::number(fps, 'f', 2)
|
||||
: QString::number(fps, 'g', 2);
|
||||
QString fpsStr = (wiz->idealFPSDen > 1) ? QString::number(fps, 'f', 2)
|
||||
: QString::number(fps, 'g', 2);
|
||||
|
||||
form->addRow(newLabel("Basic.Settings.Video.BaseResolution"),
|
||||
new QLabel(baseRes, ui->finishPage));
|
||||
new QLabel(baseRes, ui->finishPage));
|
||||
form->addRow(newLabel("Basic.Settings.Video.ScaledResolution"),
|
||||
new QLabel(scaleRes, ui->finishPage));
|
||||
new QLabel(scaleRes, ui->finishPage));
|
||||
form->addRow(newLabel("Basic.Settings.Video.FPS"),
|
||||
new QLabel(fpsStr, ui->finishPage));
|
||||
new QLabel(fpsStr, ui->finishPage));
|
||||
}
|
||||
|
||||
#define STARTING_SEPARATOR \
|
||||
|
@ -1103,8 +1108,7 @@ void AutoConfigTestPage::Progress(int percentage)
|
|||
}
|
||||
|
||||
AutoConfigTestPage::AutoConfigTestPage(QWidget *parent)
|
||||
: QWizardPage (parent),
|
||||
ui (new Ui_AutoConfigTestPage)
|
||||
: QWizardPage(parent), ui(new Ui_AutoConfigTestPage)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setTitle(QTStr("Basic.AutoConfig.TestPage"));
|
||||
|
|
|
@ -20,10 +20,10 @@
|
|||
struct QCef;
|
||||
struct QCefCookieManager;
|
||||
|
||||
extern QCef *cef;
|
||||
extern QCef *cef;
|
||||
extern QCefCookieManager *panel_cookies;
|
||||
|
||||
#define wiz reinterpret_cast<AutoConfig*>(wizard())
|
||||
#define wiz reinterpret_cast<AutoConfig *>(wizard())
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
|
@ -33,12 +33,12 @@ static OBSData OpenServiceSettings(std::string &type)
|
|||
{
|
||||
char serviceJsonPath[512];
|
||||
int ret = GetProfilePath(serviceJsonPath, sizeof(serviceJsonPath),
|
||||
SERVICE_PATH);
|
||||
SERVICE_PATH);
|
||||
if (ret <= 0)
|
||||
return OBSData();
|
||||
|
||||
OBSData data = obs_data_create_from_json_file_safe(serviceJsonPath,
|
||||
"bak");
|
||||
OBSData data =
|
||||
obs_data_create_from_json_file_safe(serviceJsonPath, "bak");
|
||||
obs_data_release(data);
|
||||
|
||||
obs_data_set_default_string(data, "type", "rtmp_common");
|
||||
|
@ -51,7 +51,7 @@ static OBSData OpenServiceSettings(std::string &type)
|
|||
}
|
||||
|
||||
static void GetServiceInfo(std::string &type, std::string &service,
|
||||
std::string &server, std::string &key)
|
||||
std::string &server, std::string &key)
|
||||
{
|
||||
OBSData settings = OpenServiceSettings(type);
|
||||
|
||||
|
@ -63,8 +63,7 @@ static void GetServiceInfo(std::string &type, std::string &service,
|
|||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
AutoConfigStartPage::AutoConfigStartPage(QWidget *parent)
|
||||
: QWizardPage (parent),
|
||||
ui (new Ui_AutoConfigStartPage)
|
||||
: QWizardPage(parent), ui(new Ui_AutoConfigStartPage)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setTitle(QTStr("Basic.AutoConfig.StartPage"));
|
||||
|
@ -93,16 +92,15 @@ void AutoConfigStartPage::on_prioritizeRecording_clicked()
|
|||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#define RES_TEXT(x) "Basic.AutoConfig.VideoPage." x
|
||||
#define RES_USE_CURRENT RES_TEXT("BaseResolution.UseCurrent")
|
||||
#define RES_USE_DISPLAY RES_TEXT("BaseResolution.Display")
|
||||
#define FPS_USE_CURRENT RES_TEXT("FPS.UseCurrent")
|
||||
#define FPS_PREFER_HIGH_FPS RES_TEXT("FPS.PreferHighFPS")
|
||||
#define FPS_PREFER_HIGH_RES RES_TEXT("FPS.PreferHighRes")
|
||||
#define RES_TEXT(x) "Basic.AutoConfig.VideoPage." x
|
||||
#define RES_USE_CURRENT RES_TEXT("BaseResolution.UseCurrent")
|
||||
#define RES_USE_DISPLAY RES_TEXT("BaseResolution.Display")
|
||||
#define FPS_USE_CURRENT RES_TEXT("FPS.UseCurrent")
|
||||
#define FPS_PREFER_HIGH_FPS RES_TEXT("FPS.PreferHighFPS")
|
||||
#define FPS_PREFER_HIGH_RES RES_TEXT("FPS.PreferHighRes")
|
||||
|
||||
AutoConfigVideoPage::AutoConfigVideoPage(QWidget *parent)
|
||||
: QWizardPage (parent),
|
||||
ui (new Ui_AutoConfigVideoPage)
|
||||
: QWizardPage(parent), ui(new Ui_AutoConfigVideoPage)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
|
@ -115,16 +113,15 @@ AutoConfigVideoPage::AutoConfigVideoPage(QWidget *parent)
|
|||
long double fpsVal =
|
||||
(long double)ovi.fps_num / (long double)ovi.fps_den;
|
||||
|
||||
QString fpsStr = (ovi.fps_den > 1)
|
||||
? QString::number(fpsVal, 'f', 2)
|
||||
: QString::number(fpsVal, 'g', 2);
|
||||
QString fpsStr = (ovi.fps_den > 1) ? QString::number(fpsVal, 'f', 2)
|
||||
: QString::number(fpsVal, 'g', 2);
|
||||
|
||||
ui->fps->addItem(QTStr(FPS_PREFER_HIGH_FPS),
|
||||
(int)AutoConfig::FPSType::PreferHighFPS);
|
||||
(int)AutoConfig::FPSType::PreferHighFPS);
|
||||
ui->fps->addItem(QTStr(FPS_PREFER_HIGH_RES),
|
||||
(int)AutoConfig::FPSType::PreferHighRes);
|
||||
(int)AutoConfig::FPSType::PreferHighRes);
|
||||
ui->fps->addItem(QTStr(FPS_USE_CURRENT).arg(fpsStr),
|
||||
(int)AutoConfig::FPSType::UseCurrent);
|
||||
(int)AutoConfig::FPSType::UseCurrent);
|
||||
ui->fps->addItem(QStringLiteral("30"), (int)AutoConfig::FPSType::fps30);
|
||||
ui->fps->addItem(QStringLiteral("60"), (int)AutoConfig::FPSType::fps60);
|
||||
ui->fps->setCurrentIndex(0);
|
||||
|
@ -134,9 +131,9 @@ AutoConfigVideoPage::AutoConfigVideoPage(QWidget *parent)
|
|||
|
||||
int encRes = int(ovi.base_width << 16) | int(ovi.base_height);
|
||||
ui->canvasRes->addItem(QTStr(RES_USE_CURRENT).arg(cxStr, cyStr),
|
||||
(int)encRes);
|
||||
(int)encRes);
|
||||
|
||||
QList<QScreen*> screens = QGuiApplication::screens();
|
||||
QList<QScreen *> screens = QGuiApplication::screens();
|
||||
for (int i = 0; i < screens.size(); i++) {
|
||||
QScreen *screen = screens[i];
|
||||
QSize as = screen->size();
|
||||
|
@ -144,19 +141,17 @@ AutoConfigVideoPage::AutoConfigVideoPage(QWidget *parent)
|
|||
encRes = int(as.width() << 16) | int(as.height());
|
||||
|
||||
QString str = QTStr(RES_USE_DISPLAY)
|
||||
.arg(QString::number(i + 1),
|
||||
QString::number(as.width()),
|
||||
QString::number(as.height()));
|
||||
.arg(QString::number(i + 1),
|
||||
QString::number(as.width()),
|
||||
QString::number(as.height()));
|
||||
|
||||
ui->canvasRes->addItem(str, encRes);
|
||||
}
|
||||
|
||||
auto addRes = [&] (int cx, int cy)
|
||||
{
|
||||
auto addRes = [&](int cx, int cy) {
|
||||
encRes = (cx << 16) | cy;
|
||||
QString str = QString("%1x%2").arg(
|
||||
QString::number(cx),
|
||||
QString::number(cy));
|
||||
QString str = QString("%1x%2").arg(QString::number(cx),
|
||||
QString::number(cy));
|
||||
ui->canvasRes->addItem(str, encRes);
|
||||
};
|
||||
|
||||
|
@ -174,8 +169,8 @@ AutoConfigVideoPage::~AutoConfigVideoPage()
|
|||
int AutoConfigVideoPage::nextId() const
|
||||
{
|
||||
return wiz->type == AutoConfig::Type::Recording
|
||||
? AutoConfig::TestPage
|
||||
: AutoConfig::StreamPage;
|
||||
? AutoConfig::TestPage
|
||||
: AutoConfig::StreamPage;
|
||||
}
|
||||
|
||||
bool AutoConfigVideoPage::validatePage()
|
||||
|
@ -223,12 +218,11 @@ bool AutoConfigVideoPage::validatePage()
|
|||
|
||||
enum class ListOpt : int {
|
||||
ShowAll = 1,
|
||||
Custom
|
||||
Custom,
|
||||
};
|
||||
|
||||
AutoConfigStreamPage::AutoConfigStreamPage(QWidget *parent)
|
||||
: QWizardPage (parent),
|
||||
ui (new Ui_AutoConfigStreamPage)
|
||||
: QWizardPage(parent), ui(new Ui_AutoConfigStreamPage)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->bitrateLabel->setVisible(false);
|
||||
|
@ -255,29 +249,29 @@ AutoConfigStreamPage::AutoConfigStreamPage(QWidget *parent)
|
|||
|
||||
LoadServices(false);
|
||||
|
||||
connect(ui->service, SIGNAL(currentIndexChanged(int)),
|
||||
this, SLOT(ServiceChanged()));
|
||||
connect(ui->customServer, SIGNAL(textChanged(const QString &)),
|
||||
this, SLOT(ServiceChanged()));
|
||||
connect(ui->doBandwidthTest, SIGNAL(toggled(bool)),
|
||||
this, SLOT(ServiceChanged()));
|
||||
connect(ui->service, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(ServiceChanged()));
|
||||
connect(ui->customServer, SIGNAL(textChanged(const QString &)), this,
|
||||
SLOT(ServiceChanged()));
|
||||
connect(ui->doBandwidthTest, SIGNAL(toggled(bool)), this,
|
||||
SLOT(ServiceChanged()));
|
||||
|
||||
connect(ui->service, SIGNAL(currentIndexChanged(int)),
|
||||
this, SLOT(UpdateServerList()));
|
||||
connect(ui->service, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(UpdateServerList()));
|
||||
|
||||
connect(ui->service, SIGNAL(currentIndexChanged(int)),
|
||||
this, SLOT(UpdateKeyLink()));
|
||||
connect(ui->service, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(UpdateKeyLink()));
|
||||
|
||||
connect(ui->key, SIGNAL(textChanged(const QString &)),
|
||||
this, SLOT(UpdateCompleted()));
|
||||
connect(ui->regionUS, SIGNAL(toggled(bool)),
|
||||
this, SLOT(UpdateCompleted()));
|
||||
connect(ui->regionEU, SIGNAL(toggled(bool)),
|
||||
this, SLOT(UpdateCompleted()));
|
||||
connect(ui->regionAsia, SIGNAL(toggled(bool)),
|
||||
this, SLOT(UpdateCompleted()));
|
||||
connect(ui->regionOther, SIGNAL(toggled(bool)),
|
||||
this, SLOT(UpdateCompleted()));
|
||||
connect(ui->key, SIGNAL(textChanged(const QString &)), this,
|
||||
SLOT(UpdateCompleted()));
|
||||
connect(ui->regionUS, SIGNAL(toggled(bool)), this,
|
||||
SLOT(UpdateCompleted()));
|
||||
connect(ui->regionEU, SIGNAL(toggled(bool)), this,
|
||||
SLOT(UpdateCompleted()));
|
||||
connect(ui->regionAsia, SIGNAL(toggled(bool)), this,
|
||||
SLOT(UpdateCompleted()));
|
||||
connect(ui->regionOther, SIGNAL(toggled(bool)), this,
|
||||
SLOT(UpdateCompleted()));
|
||||
}
|
||||
|
||||
AutoConfigStreamPage::~AutoConfigStreamPage()
|
||||
|
@ -307,17 +301,16 @@ bool AutoConfigStreamPage::validatePage()
|
|||
|
||||
wiz->customServer = IsCustom();
|
||||
|
||||
const char *serverType = wiz->customServer
|
||||
? "rtmp_custom"
|
||||
: "rtmp_common";
|
||||
const char *serverType = wiz->customServer ? "rtmp_custom"
|
||||
: "rtmp_common";
|
||||
|
||||
if (!wiz->customServer) {
|
||||
obs_data_set_string(service_settings, "service",
|
||||
QT_TO_UTF8(ui->service->currentText()));
|
||||
QT_TO_UTF8(ui->service->currentText()));
|
||||
}
|
||||
|
||||
OBSService service = obs_service_create(serverType, "temp_service",
|
||||
service_settings, nullptr);
|
||||
service_settings, nullptr);
|
||||
obs_service_release(service);
|
||||
|
||||
int bitrate = 10000;
|
||||
|
@ -365,9 +358,8 @@ bool AutoConfigStreamPage::validatePage()
|
|||
if (wiz->service != AutoConfig::Service::Twitch && wiz->bandwidthTest) {
|
||||
QMessageBox::StandardButton button;
|
||||
#define WARNING_TEXT(x) QTStr("Basic.AutoConfig.StreamPage.StreamWarning." x)
|
||||
button = OBSMessageBox::question(this,
|
||||
WARNING_TEXT("Title"),
|
||||
WARNING_TEXT("Text"));
|
||||
button = OBSMessageBox::question(this, WARNING_TEXT("Title"),
|
||||
WARNING_TEXT("Text"));
|
||||
#undef WARNING_TEXT
|
||||
|
||||
if (button == QMessageBox::No)
|
||||
|
@ -391,7 +383,7 @@ void AutoConfigStreamPage::on_show_clicked()
|
|||
void AutoConfigStreamPage::OnOAuthStreamKeyConnected()
|
||||
{
|
||||
#ifdef BROWSER_AVAILABLE
|
||||
OAuthStreamKey *a = reinterpret_cast<OAuthStreamKey*>(auth.get());
|
||||
OAuthStreamKey *a = reinterpret_cast<OAuthStreamKey *>(auth.get());
|
||||
|
||||
if (a) {
|
||||
bool validKey = !a->key().empty();
|
||||
|
@ -440,9 +432,8 @@ void AutoConfigStreamPage::on_disconnectAccount_clicked()
|
|||
{
|
||||
QMessageBox::StandardButton button;
|
||||
|
||||
button = OBSMessageBox::question(this,
|
||||
QTStr(DISCONNECT_COMFIRM_TITLE),
|
||||
QTStr(DISCONNECT_COMFIRM_TEXT));
|
||||
button = OBSMessageBox::question(this, QTStr(DISCONNECT_COMFIRM_TITLE),
|
||||
QTStr(DISCONNECT_COMFIRM_TEXT));
|
||||
|
||||
if (button == QMessageBox::No) {
|
||||
return;
|
||||
|
@ -479,14 +470,13 @@ static inline bool is_auth_service(const std::string &service)
|
|||
|
||||
void AutoConfigStreamPage::ServiceChanged()
|
||||
{
|
||||
bool showMore =
|
||||
ui->service->currentData().toInt() == (int)ListOpt::ShowAll;
|
||||
bool showMore = ui->service->currentData().toInt() ==
|
||||
(int)ListOpt::ShowAll;
|
||||
if (showMore)
|
||||
return;
|
||||
|
||||
std::string service = QT_TO_UTF8(ui->service->currentText());
|
||||
bool regionBased = service == "Twitch" ||
|
||||
service == "Smashcast";
|
||||
bool regionBased = service == "Twitch" || service == "Smashcast";
|
||||
bool testBandwidth = ui->doBandwidthTest->isChecked();
|
||||
bool custom = IsCustom();
|
||||
|
||||
|
@ -496,9 +486,8 @@ void AutoConfigStreamPage::ServiceChanged()
|
|||
if (cef) {
|
||||
if (lastService != service.c_str()) {
|
||||
bool can_auth = is_auth_service(service);
|
||||
int page = can_auth
|
||||
? (int)Section::Connect
|
||||
: (int)Section::StreamKey;
|
||||
int page = can_auth ? (int)Section::Connect
|
||||
: (int)Section::StreamKey;
|
||||
|
||||
ui->stackedWidget->setCurrentIndex(page);
|
||||
ui->streamKeyWidget->setVisible(true);
|
||||
|
@ -525,7 +514,7 @@ void AutoConfigStreamPage::ServiceChanged()
|
|||
|
||||
if (custom) {
|
||||
ui->streamkeyPageLayout->insertRow(1, ui->serverLabel,
|
||||
ui->serverStackedWidget);
|
||||
ui->serverStackedWidget);
|
||||
|
||||
ui->region->setVisible(false);
|
||||
ui->serverStackedWidget->setCurrentIndex(1);
|
||||
|
@ -533,8 +522,8 @@ void AutoConfigStreamPage::ServiceChanged()
|
|||
ui->serverLabel->setVisible(true);
|
||||
} else {
|
||||
if (!testBandwidth)
|
||||
ui->streamkeyPageLayout->insertRow(2, ui->serverLabel,
|
||||
ui->serverStackedWidget);
|
||||
ui->streamkeyPageLayout->insertRow(
|
||||
2, ui->serverLabel, ui->serverStackedWidget);
|
||||
|
||||
ui->region->setVisible(regionBased && testBandwidth);
|
||||
ui->serverStackedWidget->setCurrentIndex(0);
|
||||
|
@ -574,13 +563,15 @@ void AutoConfigStreamPage::UpdateKeyLink()
|
|||
text += " <a href=\"https://";
|
||||
text += "www.twitch.tv/broadcast/dashboard/streamkey";
|
||||
text += "\">";
|
||||
text += QTStr("Basic.AutoConfig.StreamPage.StreamKey.LinkToSite");
|
||||
text += QTStr(
|
||||
"Basic.AutoConfig.StreamPage.StreamKey.LinkToSite");
|
||||
text += "</a>";
|
||||
} else if (serviceName == "YouTube / YouTube Gaming") {
|
||||
text += " <a href=\"https://";
|
||||
text += "www.youtube.com/live_dashboard";
|
||||
text += "\">";
|
||||
text += QTStr("Basic.AutoConfig.StreamPage.StreamKey.LinkToSite");
|
||||
text += QTStr(
|
||||
"Basic.AutoConfig.StreamPage.StreamKey.LinkToSite");
|
||||
text += "</a>";
|
||||
|
||||
isYoutube = true;
|
||||
|
@ -632,9 +623,9 @@ void AutoConfigStreamPage::LoadServices(bool showAll)
|
|||
QVariant((int)ListOpt::ShowAll));
|
||||
}
|
||||
|
||||
ui->service->insertItem(0,
|
||||
QTStr("Basic.AutoConfig.StreamPage.Service.Custom"),
|
||||
QVariant((int)ListOpt::Custom));
|
||||
ui->service->insertItem(
|
||||
0, QTStr("Basic.AutoConfig.StreamPage.Service.Custom"),
|
||||
QVariant((int)ListOpt::Custom));
|
||||
|
||||
if (!lastService.isEmpty()) {
|
||||
int idx = ui->service->findText(lastService);
|
||||
|
@ -650,8 +641,8 @@ void AutoConfigStreamPage::LoadServices(bool showAll)
|
|||
void AutoConfigStreamPage::UpdateServerList()
|
||||
{
|
||||
QString serviceName = ui->service->currentText();
|
||||
bool showMore =
|
||||
ui->service->currentData().toInt() == (int)ListOpt::ShowAll;
|
||||
bool showMore = ui->service->currentData().toInt() ==
|
||||
(int)ListOpt::ShowAll;
|
||||
|
||||
if (showMore) {
|
||||
LoadServices(true);
|
||||
|
@ -706,8 +697,7 @@ void AutoConfigStreamPage::UpdateCompleted()
|
|||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
AutoConfig::AutoConfig(QWidget *parent)
|
||||
: QWizard(parent)
|
||||
AutoConfig::AutoConfig(QWidget *parent) : QWizard(parent)
|
||||
{
|
||||
EnableThreadedMessageBoxes(true);
|
||||
|
||||
|
@ -718,7 +708,7 @@ AutoConfig::AutoConfig(QWidget *parent)
|
|||
proc_handler_call(ph, "twitch_ingests_refresh", &cd);
|
||||
calldata_free(&cd);
|
||||
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic*>(parent);
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic *>(parent);
|
||||
main->EnableOutputs(false);
|
||||
|
||||
installEventFilter(CreateShortcutFilter());
|
||||
|
@ -805,14 +795,15 @@ AutoConfig::AutoConfig(QWidget *parent)
|
|||
} else {
|
||||
streamPage->ui->customServer->setText(server.c_str());
|
||||
int idx = streamPage->ui->service->findData(
|
||||
QVariant((int)ListOpt::Custom));
|
||||
QVariant((int)ListOpt::Custom));
|
||||
streamPage->ui->service->setCurrentIndex(idx);
|
||||
}
|
||||
|
||||
if (!key.empty())
|
||||
streamPage->ui->key->setText(key.c_str());
|
||||
|
||||
int bitrate = config_get_int(main->Config(), "SimpleOutput", "VBitrate");
|
||||
int bitrate =
|
||||
config_get_int(main->Config(), "SimpleOutput", "VBitrate");
|
||||
streamPage->ui->bitrate->setValue(bitrate);
|
||||
streamPage->ServiceChanged();
|
||||
|
||||
|
@ -825,13 +816,13 @@ AutoConfig::AutoConfig(QWidget *parent)
|
|||
* bitrate ratio that if NVENC is available, it makes sense to
|
||||
* just always prefer hardware encoding by default */
|
||||
bool preferHardware = nvencAvailable ||
|
||||
os_get_physical_cores() <= 4;
|
||||
os_get_physical_cores() <= 4;
|
||||
streamPage->ui->preferHardware->setChecked(preferHardware);
|
||||
}
|
||||
|
||||
setOptions(0);
|
||||
setButtonText(QWizard::FinishButton,
|
||||
QTStr("Basic.AutoConfig.ApplySettings"));
|
||||
QTStr("Basic.AutoConfig.ApplySettings"));
|
||||
setButtonText(QWizard::BackButton, QTStr("Back"));
|
||||
setButtonText(QWizard::NextButton, QTStr("Next"));
|
||||
setButtonText(QWizard::CancelButton, QTStr("Cancel"));
|
||||
|
@ -839,7 +830,7 @@ AutoConfig::AutoConfig(QWidget *parent)
|
|||
|
||||
AutoConfig::~AutoConfig()
|
||||
{
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
|
||||
main->EnableOutputs(true);
|
||||
EnableThreadedMessageBoxes(false);
|
||||
}
|
||||
|
@ -879,13 +870,13 @@ bool AutoConfig::CanTestServer(const char *server)
|
|||
if (strcmp(server, "Default") == 0) {
|
||||
return true;
|
||||
} else if (astrcmp_n(server, "US-West:", 8) == 0 ||
|
||||
astrcmp_n(server, "US-East:", 8) == 0) {
|
||||
astrcmp_n(server, "US-East:", 8) == 0) {
|
||||
return regionUS;
|
||||
} else if (astrcmp_n(server, "EU-", 3) == 0) {
|
||||
return regionEU;
|
||||
} else if (astrcmp_n(server, "South Korea:", 12) == 0 ||
|
||||
astrcmp_n(server, "Asia:", 5) == 0 ||
|
||||
astrcmp_n(server, "China:", 6) == 0) {
|
||||
astrcmp_n(server, "Asia:", 5) == 0 ||
|
||||
astrcmp_n(server, "China:", 6) == 0) {
|
||||
return regionAsia;
|
||||
} else if (regionOther) {
|
||||
return true;
|
||||
|
@ -924,14 +915,12 @@ inline const char *AutoConfig::GetEncoderId(Encoder enc)
|
|||
|
||||
void AutoConfig::SaveStreamSettings()
|
||||
{
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
|
||||
|
||||
/* ---------------------------------- */
|
||||
/* save service */
|
||||
|
||||
const char *service_id = customServer
|
||||
? "rtmp_custom"
|
||||
: "rtmp_common";
|
||||
const char *service_id = customServer ? "rtmp_custom" : "rtmp_common";
|
||||
|
||||
obs_service_t *oldService = main->GetService();
|
||||
OBSData hotkeyData = obs_hotkeys_save_service(oldService);
|
||||
|
@ -945,8 +934,8 @@ void AutoConfig::SaveStreamSettings()
|
|||
obs_data_set_string(settings, "server", server.c_str());
|
||||
obs_data_set_string(settings, "key", key.c_str());
|
||||
|
||||
OBSService newService = obs_service_create(service_id,
|
||||
"default_service", settings, hotkeyData);
|
||||
OBSService newService = obs_service_create(
|
||||
service_id, "default_service", settings, hotkeyData);
|
||||
obs_service_release(newService);
|
||||
|
||||
if (!newService)
|
||||
|
@ -962,26 +951,26 @@ void AutoConfig::SaveStreamSettings()
|
|||
/* save stream settings */
|
||||
|
||||
config_set_int(main->Config(), "SimpleOutput", "VBitrate",
|
||||
idealBitrate);
|
||||
idealBitrate);
|
||||
config_set_string(main->Config(), "SimpleOutput", "StreamEncoder",
|
||||
GetEncoderId(streamingEncoder));
|
||||
GetEncoderId(streamingEncoder));
|
||||
config_remove_value(main->Config(), "SimpleOutput", "UseAdvanced");
|
||||
}
|
||||
|
||||
void AutoConfig::SaveSettings()
|
||||
{
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
|
||||
|
||||
if (recordingEncoder != Encoder::Stream)
|
||||
config_set_string(main->Config(), "SimpleOutput", "RecEncoder",
|
||||
GetEncoderId(recordingEncoder));
|
||||
GetEncoderId(recordingEncoder));
|
||||
|
||||
const char *quality = recordingQuality == Quality::High
|
||||
? "Small"
|
||||
: "Stream";
|
||||
const char *quality = recordingQuality == Quality::High ? "Small"
|
||||
: "Stream";
|
||||
|
||||
config_set_string(main->Config(), "Output", "Mode", "Simple");
|
||||
config_set_string(main->Config(), "SimpleOutput", "RecQuality", quality);
|
||||
config_set_string(main->Config(), "SimpleOutput", "RecQuality",
|
||||
quality);
|
||||
config_set_int(main->Config(), "Video", "BaseCX", baseResolutionCX);
|
||||
config_set_int(main->Config(), "Video", "BaseCY", baseResolutionCY);
|
||||
config_set_int(main->Config(), "Video", "OutputCX", idealResolutionCX);
|
||||
|
@ -990,7 +979,7 @@ void AutoConfig::SaveSettings()
|
|||
if (fpsType != FPSType::UseCurrent) {
|
||||
config_set_uint(main->Config(), "Video", "FPSType", 0);
|
||||
config_set_string(main->Config(), "Video", "FPSCommon",
|
||||
std::to_string(idealFPSNum).c_str());
|
||||
std::to_string(idealFPSNum).c_str());
|
||||
}
|
||||
|
||||
main->ResetVideo();
|
||||
|
|
|
@ -32,13 +32,13 @@ class AutoConfig : public QWizard {
|
|||
enum class Type {
|
||||
Invalid,
|
||||
Streaming,
|
||||
Recording
|
||||
Recording,
|
||||
};
|
||||
|
||||
enum class Service {
|
||||
Twitch,
|
||||
Smashcast,
|
||||
Other
|
||||
Other,
|
||||
};
|
||||
|
||||
enum class Encoder {
|
||||
|
@ -46,12 +46,12 @@ class AutoConfig : public QWizard {
|
|||
NVENC,
|
||||
QSV,
|
||||
AMD,
|
||||
Stream
|
||||
Stream,
|
||||
};
|
||||
|
||||
enum class Quality {
|
||||
Stream,
|
||||
High
|
||||
High,
|
||||
};
|
||||
|
||||
enum class FPSType : int {
|
||||
|
@ -59,7 +59,7 @@ class AutoConfig : public QWizard {
|
|||
PreferHighRes,
|
||||
UseCurrent,
|
||||
fps30,
|
||||
fps60
|
||||
fps60,
|
||||
};
|
||||
|
||||
static inline const char *GetEncoderId(Encoder enc);
|
||||
|
@ -119,7 +119,7 @@ public:
|
|||
StartPage,
|
||||
VideoPage,
|
||||
StreamPage,
|
||||
TestPage
|
||||
TestPage,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -216,7 +216,7 @@ class AutoConfigTestPage : public QWizardPage {
|
|||
BandwidthTest,
|
||||
StreamEncoder,
|
||||
RecordingEncoder,
|
||||
Finished
|
||||
Finished,
|
||||
};
|
||||
|
||||
Stage stage = Stage::Starting;
|
||||
|
|
|
@ -36,45 +36,39 @@ using namespace std;
|
|||
Q_DECLARE_METATYPE(OBSSource);
|
||||
|
||||
OBSBasicFilters::OBSBasicFilters(QWidget *parent, OBSSource source_)
|
||||
: QDialog (parent),
|
||||
ui (new Ui::OBSBasicFilters),
|
||||
source (source_),
|
||||
addSignal (obs_source_get_signal_handler(source),
|
||||
"filter_add",
|
||||
OBSBasicFilters::OBSSourceFilterAdded,
|
||||
this),
|
||||
removeSignal (obs_source_get_signal_handler(source),
|
||||
"filter_remove",
|
||||
OBSBasicFilters::OBSSourceFilterRemoved,
|
||||
this),
|
||||
reorderSignal (obs_source_get_signal_handler(source),
|
||||
"reorder_filters",
|
||||
OBSBasicFilters::OBSSourceReordered,
|
||||
this),
|
||||
removeSourceSignal (obs_source_get_signal_handler(source),
|
||||
"remove",
|
||||
OBSBasicFilters::SourceRemoved, this),
|
||||
renameSourceSignal (obs_source_get_signal_handler(source),
|
||||
"rename",
|
||||
OBSBasicFilters::SourceRenamed, this),
|
||||
noPreviewMargin (13)
|
||||
: QDialog(parent),
|
||||
ui(new Ui::OBSBasicFilters),
|
||||
source(source_),
|
||||
addSignal(obs_source_get_signal_handler(source), "filter_add",
|
||||
OBSBasicFilters::OBSSourceFilterAdded, this),
|
||||
removeSignal(obs_source_get_signal_handler(source), "filter_remove",
|
||||
OBSBasicFilters::OBSSourceFilterRemoved, this),
|
||||
reorderSignal(obs_source_get_signal_handler(source),
|
||||
"reorder_filters", OBSBasicFilters::OBSSourceReordered,
|
||||
this),
|
||||
removeSourceSignal(obs_source_get_signal_handler(source), "remove",
|
||||
OBSBasicFilters::SourceRemoved, this),
|
||||
renameSourceSignal(obs_source_get_signal_handler(source), "rename",
|
||||
OBSBasicFilters::SourceRenamed, this),
|
||||
noPreviewMargin(13)
|
||||
{
|
||||
main = reinterpret_cast<OBSBasic*>(parent);
|
||||
main = reinterpret_cast<OBSBasic *>(parent);
|
||||
|
||||
ui->setupUi(this);
|
||||
UpdateFilters();
|
||||
|
||||
ui->asyncFilters->setItemDelegate(
|
||||
new VisibilityItemDelegate(ui->asyncFilters));
|
||||
new VisibilityItemDelegate(ui->asyncFilters));
|
||||
ui->effectFilters->setItemDelegate(
|
||||
new VisibilityItemDelegate(ui->effectFilters));
|
||||
new VisibilityItemDelegate(ui->effectFilters));
|
||||
|
||||
const char *name = obs_source_get_name(source);
|
||||
setWindowTitle(QTStr("Basic.Filters.Title").arg(QT_UTF8(name)));
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
|
||||
#ifndef QT_NO_SHORTCUT
|
||||
ui->actionRemoveFilter->setShortcut(QApplication::translate("OBSBasicFilters", "Del", nullptr));
|
||||
ui->actionRemoveFilter->setShortcut(
|
||||
QApplication::translate("OBSBasicFilters", "Del", nullptr));
|
||||
#endif // QT_NO_SHORTCUT
|
||||
|
||||
addAction(ui->actionRemoveFilter);
|
||||
|
@ -84,33 +78,33 @@ OBSBasicFilters::OBSBasicFilters(QWidget *parent, OBSSource source_)
|
|||
installEventFilter(CreateShortcutFilter());
|
||||
|
||||
connect(ui->asyncFilters->itemDelegate(),
|
||||
SIGNAL(closeEditor(QWidget*,
|
||||
QAbstractItemDelegate::EndEditHint)),
|
||||
this,
|
||||
SLOT(AsyncFilterNameEdited(QWidget*,
|
||||
QAbstractItemDelegate::EndEditHint)));
|
||||
SIGNAL(closeEditor(QWidget *,
|
||||
QAbstractItemDelegate::EndEditHint)),
|
||||
this,
|
||||
SLOT(AsyncFilterNameEdited(
|
||||
QWidget *, QAbstractItemDelegate::EndEditHint)));
|
||||
|
||||
connect(ui->effectFilters->itemDelegate(),
|
||||
SIGNAL(closeEditor(QWidget*,
|
||||
QAbstractItemDelegate::EndEditHint)),
|
||||
this,
|
||||
SLOT(EffectFilterNameEdited(QWidget*,
|
||||
QAbstractItemDelegate::EndEditHint)));
|
||||
SIGNAL(closeEditor(QWidget *,
|
||||
QAbstractItemDelegate::EndEditHint)),
|
||||
this,
|
||||
SLOT(EffectFilterNameEdited(
|
||||
QWidget *, QAbstractItemDelegate::EndEditHint)));
|
||||
|
||||
QPushButton *close = ui->buttonBox->button(QDialogButtonBox::Close);
|
||||
connect(close, SIGNAL(clicked()), this, SLOT(close()));
|
||||
close->setDefault(true);
|
||||
|
||||
ui->buttonBox->button(QDialogButtonBox::Reset)->setText(
|
||||
QTStr("Defaults"));
|
||||
ui->buttonBox->button(QDialogButtonBox::Reset)
|
||||
->setText(QTStr("Defaults"));
|
||||
|
||||
connect(ui->buttonBox->button(QDialogButtonBox::Reset),
|
||||
SIGNAL(clicked()), this, SLOT(ResetFilters()));
|
||||
|
||||
uint32_t caps = obs_source_get_output_flags(source);
|
||||
bool audio = (caps & OBS_SOURCE_AUDIO) != 0;
|
||||
bool audio = (caps & OBS_SOURCE_AUDIO) != 0;
|
||||
bool audioOnly = (caps & OBS_SOURCE_VIDEO) == 0;
|
||||
bool async = (caps & OBS_SOURCE_ASYNC) != 0;
|
||||
bool async = (caps & OBS_SOURCE_ASYNC) != 0;
|
||||
|
||||
if (!async && !audio) {
|
||||
ui->asyncWidget->setVisible(false);
|
||||
|
@ -124,22 +118,22 @@ OBSBasicFilters::OBSBasicFilters(QWidget *parent, OBSSource source_)
|
|||
if (audioOnly || (audio && !async))
|
||||
ui->asyncLabel->setText(QTStr("Basic.Filters.AudioFilters"));
|
||||
|
||||
auto addDrawCallback = [this] ()
|
||||
{
|
||||
auto addDrawCallback = [this]() {
|
||||
obs_display_add_draw_callback(ui->preview->GetDisplay(),
|
||||
OBSBasicFilters::DrawPreview, this);
|
||||
OBSBasicFilters::DrawPreview,
|
||||
this);
|
||||
};
|
||||
|
||||
enum obs_source_type type = obs_source_get_type(source);
|
||||
bool drawable_type = type == OBS_SOURCE_TYPE_INPUT ||
|
||||
type == OBS_SOURCE_TYPE_SCENE;
|
||||
type == OBS_SOURCE_TYPE_SCENE;
|
||||
|
||||
if ((caps & OBS_SOURCE_VIDEO) != 0) {
|
||||
ui->rightLayout->setContentsMargins(0, 0, 0, 0);
|
||||
ui->preview->show();
|
||||
if (drawable_type)
|
||||
connect(ui->preview, &OBSQTDisplay::DisplayCreated,
|
||||
addDrawCallback);
|
||||
addDrawCallback);
|
||||
} else {
|
||||
ui->rightLayout->setContentsMargins(0, noPreviewMargin, 0, 0);
|
||||
ui->rightContainerLayout->insertStretch(1);
|
||||
|
@ -187,14 +181,14 @@ void OBSBasicFilters::UpdatePropertiesView(int row, bool async)
|
|||
|
||||
obs_data_t *settings = obs_source_get_settings(filter);
|
||||
|
||||
view = new OBSPropertiesView(settings, filter,
|
||||
(PropertiesReloadCallback)obs_source_properties,
|
||||
(PropertiesUpdateCallback)obs_source_update);
|
||||
view = new OBSPropertiesView(
|
||||
settings, filter,
|
||||
(PropertiesReloadCallback)obs_source_properties,
|
||||
(PropertiesUpdateCallback)obs_source_update);
|
||||
|
||||
updatePropertiesSignal.Connect(obs_source_get_signal_handler(filter),
|
||||
"update_properties",
|
||||
OBSBasicFilters::UpdateProperties,
|
||||
this);
|
||||
"update_properties",
|
||||
OBSBasicFilters::UpdateProperties, this);
|
||||
|
||||
obs_data_release(settings);
|
||||
|
||||
|
@ -206,8 +200,8 @@ void OBSBasicFilters::UpdatePropertiesView(int row, bool async)
|
|||
|
||||
void OBSBasicFilters::UpdateProperties(void *data, calldata_t *)
|
||||
{
|
||||
QMetaObject::invokeMethod(static_cast<OBSBasicFilters*>(data)->view,
|
||||
"ReloadProperties");
|
||||
QMetaObject::invokeMethod(static_cast<OBSBasicFilters *>(data)->view,
|
||||
"ReloadProperties");
|
||||
}
|
||||
|
||||
void OBSBasicFilters::AddFilter(OBSSource filter)
|
||||
|
@ -252,7 +246,7 @@ void OBSBasicFilters::RemoveFilter(OBSSource filter)
|
|||
const char *filterId = obs_source_get_id(filter);
|
||||
|
||||
blog(LOG_INFO, "User removed filter '%s' (%s) from source '%s'",
|
||||
filterName, filterId, sourceName);
|
||||
filterName, filterId, sourceName);
|
||||
|
||||
main->SaveProject();
|
||||
}
|
||||
|
@ -265,8 +259,8 @@ struct FilterOrderInfo {
|
|||
inline FilterOrderInfo(OBSBasicFilters *window_) : window(window_) {}
|
||||
};
|
||||
|
||||
void OBSBasicFilters::ReorderFilter(QListWidget *list,
|
||||
obs_source_t *filter, size_t idx)
|
||||
void OBSBasicFilters::ReorderFilter(QListWidget *list, obs_source_t *filter,
|
||||
size_t idx)
|
||||
{
|
||||
int count = list->count();
|
||||
|
||||
|
@ -280,10 +274,10 @@ void OBSBasicFilters::ReorderFilter(QListWidget *list,
|
|||
bool sel = (list->currentRow() == i);
|
||||
|
||||
listItem = TakeListItem(list, i);
|
||||
if (listItem) {
|
||||
if (listItem) {
|
||||
list->insertItem((int)idx, listItem);
|
||||
SetupVisibilityItem(list,
|
||||
listItem, filterItem);
|
||||
SetupVisibilityItem(list, listItem,
|
||||
filterItem);
|
||||
|
||||
if (sel)
|
||||
list->setCurrentRow((int)idx);
|
||||
|
@ -299,27 +293,28 @@ void OBSBasicFilters::ReorderFilters()
|
|||
{
|
||||
FilterOrderInfo info(this);
|
||||
|
||||
obs_source_enum_filters(source,
|
||||
[] (obs_source_t*, obs_source_t *filter, void *p)
|
||||
{
|
||||
FilterOrderInfo *info =
|
||||
reinterpret_cast<FilterOrderInfo*>(p);
|
||||
uint32_t flags;
|
||||
bool async;
|
||||
obs_source_enum_filters(
|
||||
source,
|
||||
[](obs_source_t *, obs_source_t *filter, void *p) {
|
||||
FilterOrderInfo *info =
|
||||
reinterpret_cast<FilterOrderInfo *>(p);
|
||||
uint32_t flags;
|
||||
bool async;
|
||||
|
||||
flags = obs_source_get_output_flags(filter);
|
||||
async = (flags & OBS_SOURCE_ASYNC) != 0;
|
||||
flags = obs_source_get_output_flags(filter);
|
||||
async = (flags & OBS_SOURCE_ASYNC) != 0;
|
||||
|
||||
if (async) {
|
||||
info->window->ReorderFilter(
|
||||
info->window->ui->asyncFilters,
|
||||
filter, info->asyncIdx++);
|
||||
} else {
|
||||
info->window->ReorderFilter(
|
||||
info->window->ui->effectFilters,
|
||||
filter, info->effectIdx++);
|
||||
}
|
||||
}, &info);
|
||||
if (async) {
|
||||
info->window->ReorderFilter(
|
||||
info->window->ui->asyncFilters, filter,
|
||||
info->asyncIdx++);
|
||||
} else {
|
||||
info->window->ReorderFilter(
|
||||
info->window->ui->effectFilters, filter,
|
||||
info->effectIdx++);
|
||||
}
|
||||
},
|
||||
&info);
|
||||
}
|
||||
|
||||
void OBSBasicFilters::UpdateFilters()
|
||||
|
@ -330,33 +325,34 @@ void OBSBasicFilters::UpdateFilters()
|
|||
ClearListItems(ui->effectFilters);
|
||||
ClearListItems(ui->asyncFilters);
|
||||
|
||||
obs_source_enum_filters(source,
|
||||
[] (obs_source_t*, obs_source_t *filter, void *p)
|
||||
{
|
||||
OBSBasicFilters *window =
|
||||
reinterpret_cast<OBSBasicFilters*>(p);
|
||||
obs_source_enum_filters(
|
||||
source,
|
||||
[](obs_source_t *, obs_source_t *filter, void *p) {
|
||||
OBSBasicFilters *window =
|
||||
reinterpret_cast<OBSBasicFilters *>(p);
|
||||
|
||||
window->AddFilter(filter);
|
||||
}, this);
|
||||
window->AddFilter(filter);
|
||||
},
|
||||
this);
|
||||
|
||||
main->SaveProject();
|
||||
}
|
||||
|
||||
static bool filter_compatible(bool async, uint32_t sourceFlags,
|
||||
uint32_t filterFlags)
|
||||
uint32_t filterFlags)
|
||||
{
|
||||
bool filterVideo = (filterFlags & OBS_SOURCE_VIDEO) != 0;
|
||||
bool filterAsync = (filterFlags & OBS_SOURCE_ASYNC) != 0;
|
||||
bool filterAudio = (filterFlags & OBS_SOURCE_AUDIO) != 0;
|
||||
bool audio = (sourceFlags & OBS_SOURCE_AUDIO) != 0;
|
||||
bool audioOnly = (sourceFlags & OBS_SOURCE_VIDEO) == 0;
|
||||
bool audio = (sourceFlags & OBS_SOURCE_AUDIO) != 0;
|
||||
bool audioOnly = (sourceFlags & OBS_SOURCE_VIDEO) == 0;
|
||||
bool asyncSource = (sourceFlags & OBS_SOURCE_ASYNC) != 0;
|
||||
|
||||
if (async && ((audioOnly && filterVideo) || (!audio && !asyncSource)))
|
||||
return false;
|
||||
|
||||
return (async && (filterAudio || filterAsync)) ||
|
||||
(!async && !filterAudio && !filterAsync);
|
||||
(!async && !filterAudio && !filterAsync);
|
||||
}
|
||||
|
||||
QMenu *OBSBasicFilters::CreateAddFilterPopupMenu(bool async)
|
||||
|
@ -372,7 +368,8 @@ QMenu *OBSBasicFilters::CreateAddFilterPopupMenu(bool async)
|
|||
|
||||
inline FilterInfo(const char *type_, const char *name_)
|
||||
: type(type_), name(name_)
|
||||
{}
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
vector<FilterInfo> types;
|
||||
|
@ -396,17 +393,17 @@ QMenu *OBSBasicFilters::CreateAddFilterPopupMenu(bool async)
|
|||
|
||||
QMenu *popup = new QMenu(QTStr("Add"), this);
|
||||
for (FilterInfo &type : types) {
|
||||
uint32_t filterFlags = obs_get_source_output_flags(
|
||||
type.type.c_str());
|
||||
uint32_t filterFlags =
|
||||
obs_get_source_output_flags(type.type.c_str());
|
||||
|
||||
if (!filter_compatible(async, sourceFlags, filterFlags))
|
||||
continue;
|
||||
|
||||
QAction *popupItem = new QAction(QT_UTF8(type.name.c_str()),
|
||||
this);
|
||||
QAction *popupItem =
|
||||
new QAction(QT_UTF8(type.name.c_str()), this);
|
||||
popupItem->setData(QT_UTF8(type.type.c_str()));
|
||||
connect(popupItem, SIGNAL(triggered(bool)),
|
||||
this, SLOT(AddFilterFromAction()));
|
||||
connect(popupItem, SIGNAL(triggered(bool)), this,
|
||||
SLOT(AddFilterFromAction()));
|
||||
popup->addAction(popupItem);
|
||||
|
||||
foundValues = true;
|
||||
|
@ -426,40 +423,40 @@ void OBSBasicFilters::AddNewFilter(const char *id)
|
|||
obs_source_t *existing_filter;
|
||||
string name = obs_source_get_display_name(id);
|
||||
|
||||
bool success = NameDialog::AskForName(this,
|
||||
QTStr("Basic.Filters.AddFilter.Title"),
|
||||
QTStr("Basic.FIlters.AddFilter.Text"), name,
|
||||
QT_UTF8(name.c_str()));
|
||||
bool success = NameDialog::AskForName(
|
||||
this, QTStr("Basic.Filters.AddFilter.Title"),
|
||||
QTStr("Basic.FIlters.AddFilter.Text"), name,
|
||||
QT_UTF8(name.c_str()));
|
||||
if (!success)
|
||||
return;
|
||||
|
||||
if (name.empty()) {
|
||||
OBSMessageBox::warning(this,
|
||||
QTStr("NoNameEntered.Title"),
|
||||
QTStr("NoNameEntered.Text"));
|
||||
QTStr("NoNameEntered.Title"),
|
||||
QTStr("NoNameEntered.Text"));
|
||||
AddNewFilter(id);
|
||||
return;
|
||||
}
|
||||
|
||||
existing_filter = obs_source_get_filter_by_name(source,
|
||||
name.c_str());
|
||||
existing_filter =
|
||||
obs_source_get_filter_by_name(source, name.c_str());
|
||||
if (existing_filter) {
|
||||
OBSMessageBox::warning(this,
|
||||
QTStr("NameExists.Title"),
|
||||
QTStr("NameExists.Text"));
|
||||
OBSMessageBox::warning(this, QTStr("NameExists.Title"),
|
||||
QTStr("NameExists.Text"));
|
||||
obs_source_release(existing_filter);
|
||||
AddNewFilter(id);
|
||||
return;
|
||||
}
|
||||
|
||||
obs_source_t *filter = obs_source_create(id, name.c_str(),
|
||||
nullptr, nullptr);
|
||||
obs_source_t *filter =
|
||||
obs_source_create(id, name.c_str(), nullptr, nullptr);
|
||||
if (filter) {
|
||||
const char *sourceName = obs_source_get_name(source);
|
||||
|
||||
blog(LOG_INFO, "User added filter '%s' (%s) "
|
||||
"to source '%s'",
|
||||
name.c_str(), id, sourceName);
|
||||
blog(LOG_INFO,
|
||||
"User added filter '%s' (%s) "
|
||||
"to source '%s'",
|
||||
name.c_str(), id, sourceName);
|
||||
|
||||
obs_source_filter_add(source, filter);
|
||||
obs_source_release(filter);
|
||||
|
@ -469,7 +466,7 @@ void OBSBasicFilters::AddNewFilter(const char *id)
|
|||
|
||||
void OBSBasicFilters::AddFilterFromAction()
|
||||
{
|
||||
QAction *action = qobject_cast<QAction*>(sender());
|
||||
QAction *action = qobject_cast<QAction *>(sender());
|
||||
if (!action)
|
||||
return;
|
||||
|
||||
|
@ -482,8 +479,8 @@ void OBSBasicFilters::closeEvent(QCloseEvent *event)
|
|||
if (!event->isAccepted())
|
||||
return;
|
||||
|
||||
obs_display_remove_draw_callback (ui->preview->GetDisplay(),
|
||||
OBSBasicFilters::DrawPreview, this);
|
||||
obs_display_remove_draw_callback(ui->preview->GetDisplay(),
|
||||
OBSBasicFilters::DrawPreview, this);
|
||||
|
||||
main->SaveProject();
|
||||
}
|
||||
|
@ -492,26 +489,26 @@ void OBSBasicFilters::closeEvent(QCloseEvent *event)
|
|||
|
||||
void OBSBasicFilters::OBSSourceFilterAdded(void *param, calldata_t *data)
|
||||
{
|
||||
OBSBasicFilters *window = reinterpret_cast<OBSBasicFilters*>(param);
|
||||
obs_source_t *filter = (obs_source_t*)calldata_ptr(data, "filter");
|
||||
OBSBasicFilters *window = reinterpret_cast<OBSBasicFilters *>(param);
|
||||
obs_source_t *filter = (obs_source_t *)calldata_ptr(data, "filter");
|
||||
|
||||
QMetaObject::invokeMethod(window, "AddFilter",
|
||||
Q_ARG(OBSSource, OBSSource(filter)));
|
||||
Q_ARG(OBSSource, OBSSource(filter)));
|
||||
}
|
||||
|
||||
void OBSBasicFilters::OBSSourceFilterRemoved(void *param, calldata_t *data)
|
||||
{
|
||||
OBSBasicFilters *window = reinterpret_cast<OBSBasicFilters*>(param);
|
||||
obs_source_t *filter = (obs_source_t*)calldata_ptr(data, "filter");
|
||||
OBSBasicFilters *window = reinterpret_cast<OBSBasicFilters *>(param);
|
||||
obs_source_t *filter = (obs_source_t *)calldata_ptr(data, "filter");
|
||||
|
||||
QMetaObject::invokeMethod(window, "RemoveFilter",
|
||||
Q_ARG(OBSSource, OBSSource(filter)));
|
||||
Q_ARG(OBSSource, OBSSource(filter)));
|
||||
}
|
||||
|
||||
void OBSBasicFilters::OBSSourceReordered(void *param, calldata_t *data)
|
||||
{
|
||||
QMetaObject::invokeMethod(reinterpret_cast<OBSBasicFilters*>(param),
|
||||
"ReorderFilters");
|
||||
QMetaObject::invokeMethod(reinterpret_cast<OBSBasicFilters *>(param),
|
||||
"ReorderFilters");
|
||||
|
||||
UNUSED_PARAMETER(data);
|
||||
}
|
||||
|
@ -520,8 +517,8 @@ void OBSBasicFilters::SourceRemoved(void *param, calldata_t *data)
|
|||
{
|
||||
UNUSED_PARAMETER(data);
|
||||
|
||||
QMetaObject::invokeMethod(static_cast<OBSBasicFilters*>(param),
|
||||
"close");
|
||||
QMetaObject::invokeMethod(static_cast<OBSBasicFilters *>(param),
|
||||
"close");
|
||||
}
|
||||
|
||||
void OBSBasicFilters::SourceRenamed(void *param, calldata_t *data)
|
||||
|
@ -529,13 +526,13 @@ void OBSBasicFilters::SourceRenamed(void *param, calldata_t *data)
|
|||
const char *name = calldata_string(data, "new_name");
|
||||
QString title = QTStr("Basic.Filters.Title").arg(QT_UTF8(name));
|
||||
|
||||
QMetaObject::invokeMethod(static_cast<OBSBasicFilters*>(param),
|
||||
"setWindowTitle", Q_ARG(QString, title));
|
||||
QMetaObject::invokeMethod(static_cast<OBSBasicFilters *>(param),
|
||||
"setWindowTitle", Q_ARG(QString, title));
|
||||
}
|
||||
|
||||
void OBSBasicFilters::DrawPreview(void *data, uint32_t cx, uint32_t cy)
|
||||
{
|
||||
OBSBasicFilters *window = static_cast<OBSBasicFilters*>(data);
|
||||
OBSBasicFilters *window = static_cast<OBSBasicFilters *>(data);
|
||||
|
||||
if (!window->source)
|
||||
return;
|
||||
|
@ -543,8 +540,8 @@ void OBSBasicFilters::DrawPreview(void *data, uint32_t cx, uint32_t cy)
|
|||
uint32_t sourceCX = max(obs_source_get_width(window->source), 1u);
|
||||
uint32_t sourceCY = max(obs_source_get_height(window->source), 1u);
|
||||
|
||||
int x, y;
|
||||
int newCX, newCY;
|
||||
int x, y;
|
||||
int newCX, newCY;
|
||||
float scale;
|
||||
|
||||
GetScaleAndCenterPos(sourceCX, sourceCY, cx, cy, x, y, scale);
|
||||
|
@ -567,15 +564,15 @@ void OBSBasicFilters::DrawPreview(void *data, uint32_t cx, uint32_t cy)
|
|||
|
||||
static bool QueryRemove(QWidget *parent, obs_source_t *source)
|
||||
{
|
||||
const char *name = obs_source_get_name(source);
|
||||
const char *name = obs_source_get_name(source);
|
||||
|
||||
QString text = QTStr("ConfirmRemove.Text");
|
||||
text.replace("$1", QT_UTF8(name));
|
||||
|
||||
QMessageBox remove_source(parent);
|
||||
remove_source.setText(text);
|
||||
QAbstractButton *Yes = remove_source.addButton(QTStr("Yes"),
|
||||
QMessageBox::YesRole);
|
||||
QAbstractButton *Yes =
|
||||
remove_source.addButton(QTStr("Yes"), QMessageBox::YesRole);
|
||||
remove_source.addButton(QTStr("No"), QMessageBox::NoRole);
|
||||
remove_source.setIcon(QMessageBox::Question);
|
||||
remove_source.setWindowTitle(QTStr("ConfirmRemove.Title"));
|
||||
|
@ -612,7 +609,7 @@ void OBSBasicFilters::on_moveAsyncFilterDown_clicked()
|
|||
OBSSource filter = GetFilter(ui->asyncFilters->currentRow(), true);
|
||||
if (filter)
|
||||
obs_source_filter_set_order(source, filter,
|
||||
OBS_ORDER_MOVE_DOWN);
|
||||
OBS_ORDER_MOVE_DOWN);
|
||||
}
|
||||
|
||||
void OBSBasicFilters::on_asyncFilters_GotFocus()
|
||||
|
@ -654,7 +651,7 @@ void OBSBasicFilters::on_moveEffectFilterDown_clicked()
|
|||
OBSSource filter = GetFilter(ui->effectFilters->currentRow(), false);
|
||||
if (filter)
|
||||
obs_source_filter_set_order(source, filter,
|
||||
OBS_ORDER_MOVE_DOWN);
|
||||
OBS_ORDER_MOVE_DOWN);
|
||||
}
|
||||
|
||||
void OBSBasicFilters::on_effectFilters_GotFocus()
|
||||
|
@ -704,11 +701,11 @@ void OBSBasicFilters::CustomContextMenu(const QPoint &pos, bool async)
|
|||
popup.addMenu(addMenu);
|
||||
|
||||
if (item) {
|
||||
const char *renameSlot = async ?
|
||||
SLOT(RenameAsyncFilter()) : SLOT(RenameEffectFilter());
|
||||
const char *removeSlot = async ?
|
||||
SLOT(on_removeAsyncFilter_clicked()) :
|
||||
SLOT(on_removeEffectFilter_clicked());
|
||||
const char *renameSlot = async ? SLOT(RenameAsyncFilter())
|
||||
: SLOT(RenameEffectFilter());
|
||||
const char *removeSlot =
|
||||
async ? SLOT(on_removeAsyncFilter_clicked())
|
||||
: SLOT(on_removeEffectFilter_clicked());
|
||||
|
||||
popup.addSeparator();
|
||||
popup.addAction(QTStr("Rename"), this, renameSlot);
|
||||
|
@ -721,9 +718,9 @@ void OBSBasicFilters::CustomContextMenu(const QPoint &pos, bool async)
|
|||
void OBSBasicFilters::EditItem(QListWidgetItem *item, bool async)
|
||||
{
|
||||
Qt::ItemFlags flags = item->flags();
|
||||
OBSSource filter = item->data(Qt::UserRole).value<OBSSource>();
|
||||
const char *name = obs_source_get_name(filter);
|
||||
QListWidget *list = async ? ui->asyncFilters : ui->effectFilters;
|
||||
OBSSource filter = item->data(Qt::UserRole).value<OBSSource>();
|
||||
const char *name = obs_source_get_name(filter);
|
||||
QListWidget *list = async ? ui->asyncFilters : ui->effectFilters;
|
||||
|
||||
item->setText(QT_UTF8(name));
|
||||
item->setFlags(flags | Qt::ItemIsEditable);
|
||||
|
@ -733,13 +730,13 @@ void OBSBasicFilters::EditItem(QListWidgetItem *item, bool async)
|
|||
}
|
||||
|
||||
void OBSBasicFilters::on_asyncFilters_customContextMenuRequested(
|
||||
const QPoint &pos)
|
||||
const QPoint &pos)
|
||||
{
|
||||
CustomContextMenu(pos, true);
|
||||
}
|
||||
|
||||
void OBSBasicFilters::on_effectFilters_customContextMenuRequested(
|
||||
const QPoint &pos)
|
||||
const QPoint &pos)
|
||||
{
|
||||
CustomContextMenu(pos, false);
|
||||
}
|
||||
|
@ -758,7 +755,7 @@ void OBSBasicFilters::FilterNameEdited(QWidget *editor, QListWidget *list)
|
|||
{
|
||||
QListWidgetItem *listItem = list->currentItem();
|
||||
OBSSource filter = listItem->data(Qt::UserRole).value<OBSSource>();
|
||||
QLineEdit *edit = qobject_cast<QLineEdit*>(editor);
|
||||
QLineEdit *edit = qobject_cast<QLineEdit *>(editor);
|
||||
string name = QT_TO_UTF8(edit->text().trimmed());
|
||||
|
||||
const char *prevName = obs_source_get_name(filter);
|
||||
|
@ -766,28 +763,29 @@ void OBSBasicFilters::FilterNameEdited(QWidget *editor, QListWidget *list)
|
|||
obs_source_t *foundFilter = nullptr;
|
||||
|
||||
if (!sameName)
|
||||
foundFilter = obs_source_get_filter_by_name(source,
|
||||
name.c_str());
|
||||
foundFilter =
|
||||
obs_source_get_filter_by_name(source, name.c_str());
|
||||
|
||||
if (foundFilter || name.empty() || sameName) {
|
||||
listItem->setText(QT_UTF8(prevName));
|
||||
|
||||
if (foundFilter) {
|
||||
OBSMessageBox::information(window(),
|
||||
QTStr("NameExists.Title"),
|
||||
QTStr("NameExists.Text"));
|
||||
QTStr("NameExists.Title"),
|
||||
QTStr("NameExists.Text"));
|
||||
obs_source_release(foundFilter);
|
||||
|
||||
} else if (name.empty()) {
|
||||
OBSMessageBox::information(window(),
|
||||
QTStr("NoNameEntered.Title"),
|
||||
QTStr("NoNameEntered.Text"));
|
||||
QTStr("NoNameEntered.Title"),
|
||||
QTStr("NoNameEntered.Text"));
|
||||
}
|
||||
} else {
|
||||
const char *sourceName = obs_source_get_name(source);
|
||||
|
||||
blog(LOG_INFO, "User renamed filter '%s' on source '%s' to '%s'",
|
||||
prevName, sourceName, name.c_str());
|
||||
blog(LOG_INFO,
|
||||
"User renamed filter '%s' on source '%s' to '%s'",
|
||||
prevName, sourceName, name.c_str());
|
||||
|
||||
listItem->setText(QT_UTF8(name.c_str()));
|
||||
obs_source_set_name(filter, name.c_str());
|
||||
|
@ -797,15 +795,15 @@ void OBSBasicFilters::FilterNameEdited(QWidget *editor, QListWidget *list)
|
|||
SetupVisibilityItem(list, listItem, filter);
|
||||
}
|
||||
|
||||
void OBSBasicFilters::AsyncFilterNameEdited(QWidget *editor,
|
||||
QAbstractItemDelegate::EndEditHint endHint)
|
||||
void OBSBasicFilters::AsyncFilterNameEdited(
|
||||
QWidget *editor, QAbstractItemDelegate::EndEditHint endHint)
|
||||
{
|
||||
FilterNameEdited(editor, ui->asyncFilters);
|
||||
UNUSED_PARAMETER(endHint);
|
||||
}
|
||||
|
||||
void OBSBasicFilters::EffectFilterNameEdited(QWidget *editor,
|
||||
QAbstractItemDelegate::EndEditHint endHint)
|
||||
void OBSBasicFilters::EffectFilterNameEdited(
|
||||
QWidget *editor, QAbstractItemDelegate::EndEditHint endHint)
|
||||
{
|
||||
FilterNameEdited(editor, ui->effectFilters);
|
||||
UNUSED_PARAMETER(endHint);
|
||||
|
|
|
@ -105,9 +105,9 @@ private slots:
|
|||
void on_actionMoveDown_triggered();
|
||||
|
||||
void AsyncFilterNameEdited(QWidget *editor,
|
||||
QAbstractItemDelegate::EndEditHint endHint);
|
||||
QAbstractItemDelegate::EndEditHint endHint);
|
||||
void EffectFilterNameEdited(QWidget *editor,
|
||||
QAbstractItemDelegate::EndEditHint endHint);
|
||||
QAbstractItemDelegate::EndEditHint endHint);
|
||||
|
||||
public:
|
||||
OBSBasicFilters(QWidget *parent, OBSSource source_);
|
||||
|
|
|
@ -29,20 +29,20 @@
|
|||
using namespace std;
|
||||
|
||||
OBSBasicInteraction::OBSBasicInteraction(QWidget *parent, OBSSource source_)
|
||||
: QDialog (parent),
|
||||
main (qobject_cast<OBSBasic*>(parent)),
|
||||
ui (new Ui::OBSBasicInteraction),
|
||||
source (source_),
|
||||
removedSignal (obs_source_get_signal_handler(source), "remove",
|
||||
OBSBasicInteraction::SourceRemoved, this),
|
||||
renamedSignal (obs_source_get_signal_handler(source), "rename",
|
||||
OBSBasicInteraction::SourceRenamed, this),
|
||||
eventFilter (BuildEventFilter())
|
||||
: QDialog(parent),
|
||||
main(qobject_cast<OBSBasic *>(parent)),
|
||||
ui(new Ui::OBSBasicInteraction),
|
||||
source(source_),
|
||||
removedSignal(obs_source_get_signal_handler(source), "remove",
|
||||
OBSBasicInteraction::SourceRemoved, this),
|
||||
renamedSignal(obs_source_get_signal_handler(source), "rename",
|
||||
OBSBasicInteraction::SourceRenamed, this),
|
||||
eventFilter(BuildEventFilter())
|
||||
{
|
||||
int cx = (int)config_get_int(App()->GlobalConfig(), "InteractionWindow",
|
||||
"cx");
|
||||
"cx");
|
||||
int cy = (int)config_get_int(App()->GlobalConfig(), "InteractionWindow",
|
||||
"cy");
|
||||
"cy");
|
||||
|
||||
ui->setupUi(this);
|
||||
|
||||
|
@ -59,10 +59,10 @@ OBSBasicInteraction::OBSBasicInteraction(QWidget *parent, OBSSource source_)
|
|||
const char *name = obs_source_get_name(source);
|
||||
setWindowTitle(QTStr("Basic.InteractionWindow").arg(QT_UTF8(name)));
|
||||
|
||||
auto addDrawCallback = [this] ()
|
||||
{
|
||||
auto addDrawCallback = [this]() {
|
||||
obs_display_add_draw_callback(ui->preview->GetDisplay(),
|
||||
OBSBasicInteraction::DrawPreview, this);
|
||||
OBSBasicInteraction::DrawPreview,
|
||||
this);
|
||||
};
|
||||
|
||||
connect(ui->preview, &OBSQTDisplay::DisplayCreated, addDrawCallback);
|
||||
|
@ -77,34 +77,32 @@ OBSBasicInteraction::~OBSBasicInteraction()
|
|||
|
||||
OBSEventFilter *OBSBasicInteraction::BuildEventFilter()
|
||||
{
|
||||
return new OBSEventFilter(
|
||||
[this](QObject *obj, QEvent *event)
|
||||
{
|
||||
return new OBSEventFilter([this](QObject *obj, QEvent *event) {
|
||||
UNUSED_PARAMETER(obj);
|
||||
|
||||
switch(event->type()) {
|
||||
switch (event->type()) {
|
||||
case QEvent::MouseButtonPress:
|
||||
case QEvent::MouseButtonRelease:
|
||||
case QEvent::MouseButtonDblClick:
|
||||
return this->HandleMouseClickEvent(
|
||||
static_cast<QMouseEvent *>(event));
|
||||
static_cast<QMouseEvent *>(event));
|
||||
case QEvent::MouseMove:
|
||||
case QEvent::Enter:
|
||||
case QEvent::Leave:
|
||||
return this->HandleMouseMoveEvent(
|
||||
static_cast<QMouseEvent *>(event));
|
||||
static_cast<QMouseEvent *>(event));
|
||||
|
||||
case QEvent::Wheel:
|
||||
return this->HandleMouseWheelEvent(
|
||||
static_cast<QWheelEvent *>(event));
|
||||
static_cast<QWheelEvent *>(event));
|
||||
case QEvent::FocusIn:
|
||||
case QEvent::FocusOut:
|
||||
return this->HandleFocusEvent(
|
||||
static_cast<QFocusEvent *>(event));
|
||||
static_cast<QFocusEvent *>(event));
|
||||
case QEvent::KeyPress:
|
||||
case QEvent::KeyRelease:
|
||||
return this->HandleKeyEvent(
|
||||
static_cast<QKeyEvent *>(event));
|
||||
static_cast<QKeyEvent *>(event));
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -113,8 +111,8 @@ OBSEventFilter *OBSBasicInteraction::BuildEventFilter()
|
|||
|
||||
void OBSBasicInteraction::SourceRemoved(void *data, calldata_t *params)
|
||||
{
|
||||
QMetaObject::invokeMethod(static_cast<OBSBasicInteraction*>(data),
|
||||
"close");
|
||||
QMetaObject::invokeMethod(static_cast<OBSBasicInteraction *>(data),
|
||||
"close");
|
||||
|
||||
UNUSED_PARAMETER(params);
|
||||
}
|
||||
|
@ -124,13 +122,13 @@ void OBSBasicInteraction::SourceRenamed(void *data, calldata_t *params)
|
|||
const char *name = calldata_string(params, "new_name");
|
||||
QString title = QTStr("Basic.InteractionWindow").arg(QT_UTF8(name));
|
||||
|
||||
QMetaObject::invokeMethod(static_cast<OBSBasicProperties*>(data),
|
||||
"setWindowTitle", Q_ARG(QString, title));
|
||||
QMetaObject::invokeMethod(static_cast<OBSBasicProperties *>(data),
|
||||
"setWindowTitle", Q_ARG(QString, title));
|
||||
}
|
||||
|
||||
void OBSBasicInteraction::DrawPreview(void *data, uint32_t cx, uint32_t cy)
|
||||
{
|
||||
OBSBasicInteraction *window = static_cast<OBSBasicInteraction*>(data);
|
||||
OBSBasicInteraction *window = static_cast<OBSBasicInteraction *>(data);
|
||||
|
||||
if (!window->source)
|
||||
return;
|
||||
|
@ -138,8 +136,8 @@ void OBSBasicInteraction::DrawPreview(void *data, uint32_t cx, uint32_t cy)
|
|||
uint32_t sourceCX = max(obs_source_get_width(window->source), 1u);
|
||||
uint32_t sourceCY = max(obs_source_get_height(window->source), 1u);
|
||||
|
||||
int x, y;
|
||||
int newCX, newCY;
|
||||
int x, y;
|
||||
int newCX, newCY;
|
||||
float scale;
|
||||
|
||||
GetScaleAndCenterPos(sourceCX, sourceCY, cx, cy, x, y, scale);
|
||||
|
@ -149,8 +147,7 @@ void OBSBasicInteraction::DrawPreview(void *data, uint32_t cx, uint32_t cy)
|
|||
|
||||
gs_viewport_push();
|
||||
gs_projection_push();
|
||||
gs_ortho(0.0f, float(sourceCX), 0.0f, float(sourceCY),
|
||||
-100.0f, 100.0f);
|
||||
gs_ortho(0.0f, float(sourceCX), 0.0f, float(sourceCY), -100.0f, 100.0f);
|
||||
gs_set_viewport(x, y, newCX, newCY);
|
||||
obs_source_video_render(window->source);
|
||||
|
||||
|
@ -165,15 +162,18 @@ void OBSBasicInteraction::closeEvent(QCloseEvent *event)
|
|||
return;
|
||||
|
||||
config_set_int(App()->GlobalConfig(), "InteractionWindow", "cx",
|
||||
width());
|
||||
width());
|
||||
config_set_int(App()->GlobalConfig(), "InteractionWindow", "cy",
|
||||
height());
|
||||
height());
|
||||
|
||||
obs_display_remove_draw_callback(ui->preview->GetDisplay(),
|
||||
OBSBasicInteraction::DrawPreview, this);
|
||||
OBSBasicInteraction::DrawPreview,
|
||||
this);
|
||||
}
|
||||
|
||||
static int TranslateQtKeyboardEventModifiers(QInputEvent *event, bool mouseEvent) {
|
||||
static int TranslateQtKeyboardEventModifiers(QInputEvent *event,
|
||||
bool mouseEvent)
|
||||
{
|
||||
int obsModifiers = INTERACT_NONE;
|
||||
|
||||
if (event->modifiers().testFlag(Qt::ShiftModifier))
|
||||
|
@ -200,8 +200,7 @@ static int TranslateQtKeyboardEventModifiers(QInputEvent *event, bool mouseEvent
|
|||
return obsModifiers;
|
||||
}
|
||||
|
||||
static int TranslateQtMouseEventModifiers(
|
||||
QMouseEvent *event)
|
||||
static int TranslateQtMouseEventModifiers(QMouseEvent *event)
|
||||
{
|
||||
int modifiers = TranslateQtKeyboardEventModifiers(event, true);
|
||||
|
||||
|
@ -215,19 +214,19 @@ static int TranslateQtMouseEventModifiers(
|
|||
return modifiers;
|
||||
}
|
||||
|
||||
bool OBSBasicInteraction::GetSourceRelativeXY(
|
||||
int mouseX, int mouseY, int &relX, int &relY)
|
||||
bool OBSBasicInteraction::GetSourceRelativeXY(int mouseX, int mouseY, int &relX,
|
||||
int &relY)
|
||||
{
|
||||
QSize size = GetPixelSize(ui->preview);
|
||||
|
||||
uint32_t sourceCX = max(obs_source_get_width(source), 1u);
|
||||
uint32_t sourceCY = max(obs_source_get_height(source), 1u);
|
||||
|
||||
int x, y;
|
||||
int x, y;
|
||||
float scale;
|
||||
|
||||
GetScaleAndCenterPos(sourceCX, sourceCY, size.width(), size.height(),
|
||||
x, y, scale);
|
||||
GetScaleAndCenterPos(sourceCX, sourceCY, size.width(), size.height(), x,
|
||||
y, scale);
|
||||
|
||||
if (x > 0) {
|
||||
relX = int(float(mouseX - x) / scale);
|
||||
|
@ -246,8 +245,7 @@ bool OBSBasicInteraction::GetSourceRelativeXY(
|
|||
return true;
|
||||
}
|
||||
|
||||
bool OBSBasicInteraction::HandleMouseClickEvent(
|
||||
QMouseEvent *event)
|
||||
bool OBSBasicInteraction::HandleMouseClickEvent(QMouseEvent *event)
|
||||
{
|
||||
bool mouseUp = event->type() == QEvent::MouseButtonRelease;
|
||||
int clickCount = 1;
|
||||
|
@ -271,8 +269,7 @@ bool OBSBasicInteraction::HandleMouseClickEvent(
|
|||
button = MOUSE_RIGHT;
|
||||
break;
|
||||
default:
|
||||
blog(LOG_WARNING, "unknown button type %d",
|
||||
event->button());
|
||||
blog(LOG_WARNING, "unknown button type %d", event->button());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -281,11 +278,11 @@ bool OBSBasicInteraction::HandleMouseClickEvent(
|
|||
// clickCount = 2;
|
||||
|
||||
bool insideSource = GetSourceRelativeXY(event->x(), event->y(),
|
||||
mouseEvent.x, mouseEvent.y);
|
||||
mouseEvent.x, mouseEvent.y);
|
||||
|
||||
if (mouseUp || insideSource)
|
||||
obs_source_send_mouse_click(source, &mouseEvent, button,
|
||||
mouseUp, clickCount);
|
||||
mouseUp, clickCount);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -299,7 +296,7 @@ bool OBSBasicInteraction::HandleMouseMoveEvent(QMouseEvent *event)
|
|||
if (!mouseLeave) {
|
||||
mouseEvent.modifiers = TranslateQtMouseEventModifiers(event);
|
||||
mouseLeave = !GetSourceRelativeXY(event->x(), event->y(),
|
||||
mouseEvent.x, mouseEvent.y);
|
||||
mouseEvent.x, mouseEvent.y);
|
||||
}
|
||||
|
||||
obs_source_send_mouse_move(source, &mouseEvent, mouseLeave);
|
||||
|
@ -329,9 +326,9 @@ bool OBSBasicInteraction::HandleMouseWheelEvent(QWheelEvent *event)
|
|||
}
|
||||
|
||||
if (GetSourceRelativeXY(event->x(), event->y(), mouseEvent.x,
|
||||
mouseEvent.y))
|
||||
mouseEvent.y))
|
||||
obs_source_send_mouse_wheel(source, &mouseEvent, xDelta,
|
||||
yDelta);
|
||||
yDelta);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -35,12 +35,12 @@ class OBSBasicInteraction : public QDialog {
|
|||
Q_OBJECT
|
||||
|
||||
private:
|
||||
OBSBasic *main;
|
||||
OBSBasic *main;
|
||||
|
||||
std::unique_ptr<Ui::OBSBasicInteraction> ui;
|
||||
OBSSource source;
|
||||
OBSSignal removedSignal;
|
||||
OBSSignal renamedSignal;
|
||||
OBSSource source;
|
||||
OBSSignal removedSignal;
|
||||
OBSSignal renamedSignal;
|
||||
std::unique_ptr<OBSEventFilter> eventFilter;
|
||||
|
||||
static void SourceRemoved(void *data, calldata_t *params);
|
||||
|
@ -69,13 +69,10 @@ protected:
|
|||
|
||||
typedef std::function<bool(QObject *, QEvent *)> EventFilterFunc;
|
||||
|
||||
class OBSEventFilter : public QObject
|
||||
{
|
||||
class OBSEventFilter : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
OBSEventFilter(EventFilterFunc filter_)
|
||||
: filter(filter_)
|
||||
{}
|
||||
OBSEventFilter(EventFilterFunc filter_) : filter(filter_) {}
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *obj, QEvent *event)
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
struct QCef;
|
||||
struct QCefCookieManager;
|
||||
|
||||
extern QCef *cef;
|
||||
extern QCef *cef;
|
||||
extern QCefCookieManager *panel_cookies;
|
||||
|
||||
static std::string GenId()
|
||||
|
@ -52,7 +52,8 @@ void CheckExistingCookieId()
|
|||
if (config_has_user_value(main->Config(), "Panels", "CookieId"))
|
||||
return;
|
||||
|
||||
config_set_string(main->Config(), "Panels", "CookieId", GenId().c_str());
|
||||
config_set_string(main->Config(), "Panels", "CookieId",
|
||||
GenId().c_str());
|
||||
}
|
||||
|
||||
#ifdef BROWSER_AVAILABLE
|
||||
|
@ -66,8 +67,8 @@ static void InitPanelCookieManager()
|
|||
CheckExistingCookieId();
|
||||
|
||||
OBSBasic *main = OBSBasic::Get();
|
||||
const char *cookie_id = config_get_string(main->Config(),
|
||||
"Panels", "CookieId");
|
||||
const char *cookie_id =
|
||||
config_get_string(main->Config(), "Panels", "CookieId");
|
||||
|
||||
std::string sub_path;
|
||||
sub_path += "obs_profile_cookies/";
|
||||
|
@ -102,8 +103,8 @@ void DuplicateCurrentCookieProfile(ConfigFile &config)
|
|||
#ifdef BROWSER_AVAILABLE
|
||||
if (cef) {
|
||||
OBSBasic *main = OBSBasic::Get();
|
||||
std::string cookie_id = config_get_string(main->Config(),
|
||||
"Panels", "CookieId");
|
||||
std::string cookie_id =
|
||||
config_get_string(main->Config(), "Panels", "CookieId");
|
||||
|
||||
std::string src_path;
|
||||
src_path += "obs_profile_cookies/";
|
||||
|
@ -136,9 +137,9 @@ void DuplicateCurrentCookieProfile(ConfigFile &config)
|
|||
}
|
||||
|
||||
config_set_string(config, "Panels", "CookieId",
|
||||
cookie_id.c_str());
|
||||
cookie_id.c_str());
|
||||
config_set_string(main->Config(), "Panels", "CookieId",
|
||||
new_id.c_str());
|
||||
new_id.c_str());
|
||||
}
|
||||
#else
|
||||
UNUSED_PARAMETER(config);
|
||||
|
@ -155,10 +156,9 @@ void OBSBasic::InitBrowserPanelSafeBlock()
|
|||
return;
|
||||
}
|
||||
|
||||
ExecThreadedWithoutBlocking(
|
||||
[] {cef->wait_for_browser_init();},
|
||||
QTStr("BrowserPanelInit.Title"),
|
||||
QTStr("BrowserPanelInit.Text"));
|
||||
ExecThreadedWithoutBlocking([] { cef->wait_for_browser_init(); },
|
||||
QTStr("BrowserPanelInit.Title"),
|
||||
QTStr("BrowserPanelInit.Text"));
|
||||
InitPanelCookieManager();
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -11,34 +11,29 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
static const char *textExtensions[] = {
|
||||
"txt", "log", nullptr
|
||||
};
|
||||
static const char *textExtensions[] = {"txt", "log", nullptr};
|
||||
|
||||
static const char *imageExtensions[] = {
|
||||
"bmp", "tga", "png", "jpg", "jpeg", "gif", nullptr
|
||||
};
|
||||
static const char *imageExtensions[] = {"bmp", "tga", "png", "jpg",
|
||||
"jpeg", "gif", nullptr};
|
||||
|
||||
static const char *htmlExtensions[] = {
|
||||
"htm", "html", nullptr
|
||||
};
|
||||
static const char *htmlExtensions[] = {"htm", "html", nullptr};
|
||||
|
||||
static const char *mediaExtensions[] = {
|
||||
"3ga", "669", "a52", "aac", "ac3", "adt", "adts", "aif", "aifc",
|
||||
"aiff", "amb", "amr", "aob", "ape", "au", "awb", "caf", "dts",
|
||||
"flac", "it", "kar", "m4a", "m4b", "m4p", "m5p", "mid", "mka",
|
||||
"mlp", "mod", "mpa", "mp1", "mp2", "mp3", "mpc", "mpga", "mus",
|
||||
"oga", "ogg", "oma", "opus", "qcp", "ra", "rmi", "s3m", "sid",
|
||||
"spx", "tak", "thd", "tta", "voc", "vqf", "w64", "wav", "wma",
|
||||
"wv", "xa", "xm", "3g2", "3gp", "3gp2", "3gpp", "amv", "asf", "avi",
|
||||
"bik", "crf", "divx", "drc", "dv", "evo", "f4v", "flv", "gvi",
|
||||
"gxf", "iso", "m1v", "m2v", "m2t", "m2ts", "m4v", "mkv", "mov",
|
||||
"mp2", "mp2v", "mp4", "mp4v", "mpe", "mpeg", "mpeg1", "mpeg2",
|
||||
"mpeg4", "mpg", "mpv2", "mts", "mtv", "mxf", "mxg", "nsv", "nuv",
|
||||
"ogg", "ogm", "ogv", "ogx", "ps", "rec", "rm", "rmvb", "rpl", "thp",
|
||||
"tod", "ts", "tts", "txd", "vob", "vro", "webm", "wm", "wmv", "wtv",
|
||||
nullptr
|
||||
};
|
||||
"3ga", "669", "a52", "aac", "ac3", "adt", "adts", "aif",
|
||||
"aifc", "aiff", "amb", "amr", "aob", "ape", "au", "awb",
|
||||
"caf", "dts", "flac", "it", "kar", "m4a", "m4b", "m4p",
|
||||
"m5p", "mid", "mka", "mlp", "mod", "mpa", "mp1", "mp2",
|
||||
"mp3", "mpc", "mpga", "mus", "oga", "ogg", "oma", "opus",
|
||||
"qcp", "ra", "rmi", "s3m", "sid", "spx", "tak", "thd",
|
||||
"tta", "voc", "vqf", "w64", "wav", "wma", "wv", "xa",
|
||||
"xm", "3g2", "3gp", "3gp2", "3gpp", "amv", "asf", "avi",
|
||||
"bik", "crf", "divx", "drc", "dv", "evo", "f4v", "flv",
|
||||
"gvi", "gxf", "iso", "m1v", "m2v", "m2t", "m2ts", "m4v",
|
||||
"mkv", "mov", "mp2", "mp2v", "mp4", "mp4v", "mpe", "mpeg",
|
||||
"mpeg1", "mpeg2", "mpeg4", "mpg", "mpv2", "mts", "mtv", "mxf",
|
||||
"mxg", "nsv", "nuv", "ogg", "ogm", "ogv", "ogx", "ps",
|
||||
"rec", "rm", "rmvb", "rpl", "thp", "tod", "ts", "tts",
|
||||
"txd", "vob", "vro", "webm", "wm", "wmv", "wtv", nullptr};
|
||||
|
||||
static string GenerateSourceName(const char *base)
|
||||
{
|
||||
|
@ -50,7 +45,7 @@ static string GenerateSourceName(const char *base)
|
|||
|
||||
if (inc) {
|
||||
name += " (";
|
||||
name += to_string(inc+1);
|
||||
name += to_string(inc + 1);
|
||||
name += ")";
|
||||
}
|
||||
|
||||
|
@ -62,7 +57,7 @@ static string GenerateSourceName(const char *base)
|
|||
|
||||
void OBSBasic::AddDropSource(const char *data, DropType image)
|
||||
{
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
|
||||
obs_data_t *settings = obs_data_create();
|
||||
obs_source_t *source = nullptr;
|
||||
const char *type = nullptr;
|
||||
|
@ -115,8 +110,8 @@ void OBSBasic::AddDropSource(const char *data, DropType image)
|
|||
if (name.isEmpty())
|
||||
name = obs_source_get_display_name(type);
|
||||
source = obs_source_create(type,
|
||||
GenerateSourceName(QT_TO_UTF8(name)).c_str(),
|
||||
settings, nullptr);
|
||||
GenerateSourceName(QT_TO_UTF8(name)).c_str(),
|
||||
settings, nullptr);
|
||||
if (source) {
|
||||
OBSScene scene = main->GetCurrentScene();
|
||||
obs_scene_add(scene, source);
|
||||
|
@ -143,7 +138,7 @@ void OBSBasic::dragMoveEvent(QDragMoveEvent *event)
|
|||
|
||||
void OBSBasic::dropEvent(QDropEvent *event)
|
||||
{
|
||||
const QMimeData* mimeData = event->mimeData();
|
||||
const QMimeData *mimeData = event->mimeData();
|
||||
|
||||
if (mimeData->hasUrls()) {
|
||||
QList<QUrl> urls = mimeData->urls();
|
||||
|
@ -162,20 +157,20 @@ void OBSBasic::dropEvent(QDropEvent *event)
|
|||
|
||||
const char **cmp;
|
||||
|
||||
#define CHECK_SUFFIX(extensions, type) \
|
||||
cmp = extensions; \
|
||||
while (*cmp) { \
|
||||
if (strcmp(*cmp, suffix) == 0) { \
|
||||
AddDropSource(QT_TO_UTF8(file), type); \
|
||||
found = true; \
|
||||
break; \
|
||||
} \
|
||||
\
|
||||
cmp++; \
|
||||
} \
|
||||
\
|
||||
if (found) \
|
||||
continue;
|
||||
#define CHECK_SUFFIX(extensions, type) \
|
||||
cmp = extensions; \
|
||||
while (*cmp) { \
|
||||
if (strcmp(*cmp, suffix) == 0) { \
|
||||
AddDropSource(QT_TO_UTF8(file), type); \
|
||||
found = true; \
|
||||
break; \
|
||||
} \
|
||||
\
|
||||
cmp++; \
|
||||
} \
|
||||
\
|
||||
if (found) \
|
||||
continue;
|
||||
|
||||
CHECK_SUFFIX(textExtensions, DropType_Text);
|
||||
CHECK_SUFFIX(htmlExtensions, DropType_Html);
|
||||
|
@ -188,4 +183,3 @@ if (found) \
|
|||
AddDropSource(QT_TO_UTF8(mimeData->text()), DropType_RawText);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -5,49 +5,49 @@
|
|||
class OBSBasic;
|
||||
|
||||
struct BasicOutputHandler {
|
||||
OBSOutput fileOutput;
|
||||
OBSOutput streamOutput;
|
||||
OBSOutput replayBuffer;
|
||||
bool streamingActive = false;
|
||||
bool recordingActive = false;
|
||||
bool delayActive = false;
|
||||
bool replayBufferActive = false;
|
||||
OBSBasic *main;
|
||||
OBSOutput fileOutput;
|
||||
OBSOutput streamOutput;
|
||||
OBSOutput replayBuffer;
|
||||
bool streamingActive = false;
|
||||
bool recordingActive = false;
|
||||
bool delayActive = false;
|
||||
bool replayBufferActive = false;
|
||||
OBSBasic *main;
|
||||
|
||||
std::string outputType;
|
||||
std::string lastError;
|
||||
std::string outputType;
|
||||
std::string lastError;
|
||||
|
||||
OBSSignal startRecording;
|
||||
OBSSignal stopRecording;
|
||||
OBSSignal startReplayBuffer;
|
||||
OBSSignal stopReplayBuffer;
|
||||
OBSSignal startStreaming;
|
||||
OBSSignal stopStreaming;
|
||||
OBSSignal streamDelayStarting;
|
||||
OBSSignal streamStopping;
|
||||
OBSSignal recordStopping;
|
||||
OBSSignal replayBufferStopping;
|
||||
OBSSignal startRecording;
|
||||
OBSSignal stopRecording;
|
||||
OBSSignal startReplayBuffer;
|
||||
OBSSignal stopReplayBuffer;
|
||||
OBSSignal startStreaming;
|
||||
OBSSignal stopStreaming;
|
||||
OBSSignal streamDelayStarting;
|
||||
OBSSignal streamStopping;
|
||||
OBSSignal recordStopping;
|
||||
OBSSignal replayBufferStopping;
|
||||
|
||||
inline BasicOutputHandler(OBSBasic *main_) : main(main_) {}
|
||||
|
||||
virtual ~BasicOutputHandler() {};
|
||||
virtual ~BasicOutputHandler(){};
|
||||
|
||||
virtual bool StartStreaming(obs_service_t *service) = 0;
|
||||
virtual bool StartRecording() = 0;
|
||||
virtual bool StartReplayBuffer() {return false;}
|
||||
virtual bool StartReplayBuffer() { return false; }
|
||||
virtual void StopStreaming(bool force = false) = 0;
|
||||
virtual void StopRecording(bool force = false) = 0;
|
||||
virtual void StopReplayBuffer(bool force = false) {(void)force;}
|
||||
virtual void StopReplayBuffer(bool force = false) { (void)force; }
|
||||
virtual bool StreamingActive() const = 0;
|
||||
virtual bool RecordingActive() const = 0;
|
||||
virtual bool ReplayBufferActive() const {return false;}
|
||||
virtual bool ReplayBufferActive() const { return false; }
|
||||
|
||||
virtual void Update() = 0;
|
||||
|
||||
inline bool Active() const
|
||||
{
|
||||
return streamingActive || recordingActive || delayActive ||
|
||||
replayBufferActive;
|
||||
replayBufferActive;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -30,13 +30,13 @@ extern void DuplicateCurrentCookieProfile(ConfigFile &config);
|
|||
extern void CheckExistingCookieId();
|
||||
extern void DeleteCookies();
|
||||
|
||||
void EnumProfiles(std::function<bool (const char *, const char *)> &&cb)
|
||||
void EnumProfiles(std::function<bool(const char *, const char *)> &&cb)
|
||||
{
|
||||
char path[512];
|
||||
os_glob_t *glob;
|
||||
|
||||
int ret = GetConfigPath(path, sizeof(path),
|
||||
"obs-studio/basic/profiles/*");
|
||||
"obs-studio/basic/profiles/*");
|
||||
if (ret <= 0) {
|
||||
blog(LOG_WARNING, "Failed to get profiles config path");
|
||||
return;
|
||||
|
@ -54,8 +54,7 @@ void EnumProfiles(std::function<bool (const char *, const char *)> &&cb)
|
|||
if (!glob->gl_pathv[i].directory)
|
||||
continue;
|
||||
|
||||
if (strcmp(dirName, ".") == 0 ||
|
||||
strcmp(dirName, "..") == 0)
|
||||
if (strcmp(dirName, ".") == 0 || strcmp(dirName, "..") == 0)
|
||||
continue;
|
||||
|
||||
std::string file = filePath;
|
||||
|
@ -80,8 +79,7 @@ void EnumProfiles(std::function<bool (const char *, const char *)> &&cb)
|
|||
static bool ProfileExists(const char *findName)
|
||||
{
|
||||
bool found = false;
|
||||
auto func = [&](const char *name, const char*)
|
||||
{
|
||||
auto func = [&](const char *name, const char *) {
|
||||
if (strcmp(name, findName) == 0) {
|
||||
found = true;
|
||||
return false;
|
||||
|
@ -94,28 +92,28 @@ static bool ProfileExists(const char *findName)
|
|||
}
|
||||
|
||||
static bool GetProfileName(QWidget *parent, std::string &name,
|
||||
std::string &file, const char *title, const char *text,
|
||||
const char *oldName = nullptr)
|
||||
std::string &file, const char *title,
|
||||
const char *text, const char *oldName = nullptr)
|
||||
{
|
||||
char path[512];
|
||||
int ret;
|
||||
|
||||
for (;;) {
|
||||
bool success = NameDialog::AskForName(parent, title, text,
|
||||
name, QT_UTF8(oldName));
|
||||
bool success = NameDialog::AskForName(parent, title, text, name,
|
||||
QT_UTF8(oldName));
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
if (name.empty()) {
|
||||
OBSMessageBox::warning(parent,
|
||||
QTStr("NoNameEntered.Title"),
|
||||
QTStr("NoNameEntered.Text"));
|
||||
QTStr("NoNameEntered.Title"),
|
||||
QTStr("NoNameEntered.Text"));
|
||||
continue;
|
||||
}
|
||||
if (ProfileExists(name.c_str())) {
|
||||
OBSMessageBox::warning(parent,
|
||||
QTStr("NameExists.Title"),
|
||||
QTStr("NameExists.Text"));
|
||||
QTStr("NameExists.Title"),
|
||||
QTStr("NameExists.Text"));
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
@ -123,7 +121,7 @@ static bool GetProfileName(QWidget *parent, std::string &name,
|
|||
|
||||
if (!GetFileSafeName(name.c_str(), file)) {
|
||||
blog(LOG_WARNING, "Failed to create safe file name for '%s'",
|
||||
name.c_str());
|
||||
name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -137,7 +135,7 @@ static bool GetProfileName(QWidget *parent, std::string &name,
|
|||
|
||||
if (!GetClosestUnusedFileName(file, nullptr)) {
|
||||
blog(LOG_WARNING, "Failed to get closest file name for %s",
|
||||
file.c_str());
|
||||
file.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -170,13 +168,14 @@ static bool CopyProfile(const char *fromPartial, const char *to)
|
|||
if (glob->gl_pathv[i].directory)
|
||||
continue;
|
||||
|
||||
ret = snprintf(path, sizeof(path), "%s/%s",
|
||||
to, strrchr(filePath, '/') + 1);
|
||||
ret = snprintf(path, sizeof(path), "%s/%s", to,
|
||||
strrchr(filePath, '/') + 1);
|
||||
if (ret > 0) {
|
||||
if (os_copyfile(filePath, path) != 0) {
|
||||
blog(LOG_WARNING, "CopyProfile: Failed to "
|
||||
"copy file %s to %s",
|
||||
filePath, path);
|
||||
blog(LOG_WARNING,
|
||||
"CopyProfile: Failed to "
|
||||
"copy file %s to %s",
|
||||
filePath, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -187,7 +186,7 @@ static bool CopyProfile(const char *fromPartial, const char *to)
|
|||
}
|
||||
|
||||
bool OBSBasic::AddProfile(bool create_new, const char *title, const char *text,
|
||||
const char *init_text, bool rename)
|
||||
const char *init_text, bool rename)
|
||||
{
|
||||
std::string newName;
|
||||
std::string newDir;
|
||||
|
@ -197,12 +196,12 @@ bool OBSBasic::AddProfile(bool create_new, const char *title, const char *text,
|
|||
if (!GetProfileName(this, newName, newDir, title, text, init_text))
|
||||
return false;
|
||||
|
||||
std::string curDir = config_get_string(App()->GlobalConfig(),
|
||||
"Basic", "ProfileDir");
|
||||
std::string curDir =
|
||||
config_get_string(App()->GlobalConfig(), "Basic", "ProfileDir");
|
||||
|
||||
char baseDir[512];
|
||||
int ret = GetConfigPath(baseDir, sizeof(baseDir),
|
||||
"obs-studio/basic/profiles/");
|
||||
"obs-studio/basic/profiles/");
|
||||
if (ret <= 0) {
|
||||
blog(LOG_WARNING, "Failed to get profiles config path");
|
||||
return false;
|
||||
|
@ -213,7 +212,7 @@ bool OBSBasic::AddProfile(bool create_new, const char *title, const char *text,
|
|||
|
||||
if (os_mkdir(newPath.c_str()) < 0) {
|
||||
blog(LOG_WARNING, "Failed to create profile directory '%s'",
|
||||
newDir.c_str());
|
||||
newDir.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -224,14 +223,14 @@ bool OBSBasic::AddProfile(bool create_new, const char *title, const char *text,
|
|||
|
||||
if (config.Open(newPath.c_str(), CONFIG_OPEN_ALWAYS) != 0) {
|
||||
blog(LOG_ERROR, "Failed to open new config file '%s'",
|
||||
newDir.c_str());
|
||||
newDir.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
config_set_string(App()->GlobalConfig(), "Basic", "Profile",
|
||||
newName.c_str());
|
||||
newName.c_str());
|
||||
config_set_string(App()->GlobalConfig(), "Basic", "ProfileDir",
|
||||
newDir.c_str());
|
||||
newDir.c_str());
|
||||
|
||||
Auth::Save();
|
||||
if (create_new) {
|
||||
|
@ -253,7 +252,7 @@ bool OBSBasic::AddProfile(bool create_new, const char *title, const char *text,
|
|||
ResetProfileData();
|
||||
|
||||
blog(LOG_INFO, "Created profile '%s' (%s, %s)", newName.c_str(),
|
||||
create_new ? "clean" : "duplicate", newDir.c_str());
|
||||
create_new ? "clean" : "duplicate", newDir.c_str());
|
||||
blog(LOG_INFO, "------------------------------------------------");
|
||||
|
||||
config_save_safe(App()->GlobalConfig(), "tmp", nullptr);
|
||||
|
@ -280,14 +279,14 @@ void OBSBasic::DeleteProfile(const char *profileName, const char *profileDir)
|
|||
ret = snprintf(profilePath, 512, "%s/%s/*", basePath, profileDir);
|
||||
if (ret <= 0) {
|
||||
blog(LOG_WARNING, "Failed to get path for profile dir '%s'",
|
||||
profileDir);
|
||||
profileDir);
|
||||
return;
|
||||
}
|
||||
|
||||
os_glob_t *glob;
|
||||
if (os_glob(profilePath, 0, &glob) != 0) {
|
||||
blog(LOG_WARNING, "Failed to glob profile dir '%s'",
|
||||
profileDir);
|
||||
profileDir);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -305,21 +304,20 @@ void OBSBasic::DeleteProfile(const char *profileName, const char *profileDir)
|
|||
ret = snprintf(profilePath, 512, "%s/%s", basePath, profileDir);
|
||||
if (ret <= 0) {
|
||||
blog(LOG_WARNING, "Failed to get path for profile dir '%s'",
|
||||
profileDir);
|
||||
profileDir);
|
||||
return;
|
||||
}
|
||||
|
||||
os_rmdir(profilePath);
|
||||
|
||||
blog(LOG_INFO, "------------------------------------------------");
|
||||
blog(LOG_INFO, "Removed profile '%s' (%s)",
|
||||
profileName, profileDir);
|
||||
blog(LOG_INFO, "Removed profile '%s' (%s)", profileName, profileDir);
|
||||
blog(LOG_INFO, "------------------------------------------------");
|
||||
}
|
||||
|
||||
void OBSBasic::RefreshProfiles()
|
||||
{
|
||||
QList<QAction*> menuActions = ui->profileMenu->actions();
|
||||
QList<QAction *> menuActions = ui->profileMenu->actions();
|
||||
int count = 0;
|
||||
|
||||
for (int i = 0; i < menuActions.count(); i++) {
|
||||
|
@ -328,17 +326,16 @@ void OBSBasic::RefreshProfiles()
|
|||
delete menuActions[i];
|
||||
}
|
||||
|
||||
const char *curName = config_get_string(App()->GlobalConfig(),
|
||||
"Basic", "Profile");
|
||||
const char *curName =
|
||||
config_get_string(App()->GlobalConfig(), "Basic", "Profile");
|
||||
|
||||
auto addProfile = [&](const char *name, const char *path)
|
||||
{
|
||||
auto addProfile = [&](const char *name, const char *path) {
|
||||
std::string file = strrchr(path, '/') + 1;
|
||||
|
||||
QAction *action = new QAction(QT_UTF8(name), this);
|
||||
action->setProperty("file_name", QT_UTF8(path));
|
||||
connect(action, &QAction::triggered,
|
||||
this, &OBSBasic::ChangeProfile);
|
||||
connect(action, &QAction::triggered, this,
|
||||
&OBSBasic::ChangeProfile);
|
||||
action->setCheckable(true);
|
||||
|
||||
action->setChecked(strcmp(name, curName) == 0);
|
||||
|
@ -364,15 +361,15 @@ void OBSBasic::ResetProfileData()
|
|||
|
||||
/* load audio monitoring */
|
||||
#if defined(_WIN32) || defined(__APPLE__) || HAVE_PULSEAUDIO
|
||||
const char *device_name = config_get_string(basicConfig, "Audio",
|
||||
"MonitoringDeviceName");
|
||||
const char *device_id = config_get_string(basicConfig, "Audio",
|
||||
"MonitoringDeviceId");
|
||||
const char *device_name =
|
||||
config_get_string(basicConfig, "Audio", "MonitoringDeviceName");
|
||||
const char *device_id =
|
||||
config_get_string(basicConfig, "Audio", "MonitoringDeviceId");
|
||||
|
||||
obs_set_audio_monitoring_device(device_name, device_id);
|
||||
|
||||
blog(LOG_INFO, "Audio monitoring device:\n\tname: %s\n\tid: %s",
|
||||
device_name, device_id);
|
||||
device_name, device_id);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -388,14 +385,15 @@ void OBSBasic::on_actionDupProfile_triggered()
|
|||
|
||||
void OBSBasic::on_actionRenameProfile_triggered()
|
||||
{
|
||||
std::string curDir = config_get_string(App()->GlobalConfig(),
|
||||
"Basic", "ProfileDir");
|
||||
std::string curName = config_get_string(App()->GlobalConfig(),
|
||||
"Basic", "Profile");
|
||||
std::string curDir =
|
||||
config_get_string(App()->GlobalConfig(), "Basic", "ProfileDir");
|
||||
std::string curName =
|
||||
config_get_string(App()->GlobalConfig(), "Basic", "Profile");
|
||||
|
||||
/* Duplicate and delete in case there are any issues in the process */
|
||||
bool success = AddProfile(false, Str("RenameProfile.Title"),
|
||||
Str("AddProfile.Text"), curName.c_str(), true);
|
||||
Str("AddProfile.Text"), curName.c_str(),
|
||||
true);
|
||||
if (success) {
|
||||
DeleteProfile(curName.c_str(), curDir.c_str());
|
||||
RefreshProfiles();
|
||||
|
@ -413,13 +411,12 @@ void OBSBasic::on_actionRemoveProfile_triggered()
|
|||
std::string newPath;
|
||||
ConfigFile config;
|
||||
|
||||
std::string oldDir = config_get_string(App()->GlobalConfig(),
|
||||
"Basic", "ProfileDir");
|
||||
std::string oldName = config_get_string(App()->GlobalConfig(),
|
||||
"Basic", "Profile");
|
||||
std::string oldDir =
|
||||
config_get_string(App()->GlobalConfig(), "Basic", "ProfileDir");
|
||||
std::string oldName =
|
||||
config_get_string(App()->GlobalConfig(), "Basic", "Profile");
|
||||
|
||||
auto cb = [&](const char *name, const char *filePath)
|
||||
{
|
||||
auto cb = [&](const char *name, const char *filePath) {
|
||||
if (strcmp(oldName.c_str(), name) != 0) {
|
||||
newName = name;
|
||||
newPath = filePath;
|
||||
|
@ -438,8 +435,8 @@ void OBSBasic::on_actionRemoveProfile_triggered()
|
|||
QString text = QTStr("ConfirmRemove.Text");
|
||||
text.replace("$1", QT_UTF8(oldName.c_str()));
|
||||
|
||||
QMessageBox::StandardButton button = OBSMessageBox::question(this,
|
||||
QTStr("ConfirmRemove.Title"), text);
|
||||
QMessageBox::StandardButton button = OBSMessageBox::question(
|
||||
this, QTStr("ConfirmRemove.Title"), text);
|
||||
if (button == QMessageBox::No)
|
||||
return;
|
||||
|
||||
|
@ -448,7 +445,7 @@ void OBSBasic::on_actionRemoveProfile_triggered()
|
|||
|
||||
if (config.Open(newPath.c_str(), CONFIG_OPEN_ALWAYS) != 0) {
|
||||
blog(LOG_ERROR, "ChangeProfile: Failed to load file '%s'",
|
||||
newPath.c_str());
|
||||
newPath.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -457,9 +454,8 @@ void OBSBasic::on_actionRemoveProfile_triggered()
|
|||
const char *newDir = strrchr(newPath.c_str(), '/') + 1;
|
||||
|
||||
config_set_string(App()->GlobalConfig(), "Basic", "Profile",
|
||||
newName.c_str());
|
||||
config_set_string(App()->GlobalConfig(), "Basic", "ProfileDir",
|
||||
newDir);
|
||||
newName.c_str());
|
||||
config_set_string(App()->GlobalConfig(), "Basic", "ProfileDir", newDir);
|
||||
|
||||
Auth::Save();
|
||||
auth.reset();
|
||||
|
@ -474,8 +470,8 @@ void OBSBasic::on_actionRemoveProfile_triggered()
|
|||
RefreshProfiles();
|
||||
config_save_safe(App()->GlobalConfig(), "tmp", nullptr);
|
||||
|
||||
blog(LOG_INFO, "Switched to profile '%s' (%s)",
|
||||
newName.c_str(), newDir);
|
||||
blog(LOG_INFO, "Switched to profile '%s' (%s)", newName.c_str(),
|
||||
newDir);
|
||||
blog(LOG_INFO, "------------------------------------------------");
|
||||
|
||||
UpdateTitleBar();
|
||||
|
@ -501,11 +497,8 @@ void OBSBasic::on_actionImportProfile_triggered()
|
|||
}
|
||||
|
||||
QString dir = QFileDialog::getExistingDirectory(
|
||||
this,
|
||||
QTStr("Basic.MainMenu.Profile.Import"),
|
||||
home,
|
||||
QFileDialog::ShowDirsOnly |
|
||||
QFileDialog::DontResolveSymlinks);
|
||||
this, QTStr("Basic.MainMenu.Profile.Import"), home,
|
||||
QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
|
||||
|
||||
if (!dir.isEmpty() && !dir.isNull()) {
|
||||
QString inputPath = QString::fromUtf8(path);
|
||||
|
@ -517,18 +510,18 @@ void OBSBasic::on_actionImportProfile_triggered()
|
|||
if (!folder.exists()) {
|
||||
folder.mkpath(profileDir);
|
||||
QFile::copy(dir + "/basic.ini",
|
||||
profileDir + "/basic.ini");
|
||||
profileDir + "/basic.ini");
|
||||
QFile::copy(dir + "/service.json",
|
||||
profileDir + "/service.json");
|
||||
profileDir + "/service.json");
|
||||
QFile::copy(dir + "/streamEncoder.json",
|
||||
profileDir + "/streamEncoder.json");
|
||||
profileDir + "/streamEncoder.json");
|
||||
QFile::copy(dir + "/recordEncoder.json",
|
||||
profileDir + "/recordEncoder.json");
|
||||
profileDir + "/recordEncoder.json");
|
||||
RefreshProfiles();
|
||||
} else {
|
||||
OBSMessageBox::warning(this,
|
||||
QTStr("Basic.MainMenu.Profile.Import"),
|
||||
QTStr("Basic.MainMenu.Profile.Exists"));
|
||||
OBSMessageBox::warning(
|
||||
this, QTStr("Basic.MainMenu.Profile.Import"),
|
||||
QTStr("Basic.MainMenu.Profile.Exists"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -539,9 +532,8 @@ void OBSBasic::on_actionExportProfile_triggered()
|
|||
|
||||
QString home = QDir::homePath();
|
||||
|
||||
QString currentProfile =
|
||||
QString::fromUtf8(config_get_string(App()->GlobalConfig(),
|
||||
"Basic", "ProfileDir"));
|
||||
QString currentProfile = QString::fromUtf8(config_get_string(
|
||||
App()->GlobalConfig(), "Basic", "ProfileDir"));
|
||||
|
||||
int ret = GetConfigPath(path, 512, "obs-studio/basic/profiles/");
|
||||
if (ret <= 0) {
|
||||
|
@ -550,11 +542,8 @@ void OBSBasic::on_actionExportProfile_triggered()
|
|||
}
|
||||
|
||||
QString dir = QFileDialog::getExistingDirectory(
|
||||
this,
|
||||
QTStr("Basic.MainMenu.Profile.Export"),
|
||||
home,
|
||||
QFileDialog::ShowDirsOnly |
|
||||
QFileDialog::DontResolveSymlinks);
|
||||
this, QTStr("Basic.MainMenu.Profile.Export"), home,
|
||||
QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
|
||||
|
||||
if (!dir.isEmpty() && !dir.isNull()) {
|
||||
QString outputDir = dir + "/" + currentProfile;
|
||||
|
@ -571,26 +560,28 @@ void OBSBasic::on_actionExportProfile_triggered()
|
|||
QFile::remove(outputDir + "/service.json");
|
||||
|
||||
if (QFile::exists(outputDir + "/streamEncoder.json"))
|
||||
QFile::remove(outputDir + "/streamEncoder.json");
|
||||
QFile::remove(outputDir +
|
||||
"/streamEncoder.json");
|
||||
|
||||
if (QFile::exists(outputDir + "/recordEncoder.json"))
|
||||
QFile::remove(outputDir + "/recordEncoder.json");
|
||||
QFile::remove(outputDir +
|
||||
"/recordEncoder.json");
|
||||
}
|
||||
|
||||
QFile::copy(inputPath + currentProfile + "/basic.ini",
|
||||
outputDir + "/basic.ini");
|
||||
outputDir + "/basic.ini");
|
||||
QFile::copy(inputPath + currentProfile + "/service.json",
|
||||
outputDir + "/service.json");
|
||||
outputDir + "/service.json");
|
||||
QFile::copy(inputPath + currentProfile + "/streamEncoder.json",
|
||||
outputDir + "/streamEncoder.json");
|
||||
outputDir + "/streamEncoder.json");
|
||||
QFile::copy(inputPath + currentProfile + "/recordEncoder.json",
|
||||
outputDir + "/recordEncoder.json");
|
||||
outputDir + "/recordEncoder.json");
|
||||
}
|
||||
}
|
||||
|
||||
void OBSBasic::ChangeProfile()
|
||||
{
|
||||
QAction *action = reinterpret_cast<QAction*>(sender());
|
||||
QAction *action = reinterpret_cast<QAction *>(sender());
|
||||
ConfigFile config;
|
||||
std::string path;
|
||||
|
||||
|
@ -601,8 +592,8 @@ void OBSBasic::ChangeProfile()
|
|||
if (path.empty())
|
||||
return;
|
||||
|
||||
const char *oldName = config_get_string(App()->GlobalConfig(),
|
||||
"Basic", "Profile");
|
||||
const char *oldName =
|
||||
config_get_string(App()->GlobalConfig(), "Basic", "Profile");
|
||||
if (action->text().compare(QT_UTF8(oldName)) == 0) {
|
||||
action->setChecked(true);
|
||||
return;
|
||||
|
@ -613,7 +604,7 @@ void OBSBasic::ChangeProfile()
|
|||
|
||||
if (config.Open(path.c_str(), CONFIG_OPEN_ALWAYS) != 0) {
|
||||
blog(LOG_ERROR, "ChangeProfile: Failed to load file '%s'",
|
||||
path.c_str());
|
||||
path.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -623,8 +614,7 @@ void OBSBasic::ChangeProfile()
|
|||
const char *newDir = strrchr(path.c_str(), '/') + 1;
|
||||
|
||||
config_set_string(App()->GlobalConfig(), "Basic", "Profile", newName);
|
||||
config_set_string(App()->GlobalConfig(), "Basic", "ProfileDir",
|
||||
newDir);
|
||||
config_set_string(App()->GlobalConfig(), "Basic", "ProfileDir", newDir);
|
||||
|
||||
Auth::Save();
|
||||
auth.reset();
|
||||
|
@ -642,8 +632,7 @@ void OBSBasic::ChangeProfile()
|
|||
|
||||
CheckForSimpleModeX264Fallback();
|
||||
|
||||
blog(LOG_INFO, "Switched to profile '%s' (%s)",
|
||||
newName, newDir);
|
||||
blog(LOG_INFO, "Switched to profile '%s' (%s)", newName, newDir);
|
||||
blog(LOG_INFO, "------------------------------------------------");
|
||||
|
||||
if (api)
|
||||
|
@ -652,10 +641,10 @@ void OBSBasic::ChangeProfile()
|
|||
|
||||
void OBSBasic::CheckForSimpleModeX264Fallback()
|
||||
{
|
||||
const char *curStreamEncoder = config_get_string(basicConfig,
|
||||
"SimpleOutput", "StreamEncoder");
|
||||
const char *curRecEncoder = config_get_string(basicConfig,
|
||||
"SimpleOutput", "RecEncoder");
|
||||
const char *curStreamEncoder =
|
||||
config_get_string(basicConfig, "SimpleOutput", "StreamEncoder");
|
||||
const char *curRecEncoder =
|
||||
config_get_string(basicConfig, "SimpleOutput", "RecEncoder");
|
||||
bool qsv_supported = false;
|
||||
bool amd_supported = false;
|
||||
bool nve_supported = false;
|
||||
|
@ -672,8 +661,7 @@ void OBSBasic::CheckForSimpleModeX264Fallback()
|
|||
nve_supported = true;
|
||||
}
|
||||
|
||||
auto CheckEncoder = [&] (const char *&name)
|
||||
{
|
||||
auto CheckEncoder = [&](const char *&name) {
|
||||
if (strcmp(name, SIMPLE_ENCODER_QSV) == 0) {
|
||||
if (!qsv_supported) {
|
||||
changed = true;
|
||||
|
@ -698,13 +686,11 @@ void OBSBasic::CheckForSimpleModeX264Fallback()
|
|||
};
|
||||
|
||||
if (!CheckEncoder(curStreamEncoder))
|
||||
config_set_string(basicConfig,
|
||||
"SimpleOutput", "StreamEncoder",
|
||||
curStreamEncoder);
|
||||
config_set_string(basicConfig, "SimpleOutput", "StreamEncoder",
|
||||
curStreamEncoder);
|
||||
if (!CheckEncoder(curRecEncoder))
|
||||
config_set_string(basicConfig,
|
||||
"SimpleOutput", "RecEncoder",
|
||||
curRecEncoder);
|
||||
config_set_string(basicConfig, "SimpleOutput", "RecEncoder",
|
||||
curRecEncoder);
|
||||
if (changed)
|
||||
config_save_safe(basicConfig, "tmp", nullptr);
|
||||
}
|
||||
|
|
|
@ -28,16 +28,16 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
void EnumSceneCollections(std::function<bool (const char *, const char *)> &&cb)
|
||||
void EnumSceneCollections(std::function<bool(const char *, const char *)> &&cb)
|
||||
{
|
||||
char path[512];
|
||||
os_glob_t *glob;
|
||||
|
||||
int ret = GetConfigPath(path, sizeof(path),
|
||||
"obs-studio/basic/scenes/*.json");
|
||||
"obs-studio/basic/scenes/*.json");
|
||||
if (ret <= 0) {
|
||||
blog(LOG_WARNING, "Failed to get config path for scene "
|
||||
"collections");
|
||||
"collections");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -52,8 +52,8 @@ void EnumSceneCollections(std::function<bool (const char *, const char *)> &&cb)
|
|||
if (glob->gl_pathv[i].directory)
|
||||
continue;
|
||||
|
||||
obs_data_t *data = obs_data_create_from_json_file_safe(filePath,
|
||||
"bak");
|
||||
obs_data_t *data =
|
||||
obs_data_create_from_json_file_safe(filePath, "bak");
|
||||
std::string name = obs_data_get_string(data, "name");
|
||||
|
||||
/* if no name found, use the file name as the name
|
||||
|
@ -75,8 +75,7 @@ void EnumSceneCollections(std::function<bool (const char *, const char *)> &&cb)
|
|||
static bool SceneCollectionExists(const char *findName)
|
||||
{
|
||||
bool found = false;
|
||||
auto func = [&](const char *name, const char*)
|
||||
{
|
||||
auto func = [&](const char *name, const char *) {
|
||||
if (strcmp(name, findName) == 0) {
|
||||
found = true;
|
||||
return false;
|
||||
|
@ -90,7 +89,8 @@ static bool SceneCollectionExists(const char *findName)
|
|||
}
|
||||
|
||||
static bool GetSceneCollectionName(QWidget *parent, std::string &name,
|
||||
std::string &file, const char *oldName = nullptr)
|
||||
std::string &file,
|
||||
const char *oldName = nullptr)
|
||||
{
|
||||
bool rename = oldName != nullptr;
|
||||
const char *title;
|
||||
|
@ -101,28 +101,28 @@ static bool GetSceneCollectionName(QWidget *parent, std::string &name,
|
|||
|
||||
if (rename) {
|
||||
title = Str("Basic.Main.RenameSceneCollection.Title");
|
||||
text = Str("Basic.Main.AddSceneCollection.Text");
|
||||
text = Str("Basic.Main.AddSceneCollection.Text");
|
||||
} else {
|
||||
title = Str("Basic.Main.AddSceneCollection.Title");
|
||||
text = Str("Basic.Main.AddSceneCollection.Text");
|
||||
text = Str("Basic.Main.AddSceneCollection.Text");
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
bool success = NameDialog::AskForName(parent, title, text,
|
||||
name, QT_UTF8(oldName));
|
||||
bool success = NameDialog::AskForName(parent, title, text, name,
|
||||
QT_UTF8(oldName));
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
if (name.empty()) {
|
||||
OBSMessageBox::warning(parent,
|
||||
QTStr("NoNameEntered.Title"),
|
||||
QTStr("NoNameEntered.Text"));
|
||||
QTStr("NoNameEntered.Title"),
|
||||
QTStr("NoNameEntered.Text"));
|
||||
continue;
|
||||
}
|
||||
if (SceneCollectionExists(name.c_str())) {
|
||||
OBSMessageBox::warning(parent,
|
||||
QTStr("NameExists.Title"),
|
||||
QTStr("NameExists.Text"));
|
||||
QTStr("NameExists.Title"),
|
||||
QTStr("NameExists.Text"));
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
@ -130,7 +130,7 @@ static bool GetSceneCollectionName(QWidget *parent, std::string &name,
|
|||
|
||||
if (!GetFileSafeName(name.c_str(), file)) {
|
||||
blog(LOG_WARNING, "Failed to create safe file name for '%s'",
|
||||
name.c_str());
|
||||
name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -145,7 +145,7 @@ static bool GetSceneCollectionName(QWidget *parent, std::string &name,
|
|||
|
||||
if (!GetClosestUnusedFileName(file, "json")) {
|
||||
blog(LOG_WARNING, "Failed to get closest file name for %s",
|
||||
file.c_str());
|
||||
file.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -171,9 +171,9 @@ bool OBSBasic::AddSceneCollection(bool create_new, const QString &qname)
|
|||
SaveProjectNow();
|
||||
|
||||
config_set_string(App()->GlobalConfig(), "Basic", "SceneCollection",
|
||||
name.c_str());
|
||||
name.c_str());
|
||||
config_set_string(App()->GlobalConfig(), "Basic", "SceneCollectionFile",
|
||||
file.c_str());
|
||||
file.c_str());
|
||||
if (create_new) {
|
||||
CreateDefaultScene(false);
|
||||
}
|
||||
|
@ -181,8 +181,7 @@ bool OBSBasic::AddSceneCollection(bool create_new, const QString &qname)
|
|||
RefreshSceneCollections();
|
||||
|
||||
blog(LOG_INFO, "Added scene collection '%s' (%s, %s.json)",
|
||||
name.c_str(), create_new ? "clean" : "duplicate",
|
||||
file.c_str());
|
||||
name.c_str(), create_new ? "clean" : "duplicate", file.c_str());
|
||||
blog(LOG_INFO, "------------------------------------------------");
|
||||
|
||||
UpdateTitleBar();
|
||||
|
@ -197,7 +196,7 @@ bool OBSBasic::AddSceneCollection(bool create_new, const QString &qname)
|
|||
|
||||
void OBSBasic::RefreshSceneCollections()
|
||||
{
|
||||
QList<QAction*> menuActions = ui->sceneCollectionMenu->actions();
|
||||
QList<QAction *> menuActions = ui->sceneCollectionMenu->actions();
|
||||
int count = 0;
|
||||
|
||||
for (int i = 0; i < menuActions.count(); i++) {
|
||||
|
@ -206,18 +205,17 @@ void OBSBasic::RefreshSceneCollections()
|
|||
delete menuActions[i];
|
||||
}
|
||||
|
||||
const char *cur_name = config_get_string(App()->GlobalConfig(),
|
||||
"Basic", "SceneCollection");
|
||||
const char *cur_name = config_get_string(App()->GlobalConfig(), "Basic",
|
||||
"SceneCollection");
|
||||
|
||||
auto addCollection = [&](const char *name, const char *path)
|
||||
{
|
||||
auto addCollection = [&](const char *name, const char *path) {
|
||||
std::string file = strrchr(path, '/') + 1;
|
||||
file.erase(file.size() - 5, 5);
|
||||
|
||||
QAction *action = new QAction(QT_UTF8(name), this);
|
||||
action->setProperty("file_name", QT_UTF8(path));
|
||||
connect(action, &QAction::triggered,
|
||||
this, &OBSBasic::ChangeSceneCollection);
|
||||
connect(action, &QAction::triggered, this,
|
||||
&OBSBasic::ChangeSceneCollection);
|
||||
action->setCheckable(true);
|
||||
|
||||
action->setChecked(strcmp(name, cur_name) == 0);
|
||||
|
@ -243,7 +241,7 @@ void OBSBasic::RefreshSceneCollections()
|
|||
|
||||
ui->actionRemoveSceneCollection->setEnabled(count > 1);
|
||||
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
|
||||
|
||||
main->ui->actionPasteFilters->setEnabled(false);
|
||||
main->ui->actionPasteRef->setEnabled(false);
|
||||
|
@ -265,19 +263,19 @@ void OBSBasic::on_actionRenameSceneCollection_triggered()
|
|||
std::string name;
|
||||
std::string file;
|
||||
|
||||
std::string oldFile = config_get_string(App()->GlobalConfig(),
|
||||
"Basic", "SceneCollectionFile");
|
||||
const char *oldName = config_get_string(App()->GlobalConfig(),
|
||||
"Basic", "SceneCollection");
|
||||
std::string oldFile = config_get_string(App()->GlobalConfig(), "Basic",
|
||||
"SceneCollectionFile");
|
||||
const char *oldName = config_get_string(App()->GlobalConfig(), "Basic",
|
||||
"SceneCollection");
|
||||
|
||||
bool success = GetSceneCollectionName(this, name, file, oldName);
|
||||
if (!success)
|
||||
return;
|
||||
|
||||
config_set_string(App()->GlobalConfig(), "Basic", "SceneCollection",
|
||||
name.c_str());
|
||||
name.c_str());
|
||||
config_set_string(App()->GlobalConfig(), "Basic", "SceneCollectionFile",
|
||||
file.c_str());
|
||||
file.c_str());
|
||||
SaveProjectNow();
|
||||
|
||||
char path[512];
|
||||
|
@ -295,7 +293,7 @@ void OBSBasic::on_actionRenameSceneCollection_triggered()
|
|||
|
||||
blog(LOG_INFO, "------------------------------------------------");
|
||||
blog(LOG_INFO, "Renamed scene collection to '%s' (%s.json)",
|
||||
name.c_str(), file.c_str());
|
||||
name.c_str(), file.c_str());
|
||||
blog(LOG_INFO, "------------------------------------------------");
|
||||
|
||||
UpdateTitleBar();
|
||||
|
@ -312,13 +310,12 @@ void OBSBasic::on_actionRemoveSceneCollection_triggered()
|
|||
std::string newName;
|
||||
std::string newPath;
|
||||
|
||||
std::string oldFile = config_get_string(App()->GlobalConfig(),
|
||||
"Basic", "SceneCollectionFile");
|
||||
std::string oldName = config_get_string(App()->GlobalConfig(),
|
||||
"Basic", "SceneCollection");
|
||||
std::string oldFile = config_get_string(App()->GlobalConfig(), "Basic",
|
||||
"SceneCollectionFile");
|
||||
std::string oldName = config_get_string(App()->GlobalConfig(), "Basic",
|
||||
"SceneCollection");
|
||||
|
||||
auto cb = [&](const char *name, const char *filePath)
|
||||
{
|
||||
auto cb = [&](const char *name, const char *filePath) {
|
||||
if (strcmp(oldName.c_str(), name) != 0) {
|
||||
newName = name;
|
||||
newPath = filePath;
|
||||
|
@ -337,8 +334,8 @@ void OBSBasic::on_actionRemoveSceneCollection_triggered()
|
|||
QString text = QTStr("ConfirmRemove.Text");
|
||||
text.replace("$1", QT_UTF8(oldName.c_str()));
|
||||
|
||||
QMessageBox::StandardButton button = OBSMessageBox::question(this,
|
||||
QTStr("ConfirmRemove.Title"), text);
|
||||
QMessageBox::StandardButton button = OBSMessageBox::question(
|
||||
this, QTStr("ConfirmRemove.Title"), text);
|
||||
if (button == QMessageBox::No)
|
||||
return;
|
||||
|
||||
|
@ -358,13 +355,13 @@ void OBSBasic::on_actionRemoveSceneCollection_triggered()
|
|||
Load(newPath.c_str());
|
||||
RefreshSceneCollections();
|
||||
|
||||
const char *newFile = config_get_string(App()->GlobalConfig(),
|
||||
"Basic", "SceneCollectionFile");
|
||||
const char *newFile = config_get_string(App()->GlobalConfig(), "Basic",
|
||||
"SceneCollectionFile");
|
||||
|
||||
blog(LOG_INFO, "Removed scene collection '%s' (%s.json), "
|
||||
"switched to '%s' (%s.json)",
|
||||
oldName.c_str(), oldFile.c_str(),
|
||||
newName.c_str(), newFile);
|
||||
blog(LOG_INFO,
|
||||
"Removed scene collection '%s' (%s.json), "
|
||||
"switched to '%s' (%s.json)",
|
||||
oldName.c_str(), oldFile.c_str(), newName.c_str(), newFile);
|
||||
blog(LOG_INFO, "------------------------------------------------");
|
||||
|
||||
UpdateTitleBar();
|
||||
|
@ -388,10 +385,8 @@ void OBSBasic::on_actionImportSceneCollection_triggered()
|
|||
}
|
||||
|
||||
QString qfilePath = QFileDialog::getOpenFileName(
|
||||
this,
|
||||
QTStr("Basic.MainMenu.SceneCollection.Import"),
|
||||
qhome,
|
||||
"JSON Files (*.json)");
|
||||
this, QTStr("Basic.MainMenu.SceneCollection.Import"), qhome,
|
||||
"JSON Files (*.json)");
|
||||
|
||||
QFileInfo finfo(qfilePath);
|
||||
QString qfilename = finfo.fileName();
|
||||
|
@ -416,23 +411,25 @@ void OBSBasic::on_actionImportSceneCollection_triggered()
|
|||
obs_data_set_string(scenedata, "name", name.c_str());
|
||||
|
||||
if (!GetFileSafeName(name.c_str(), file)) {
|
||||
blog(LOG_WARNING, "Failed to create "
|
||||
"safe file name for '%s'",
|
||||
name.c_str());
|
||||
blog(LOG_WARNING,
|
||||
"Failed to create "
|
||||
"safe file name for '%s'",
|
||||
name.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
string filePath = path + file;
|
||||
|
||||
if (!GetClosestUnusedFileName(filePath, "json")) {
|
||||
blog(LOG_WARNING, "Failed to get "
|
||||
"closest file name for %s",
|
||||
file.c_str());
|
||||
blog(LOG_WARNING,
|
||||
"Failed to get "
|
||||
"closest file name for %s",
|
||||
file.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
obs_data_save_json_safe(scenedata, filePath.c_str(),
|
||||
"tmp", "bak");
|
||||
obs_data_save_json_safe(scenedata, filePath.c_str(), "tmp",
|
||||
"bak");
|
||||
RefreshSceneCollections();
|
||||
}
|
||||
}
|
||||
|
@ -445,8 +442,8 @@ void OBSBasic::on_actionExportSceneCollection_triggered()
|
|||
|
||||
QString home = QDir::homePath();
|
||||
|
||||
QString currentFile = QT_UTF8(config_get_string(App()->GlobalConfig(),
|
||||
"Basic", "SceneCollectionFile"));
|
||||
QString currentFile = QT_UTF8(config_get_string(
|
||||
App()->GlobalConfig(), "Basic", "SceneCollectionFile"));
|
||||
|
||||
int ret = GetConfigPath(path, 512, "obs-studio/basic/scenes/");
|
||||
if (ret <= 0) {
|
||||
|
@ -455,10 +452,8 @@ void OBSBasic::on_actionExportSceneCollection_triggered()
|
|||
}
|
||||
|
||||
QString exportFile = QFileDialog::getSaveFileName(
|
||||
this,
|
||||
QTStr("Basic.MainMenu.SceneCollection.Export"),
|
||||
home + "/" + currentFile,
|
||||
"JSON Files (*.json)");
|
||||
this, QTStr("Basic.MainMenu.SceneCollection.Export"),
|
||||
home + "/" + currentFile, "JSON Files (*.json)");
|
||||
|
||||
string file = QT_TO_UTF8(exportFile);
|
||||
|
||||
|
@ -472,7 +467,7 @@ void OBSBasic::on_actionExportSceneCollection_triggered()
|
|||
|
||||
void OBSBasic::ChangeSceneCollection()
|
||||
{
|
||||
QAction *action = reinterpret_cast<QAction*>(sender());
|
||||
QAction *action = reinterpret_cast<QAction *>(sender());
|
||||
std::string fileName;
|
||||
|
||||
if (!action)
|
||||
|
@ -482,8 +477,8 @@ void OBSBasic::ChangeSceneCollection()
|
|||
if (fileName.empty())
|
||||
return;
|
||||
|
||||
const char *oldName = config_get_string(App()->GlobalConfig(),
|
||||
"Basic", "SceneCollection");
|
||||
const char *oldName = config_get_string(App()->GlobalConfig(), "Basic",
|
||||
"SceneCollection");
|
||||
if (action->text().compare(QT_UTF8(oldName)) == 0) {
|
||||
action->setChecked(true);
|
||||
return;
|
||||
|
@ -494,13 +489,13 @@ void OBSBasic::ChangeSceneCollection()
|
|||
Load(fileName.c_str());
|
||||
RefreshSceneCollections();
|
||||
|
||||
const char *newName = config_get_string(App()->GlobalConfig(),
|
||||
"Basic", "SceneCollection");
|
||||
const char *newFile = config_get_string(App()->GlobalConfig(),
|
||||
"Basic", "SceneCollectionFile");
|
||||
const char *newName = config_get_string(App()->GlobalConfig(), "Basic",
|
||||
"SceneCollection");
|
||||
const char *newFile = config_get_string(App()->GlobalConfig(), "Basic",
|
||||
"SceneCollectionFile");
|
||||
|
||||
blog(LOG_INFO, "Switched to scene collection '%s' (%s.json)",
|
||||
newName, newFile);
|
||||
blog(LOG_INFO, "Switched to scene collection '%s' (%s.json)", newName,
|
||||
newFile);
|
||||
blog(LOG_INFO, "------------------------------------------------");
|
||||
|
||||
UpdateTitleBar();
|
||||
|
|
|
@ -54,8 +54,8 @@ void OBSBasic::InitDefaultTransitions()
|
|||
if (!obs_is_source_configurable(id)) {
|
||||
const char *name = obs_source_get_display_name(id);
|
||||
|
||||
obs_source_t *tr = obs_source_create_private(
|
||||
id, name, NULL);
|
||||
obs_source_t *tr =
|
||||
obs_source_create_private(id, name, NULL);
|
||||
InitTransition(tr);
|
||||
transitions.emplace_back(tr);
|
||||
|
||||
|
@ -68,7 +68,7 @@ void OBSBasic::InitDefaultTransitions()
|
|||
|
||||
for (OBSSource &tr : transitions) {
|
||||
ui->transitions->addItem(QT_UTF8(obs_source_get_name(tr)),
|
||||
QVariant::fromValue(OBSSource(tr)));
|
||||
QVariant::fromValue(OBSSource(tr)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,33 +79,33 @@ void OBSBasic::AddQuickTransitionHotkey(QuickTransition *qt)
|
|||
|
||||
dstr_printf(hotkeyId, "OBSBasic.QuickTransition.%d", qt->id);
|
||||
hotkeyName = QTStr("QuickTransitions.HotkeyName")
|
||||
.arg(MakeQuickTransitionText(qt));
|
||||
.arg(MakeQuickTransitionText(qt));
|
||||
|
||||
auto quickTransition = [] (void *data, obs_hotkey_id, obs_hotkey_t*,
|
||||
bool pressed)
|
||||
{
|
||||
auto quickTransition = [](void *data, obs_hotkey_id, obs_hotkey_t *,
|
||||
bool pressed) {
|
||||
int id = (int)(uintptr_t)data;
|
||||
OBSBasic *main =
|
||||
reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
||||
reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
|
||||
|
||||
if (pressed)
|
||||
QMetaObject::invokeMethod(main,
|
||||
"TriggerQuickTransition",
|
||||
Qt::QueuedConnection,
|
||||
Q_ARG(int, id));
|
||||
"TriggerQuickTransition",
|
||||
Qt::QueuedConnection,
|
||||
Q_ARG(int, id));
|
||||
};
|
||||
|
||||
qt->hotkey = obs_hotkey_register_frontend(hotkeyId->array,
|
||||
QT_TO_UTF8(hotkeyName), quickTransition,
|
||||
(void*)(uintptr_t)qt->id);
|
||||
QT_TO_UTF8(hotkeyName),
|
||||
quickTransition,
|
||||
(void *)(uintptr_t)qt->id);
|
||||
}
|
||||
|
||||
void QuickTransition::SourceRenamed(void *param, calldata_t *data)
|
||||
{
|
||||
QuickTransition *qt = reinterpret_cast<QuickTransition*>(param);
|
||||
QuickTransition *qt = reinterpret_cast<QuickTransition *>(param);
|
||||
|
||||
QString hotkeyName = QTStr("QuickTransitions.HotkeyName")
|
||||
.arg(MakeQuickTransitionText(qt));
|
||||
.arg(MakeQuickTransitionText(qt));
|
||||
|
||||
obs_hotkey_set_description(qt->hotkey, QT_TO_UTF8(hotkeyName));
|
||||
|
||||
|
@ -135,23 +135,23 @@ void OBSBasic::RemoveQuickTransitionHotkey(QuickTransition *qt)
|
|||
|
||||
void OBSBasic::InitTransition(obs_source_t *transition)
|
||||
{
|
||||
auto onTransitionStop = [] (void *data, calldata_t*) {
|
||||
OBSBasic *window = (OBSBasic*)data;
|
||||
auto onTransitionStop = [](void *data, calldata_t *) {
|
||||
OBSBasic *window = (OBSBasic *)data;
|
||||
QMetaObject::invokeMethod(window, "TransitionStopped",
|
||||
Qt::QueuedConnection);
|
||||
Qt::QueuedConnection);
|
||||
};
|
||||
|
||||
auto onTransitionFullStop = [] (void *data, calldata_t*) {
|
||||
OBSBasic *window = (OBSBasic*)data;
|
||||
auto onTransitionFullStop = [](void *data, calldata_t *) {
|
||||
OBSBasic *window = (OBSBasic *)data;
|
||||
QMetaObject::invokeMethod(window, "TransitionFullyStopped",
|
||||
Qt::QueuedConnection);
|
||||
Qt::QueuedConnection);
|
||||
};
|
||||
|
||||
signal_handler_t *handler = obs_source_get_signal_handler(transition);
|
||||
signal_handler_connect(handler, "transition_video_stop",
|
||||
onTransitionStop, this);
|
||||
signal_handler_connect(handler, "transition_stop",
|
||||
onTransitionFullStop, this);
|
||||
onTransitionStop, this);
|
||||
signal_handler_connect(handler, "transition_stop", onTransitionFullStop,
|
||||
this);
|
||||
}
|
||||
|
||||
static inline OBSSource GetTransitionComboItem(QComboBox *combo, int idx)
|
||||
|
@ -163,12 +163,12 @@ void OBSBasic::CreateDefaultQuickTransitions()
|
|||
{
|
||||
/* non-configurable transitions are always available, so add them
|
||||
* to the "default quick transitions" list */
|
||||
quickTransitions.emplace_back(
|
||||
GetTransitionComboItem(ui->transitions, 0),
|
||||
300, quickTransitionIdCounter++);
|
||||
quickTransitions.emplace_back(
|
||||
GetTransitionComboItem(ui->transitions, 1),
|
||||
300, quickTransitionIdCounter++);
|
||||
quickTransitions.emplace_back(GetTransitionComboItem(ui->transitions,
|
||||
0),
|
||||
300, quickTransitionIdCounter++);
|
||||
quickTransitions.emplace_back(GetTransitionComboItem(ui->transitions,
|
||||
1),
|
||||
300, quickTransitionIdCounter++);
|
||||
}
|
||||
|
||||
void OBSBasic::LoadQuickTransitions(obs_data_array_t *array)
|
||||
|
@ -188,13 +188,14 @@ void OBSBasic::LoadQuickTransitions(obs_data_array_t *array)
|
|||
obs_source_t *source = FindTransition(name);
|
||||
if (source) {
|
||||
quickTransitions.emplace_back(source, duration,
|
||||
id);
|
||||
id);
|
||||
|
||||
if (quickTransitionIdCounter <= id)
|
||||
quickTransitionIdCounter = id + 1;
|
||||
|
||||
int idx = (int)quickTransitions.size() - 1;
|
||||
AddQuickTransitionHotkey(&quickTransitions[idx]);
|
||||
AddQuickTransitionHotkey(
|
||||
&quickTransitions[idx]);
|
||||
obs_hotkey_load(quickTransitions[idx].hotkey,
|
||||
hotkeys);
|
||||
}
|
||||
|
@ -214,7 +215,7 @@ obs_data_array_t *OBSBasic::SaveQuickTransitions()
|
|||
obs_data_array_t *hotkeys = obs_hotkey_save(qt.hotkey);
|
||||
|
||||
obs_data_set_string(data, "name",
|
||||
obs_source_get_name(qt.source));
|
||||
obs_source_get_name(qt.source));
|
||||
obs_data_set_int(data, "duration", qt.duration);
|
||||
obs_data_set_array(data, "hotkeys", hotkeys);
|
||||
obs_data_set_int(data, "id", qt.id);
|
||||
|
@ -231,8 +232,7 @@ obs_data_array_t *OBSBasic::SaveQuickTransitions()
|
|||
obs_source_t *OBSBasic::FindTransition(const char *name)
|
||||
{
|
||||
for (int i = 0; i < ui->transitions->count(); i++) {
|
||||
OBSSource tr = ui->transitions->itemData(i)
|
||||
.value<OBSSource>();
|
||||
OBSSource tr = ui->transitions->itemData(i).value<OBSSource>();
|
||||
|
||||
const char *trName = obs_source_get_name(tr);
|
||||
if (strcmp(trName, name) == 0)
|
||||
|
@ -292,7 +292,7 @@ void OBSBasic::TransitionFullyStopped()
|
|||
}
|
||||
|
||||
void OBSBasic::TransitionToScene(OBSSource source, bool force, bool direct,
|
||||
bool quickTransition)
|
||||
bool quickTransition)
|
||||
{
|
||||
obs_scene_t *scene = obs_scene_from_source(source);
|
||||
bool usingPreviewProgram = IsPreviewProgramMode();
|
||||
|
@ -317,10 +317,10 @@ void OBSBasic::TransitionToScene(OBSSource source, bool force, bool direct,
|
|||
}
|
||||
|
||||
if (usingPreviewProgram && sceneDuplicationMode) {
|
||||
scene = obs_scene_duplicate(scene, NULL,
|
||||
editPropertiesMode ?
|
||||
OBS_SCENE_DUP_PRIVATE_COPY :
|
||||
OBS_SCENE_DUP_PRIVATE_REFS);
|
||||
scene = obs_scene_duplicate(
|
||||
scene, NULL,
|
||||
editPropertiesMode ? OBS_SCENE_DUP_PRIVATE_COPY
|
||||
: OBS_SCENE_DUP_PRIVATE_REFS);
|
||||
source = obs_scene_get_source(scene);
|
||||
}
|
||||
|
||||
|
@ -342,8 +342,8 @@ void OBSBasic::TransitionToScene(OBSSource source, bool force, bool direct,
|
|||
OBSData data = obs_source_get_private_settings(source);
|
||||
obs_data_release(data);
|
||||
|
||||
const char *trOverrideName = obs_data_get_string(data,
|
||||
"transition");
|
||||
const char *trOverrideName =
|
||||
obs_data_get_string(data, "transition");
|
||||
int duration = ui->transitionDuration->value();
|
||||
|
||||
if (trOverrideName && *trOverrideName && !quickTransition) {
|
||||
|
@ -351,18 +351,18 @@ void OBSBasic::TransitionToScene(OBSSource source, bool force, bool direct,
|
|||
if (trOverride) {
|
||||
transition = trOverride;
|
||||
|
||||
obs_data_set_default_int(data,
|
||||
"transition_duration", 300);
|
||||
obs_data_set_default_int(
|
||||
data, "transition_duration", 300);
|
||||
|
||||
duration = (int)obs_data_get_int(data,
|
||||
"transition_duration");
|
||||
duration = (int)obs_data_get_int(
|
||||
data, "transition_duration");
|
||||
OverrideTransition(trOverride);
|
||||
overridingTransition = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool success = obs_transition_start(transition,
|
||||
OBS_TRANSITION_MODE_AUTO, duration, source);
|
||||
bool success = obs_transition_start(
|
||||
transition, OBS_TRANSITION_MODE_AUTO, duration, source);
|
||||
if (!success)
|
||||
TransitionFullyStopped();
|
||||
}
|
||||
|
@ -432,12 +432,12 @@ void OBSBasic::on_transitions_currentIndexChanged(int)
|
|||
|
||||
void OBSBasic::AddTransition()
|
||||
{
|
||||
QAction *action = reinterpret_cast<QAction*>(sender());
|
||||
QAction *action = reinterpret_cast<QAction *>(sender());
|
||||
QString idStr = action->property("id").toString();
|
||||
|
||||
string name;
|
||||
QString placeHolderText = QT_UTF8(
|
||||
obs_source_get_display_name(QT_TO_UTF8(idStr)));
|
||||
QString placeHolderText =
|
||||
QT_UTF8(obs_source_get_display_name(QT_TO_UTF8(idStr)));
|
||||
QString format = placeHolderText + " (%1)";
|
||||
obs_source_t *source = nullptr;
|
||||
int i = 1;
|
||||
|
@ -447,40 +447,41 @@ void OBSBasic::AddTransition()
|
|||
}
|
||||
|
||||
bool accepted = NameDialog::AskForName(this,
|
||||
QTStr("TransitionNameDlg.Title"),
|
||||
QTStr("TransitionNameDlg.Text"),
|
||||
name, placeHolderText);
|
||||
QTStr("TransitionNameDlg.Title"),
|
||||
QTStr("TransitionNameDlg.Text"),
|
||||
name, placeHolderText);
|
||||
|
||||
if (accepted) {
|
||||
if (name.empty()) {
|
||||
OBSMessageBox::warning(this,
|
||||
QTStr("NoNameEntered.Title"),
|
||||
QTStr("NoNameEntered.Text"));
|
||||
QTStr("NoNameEntered.Title"),
|
||||
QTStr("NoNameEntered.Text"));
|
||||
AddTransition();
|
||||
return;
|
||||
}
|
||||
|
||||
source = FindTransition(name.c_str());
|
||||
if (source) {
|
||||
OBSMessageBox::warning(this,
|
||||
QTStr("NameExists.Title"),
|
||||
QTStr("NameExists.Text"));
|
||||
OBSMessageBox::warning(this, QTStr("NameExists.Title"),
|
||||
QTStr("NameExists.Text"));
|
||||
|
||||
AddTransition();
|
||||
return;
|
||||
}
|
||||
|
||||
source = obs_source_create_private(QT_TO_UTF8(idStr),
|
||||
name.c_str(), NULL);
|
||||
name.c_str(), NULL);
|
||||
InitTransition(source);
|
||||
ui->transitions->addItem(QT_UTF8(name.c_str()),
|
||||
QVariant::fromValue(OBSSource(source)));
|
||||
ui->transitions->addItem(
|
||||
QT_UTF8(name.c_str()),
|
||||
QVariant::fromValue(OBSSource(source)));
|
||||
ui->transitions->setCurrentIndex(ui->transitions->count() - 1);
|
||||
CreatePropertiesWindow(source);
|
||||
obs_source_release(source);
|
||||
|
||||
if (api)
|
||||
api->on_event(OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED);
|
||||
api->on_event(
|
||||
OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED);
|
||||
|
||||
ClearQuickTransitionWidgets();
|
||||
RefreshQuickTransitions();
|
||||
|
@ -500,8 +501,8 @@ void OBSBasic::on_transitionAdd_clicked()
|
|||
QAction *action = new QAction(name, this);
|
||||
action->setProperty("id", id);
|
||||
|
||||
connect(action, SIGNAL(triggered()),
|
||||
this, SLOT(AddTransition()));
|
||||
connect(action, SIGNAL(triggered()), this,
|
||||
SLOT(AddTransition()));
|
||||
|
||||
menu.addAction(action);
|
||||
foundConfigurableTransitions = true;
|
||||
|
@ -529,7 +530,8 @@ void OBSBasic::on_transitionRemove_clicked()
|
|||
if (qt.button)
|
||||
qt.button->deleteLater();
|
||||
RemoveQuickTransitionHotkey(&qt);
|
||||
quickTransitions.erase(quickTransitions.begin() + i - 1);
|
||||
quickTransitions.erase(quickTransitions.begin() + i -
|
||||
1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -544,7 +546,7 @@ void OBSBasic::on_transitionRemove_clicked()
|
|||
|
||||
void OBSBasic::RenameTransition()
|
||||
{
|
||||
QAction *action = reinterpret_cast<QAction*>(sender());
|
||||
QAction *action = reinterpret_cast<QAction *>(sender());
|
||||
QVariant variant = action->property("transition");
|
||||
obs_source_t *transition = variant.value<OBSSource>();
|
||||
|
||||
|
@ -553,24 +555,23 @@ void OBSBasic::RenameTransition()
|
|||
obs_source_t *source = nullptr;
|
||||
|
||||
bool accepted = NameDialog::AskForName(this,
|
||||
QTStr("TransitionNameDlg.Title"),
|
||||
QTStr("TransitionNameDlg.Text"),
|
||||
name, placeHolderText);
|
||||
QTStr("TransitionNameDlg.Title"),
|
||||
QTStr("TransitionNameDlg.Text"),
|
||||
name, placeHolderText);
|
||||
|
||||
if (accepted) {
|
||||
if (name.empty()) {
|
||||
OBSMessageBox::warning(this,
|
||||
QTStr("NoNameEntered.Title"),
|
||||
QTStr("NoNameEntered.Text"));
|
||||
QTStr("NoNameEntered.Title"),
|
||||
QTStr("NoNameEntered.Text"));
|
||||
RenameTransition();
|
||||
return;
|
||||
}
|
||||
|
||||
source = FindTransition(name.c_str());
|
||||
if (source) {
|
||||
OBSMessageBox::warning(this,
|
||||
QTStr("NameExists.Title"),
|
||||
QTStr("NameExists.Text"));
|
||||
OBSMessageBox::warning(this, QTStr("NameExists.Title"),
|
||||
QTStr("NameExists.Text"));
|
||||
|
||||
RenameTransition();
|
||||
return;
|
||||
|
@ -579,10 +580,12 @@ void OBSBasic::RenameTransition()
|
|||
obs_source_set_name(transition, name.c_str());
|
||||
int idx = ui->transitions->findData(variant);
|
||||
if (idx != -1) {
|
||||
ui->transitions->setItemText(idx, QT_UTF8(name.c_str()));
|
||||
ui->transitions->setItemText(idx,
|
||||
QT_UTF8(name.c_str()));
|
||||
|
||||
if (api)
|
||||
api->on_event(OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED);
|
||||
api->on_event(
|
||||
OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED);
|
||||
|
||||
ClearQuickTransitionWidgets();
|
||||
RefreshQuickTransitions();
|
||||
|
@ -597,9 +600,7 @@ void OBSBasic::on_transitionProps_clicked()
|
|||
if (!obs_source_configurable(source))
|
||||
return;
|
||||
|
||||
auto properties = [&] () {
|
||||
CreatePropertiesWindow(source);
|
||||
};
|
||||
auto properties = [&]() { CreatePropertiesWindow(source); };
|
||||
|
||||
QMenu menu(this);
|
||||
|
||||
|
@ -643,8 +644,7 @@ void OBSBasic::SetCurrentScene(obs_scene_t *scene, bool force, bool direct)
|
|||
SetCurrentScene(source, force, direct);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static T GetOBSRef(QListWidgetItem *item)
|
||||
template<typename T> static T GetOBSRef(QListWidgetItem *item)
|
||||
{
|
||||
return item->data(static_cast<int>(QtDataRole::OBSRef)).value<T>();
|
||||
}
|
||||
|
@ -679,7 +679,8 @@ void OBSBasic::SetCurrentScene(OBSSource scene, bool force, bool direct)
|
|||
ui->scenes->setCurrentItem(item);
|
||||
ui->scenes->blockSignals(false);
|
||||
if (api)
|
||||
api->on_event(OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED);
|
||||
api->on_event(
|
||||
OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -689,8 +690,8 @@ void OBSBasic::SetCurrentScene(OBSSource scene, bool force, bool direct)
|
|||
|
||||
bool userSwitched = (!force && !disableSaving);
|
||||
blog(LOG_INFO, "%s to scene '%s'",
|
||||
userSwitched ? "User switched" : "Switched",
|
||||
obs_source_get_name(scene));
|
||||
userSwitched ? "User switched" : "Switched",
|
||||
obs_source_get_name(scene));
|
||||
}
|
||||
|
||||
void OBSBasic::CreateProgramDisplay()
|
||||
|
@ -698,8 +699,8 @@ void OBSBasic::CreateProgramDisplay()
|
|||
program = new OBSQTDisplay();
|
||||
|
||||
program->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(program.data(), &QWidget::customContextMenuRequested,
|
||||
this, &OBSBasic::on_program_customContextMenuRequested);
|
||||
connect(program.data(), &QWidget::customContextMenuRequested, this,
|
||||
&OBSBasic::on_program_customContextMenuRequested);
|
||||
|
||||
auto displayResize = [this]() {
|
||||
struct obs_video_info ovi;
|
||||
|
@ -708,13 +709,11 @@ void OBSBasic::CreateProgramDisplay()
|
|||
ResizeProgram(ovi.base_width, ovi.base_height);
|
||||
};
|
||||
|
||||
connect(program.data(), &OBSQTDisplay::DisplayResized,
|
||||
displayResize);
|
||||
connect(program.data(), &OBSQTDisplay::DisplayResized, displayResize);
|
||||
|
||||
auto addDisplay = [this] (OBSQTDisplay *window)
|
||||
{
|
||||
auto addDisplay = [this](OBSQTDisplay *window) {
|
||||
obs_display_add_draw_callback(window->GetDisplay(),
|
||||
OBSBasic::RenderProgram, this);
|
||||
OBSBasic::RenderProgram, this);
|
||||
|
||||
struct obs_video_info ovi;
|
||||
if (obs_get_video_info(&ovi))
|
||||
|
@ -723,8 +722,7 @@ void OBSBasic::CreateProgramDisplay()
|
|||
|
||||
connect(program.data(), &OBSQTDisplay::DisplayCreated, addDisplay);
|
||||
|
||||
program->setSizePolicy(QSizePolicy::Expanding,
|
||||
QSizePolicy::Expanding);
|
||||
program->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
}
|
||||
|
||||
void OBSBasic::TransitionClicked()
|
||||
|
@ -771,16 +769,16 @@ void OBSBasic::CreateProgramOptions()
|
|||
|
||||
programOptions->setLayout(layout);
|
||||
|
||||
auto onAdd = [this] () {
|
||||
auto onAdd = [this]() {
|
||||
QScopedPointer<QMenu> menu(CreateTransitionMenu(this, nullptr));
|
||||
menu->exec(QCursor::pos());
|
||||
};
|
||||
|
||||
auto onConfig = [this] () {
|
||||
auto onConfig = [this]() {
|
||||
QMenu menu(this);
|
||||
QAction *action;
|
||||
|
||||
auto toggleEditProperties = [this] () {
|
||||
auto toggleEditProperties = [this]() {
|
||||
editPropertiesMode = !editPropertiesMode;
|
||||
|
||||
OBSSource actualScene = OBSGetStrongRef(programScene);
|
||||
|
@ -788,11 +786,11 @@ void OBSBasic::CreateProgramOptions()
|
|||
TransitionToScene(actualScene, true);
|
||||
};
|
||||
|
||||
auto toggleSwapScenesMode = [this] () {
|
||||
auto toggleSwapScenesMode = [this]() {
|
||||
swapScenesMode = !swapScenesMode;
|
||||
};
|
||||
|
||||
auto toggleSceneDuplication = [this] () {
|
||||
auto toggleSceneDuplication = [this]() {
|
||||
sceneDuplicationMode = !sceneDuplicationMode;
|
||||
|
||||
OBSSource actualScene = OBSGetStrongRef(programScene);
|
||||
|
@ -800,20 +798,22 @@ void OBSBasic::CreateProgramOptions()
|
|||
TransitionToScene(actualScene, true);
|
||||
};
|
||||
|
||||
auto showToolTip = [&] () {
|
||||
auto showToolTip = [&]() {
|
||||
QAction *act = menu.activeAction();
|
||||
QToolTip::showText(QCursor::pos(), act->toolTip(),
|
||||
&menu, menu.actionGeometry(act));
|
||||
&menu, menu.actionGeometry(act));
|
||||
};
|
||||
|
||||
action = menu.addAction(QTStr("QuickTransitions.DuplicateScene"));
|
||||
action = menu.addAction(
|
||||
QTStr("QuickTransitions.DuplicateScene"));
|
||||
action->setToolTip(QTStr("QuickTransitions.DuplicateSceneTT"));
|
||||
action->setCheckable(true);
|
||||
action->setChecked(sceneDuplicationMode);
|
||||
connect(action, &QAction::triggered, toggleSceneDuplication);
|
||||
connect(action, &QAction::hovered, showToolTip);
|
||||
|
||||
action = menu.addAction(QTStr("QuickTransitions.EditProperties"));
|
||||
action = menu.addAction(
|
||||
QTStr("QuickTransitions.EditProperties"));
|
||||
action->setToolTip(QTStr("QuickTransitions.EditPropertiesTT"));
|
||||
action->setCheckable(true);
|
||||
action->setChecked(editPropertiesMode);
|
||||
|
@ -831,8 +831,8 @@ void OBSBasic::CreateProgramOptions()
|
|||
menu.exec(QCursor::pos());
|
||||
};
|
||||
|
||||
connect(transitionButton.data(), &QAbstractButton::clicked,
|
||||
this, &OBSBasic::TransitionClicked);
|
||||
connect(transitionButton.data(), &QAbstractButton::clicked, this,
|
||||
&OBSBasic::TransitionClicked);
|
||||
connect(addQuickTransition, &QAbstractButton::clicked, onAdd);
|
||||
connect(configTransitions, &QAbstractButton::clicked, onConfig);
|
||||
}
|
||||
|
@ -868,8 +868,7 @@ QMenu *OBSBasic::CreatePerSceneTransitionMenu()
|
|||
duration->setSingleStep(50);
|
||||
duration->setValue(curDuration);
|
||||
|
||||
auto setTransition = [this] (QAction *action)
|
||||
{
|
||||
auto setTransition = [this](QAction *action) {
|
||||
int idx = action->property("transition_index").toInt();
|
||||
OBSSource scene = GetCurrentSceneSource();
|
||||
OBSData data = obs_source_get_private_settings(scene);
|
||||
|
@ -886,8 +885,7 @@ QMenu *OBSBasic::CreatePerSceneTransitionMenu()
|
|||
obs_data_set_string(data, "transition", name);
|
||||
};
|
||||
|
||||
auto setDuration = [this] (int duration)
|
||||
{
|
||||
auto setDuration = [this](int duration) {
|
||||
OBSSource scene = GetCurrentSceneSource();
|
||||
OBSData data = obs_source_get_private_settings(scene);
|
||||
obs_data_release(data);
|
||||
|
@ -895,8 +893,8 @@ QMenu *OBSBasic::CreatePerSceneTransitionMenu()
|
|||
obs_data_set_int(data, "transition_duration", duration);
|
||||
};
|
||||
|
||||
connect(duration, (void (QSpinBox::*)(int))&QSpinBox::valueChanged,
|
||||
setDuration);
|
||||
connect(duration, (void (QSpinBox::*)(int)) & QSpinBox::valueChanged,
|
||||
setDuration);
|
||||
|
||||
for (int i = -1; i < ui->transitions->count(); i++) {
|
||||
const char *name = "";
|
||||
|
@ -918,7 +916,7 @@ QMenu *OBSBasic::CreatePerSceneTransitionMenu()
|
|||
action->setChecked(match);
|
||||
|
||||
connect(action, &QAction::triggered,
|
||||
std::bind(setTransition, action));
|
||||
std::bind(setTransition, action));
|
||||
}
|
||||
|
||||
QWidgetAction *durationAction = new QWidgetAction(menu);
|
||||
|
@ -937,8 +935,8 @@ QMenu *OBSBasic::CreateTransitionMenu(QWidget *parent, QuickTransition *qt)
|
|||
if (qt) {
|
||||
action = menu->addAction(QTStr("Remove"));
|
||||
action->setProperty("id", qt->id);
|
||||
connect(action, &QAction::triggered,
|
||||
this, &OBSBasic::QuickTransitionRemoveClicked);
|
||||
connect(action, &QAction::triggered, this,
|
||||
&OBSBasic::QuickTransitionRemoveClicked);
|
||||
|
||||
menu->addSeparator();
|
||||
}
|
||||
|
@ -953,8 +951,9 @@ QMenu *OBSBasic::CreateTransitionMenu(QWidget *parent, QuickTransition *qt)
|
|||
duration->setValue(qt ? qt->duration : 300);
|
||||
|
||||
if (qt) {
|
||||
connect(duration, (void (QSpinBox::*)(int))&QSpinBox::valueChanged,
|
||||
this, &OBSBasic::QuickTransitionChangeDuration);
|
||||
connect(duration,
|
||||
(void (QSpinBox::*)(int)) & QSpinBox::valueChanged,
|
||||
this, &OBSBasic::QuickTransitionChangeDuration);
|
||||
}
|
||||
|
||||
for (int i = 0; i < ui->transitions->count(); i++) {
|
||||
|
@ -966,12 +965,13 @@ QMenu *OBSBasic::CreateTransitionMenu(QWidget *parent, QuickTransition *qt)
|
|||
if (qt) {
|
||||
action->setProperty("id", qt->id);
|
||||
connect(action, &QAction::triggered, this,
|
||||
&OBSBasic::QuickTransitionChange);
|
||||
&OBSBasic::QuickTransitionChange);
|
||||
} else {
|
||||
action->setProperty("duration",
|
||||
QVariant::fromValue<QWidget*>(duration));
|
||||
action->setProperty(
|
||||
"duration",
|
||||
QVariant::fromValue<QWidget *>(duration));
|
||||
connect(action, &QAction::triggered, this,
|
||||
&OBSBasic::AddQuickTransition);
|
||||
&OBSBasic::AddQuickTransition);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1004,11 +1004,11 @@ void OBSBasic::AddQuickTransitionId(int id)
|
|||
/* --------------------------------- */
|
||||
|
||||
button->setMenu(buttonMenu);
|
||||
connect(button, &QAbstractButton::clicked,
|
||||
this, &OBSBasic::QuickTransitionClicked);
|
||||
connect(button, &QAbstractButton::clicked, this,
|
||||
&OBSBasic::QuickTransitionClicked);
|
||||
|
||||
QVBoxLayout *programLayout =
|
||||
reinterpret_cast<QVBoxLayout*>(programOptions->layout());
|
||||
reinterpret_cast<QVBoxLayout *>(programOptions->layout());
|
||||
|
||||
int idx = 3;
|
||||
for (;; idx++) {
|
||||
|
@ -1027,7 +1027,7 @@ void OBSBasic::AddQuickTransitionId(int id)
|
|||
void OBSBasic::AddQuickTransition()
|
||||
{
|
||||
int trIdx = sender()->property("transition_index").toInt();
|
||||
QSpinBox *duration = sender()->property("duration").value<QSpinBox*>();
|
||||
QSpinBox *duration = sender()->property("duration").value<QSpinBox *>();
|
||||
OBSSource transition = GetTransitionComboItem(ui->transitions, trIdx);
|
||||
int id = quickTransitionIdCounter++;
|
||||
|
||||
|
@ -1048,7 +1048,7 @@ void OBSBasic::ClearQuickTransitions()
|
|||
return;
|
||||
|
||||
QVBoxLayout *programLayout =
|
||||
reinterpret_cast<QVBoxLayout*>(programOptions->layout());
|
||||
reinterpret_cast<QVBoxLayout *>(programOptions->layout());
|
||||
|
||||
for (int idx = 0;; idx++) {
|
||||
QLayoutItem *item = programLayout->itemAt(idx);
|
||||
|
@ -1118,7 +1118,7 @@ void OBSBasic::ClearQuickTransitionWidgets()
|
|||
return;
|
||||
|
||||
QVBoxLayout *programLayout =
|
||||
reinterpret_cast<QVBoxLayout*>(programOptions->layout());
|
||||
reinterpret_cast<QVBoxLayout *>(programOptions->layout());
|
||||
|
||||
for (int idx = 0;; idx++) {
|
||||
QLayoutItem *item = programLayout->itemAt(idx);
|
||||
|
@ -1152,7 +1152,7 @@ void OBSBasic::DisableQuickTransitionWidgets()
|
|||
return;
|
||||
|
||||
QVBoxLayout *programLayout =
|
||||
reinterpret_cast<QVBoxLayout*>(programOptions->layout());
|
||||
reinterpret_cast<QVBoxLayout *>(programOptions->layout());
|
||||
|
||||
for (int idx = 0;; idx++) {
|
||||
QLayoutItem *item = programLayout->itemAt(idx);
|
||||
|
@ -1173,7 +1173,7 @@ void OBSBasic::EnableQuickTransitionWidgets()
|
|||
return;
|
||||
|
||||
QVBoxLayout *programLayout =
|
||||
reinterpret_cast<QVBoxLayout*>(programOptions->layout());
|
||||
reinterpret_cast<QVBoxLayout *>(programOptions->layout());
|
||||
|
||||
for (int idx = 0;; idx++) {
|
||||
QLayoutItem *item = programLayout->itemAt(idx);
|
||||
|
@ -1209,10 +1209,11 @@ void OBSBasic::SetPreviewProgramMode(bool enabled)
|
|||
|
||||
obs_scene_t *dup;
|
||||
if (sceneDuplicationMode) {
|
||||
dup = obs_scene_duplicate(curScene, nullptr,
|
||||
editPropertiesMode ?
|
||||
OBS_SCENE_DUP_PRIVATE_COPY :
|
||||
OBS_SCENE_DUP_PRIVATE_REFS);
|
||||
dup = obs_scene_duplicate(
|
||||
curScene, nullptr,
|
||||
editPropertiesMode
|
||||
? OBS_SCENE_DUP_PRIVATE_COPY
|
||||
: OBS_SCENE_DUP_PRIVATE_REFS);
|
||||
} else {
|
||||
dup = curScene;
|
||||
obs_scene_addref(dup);
|
||||
|
@ -1235,7 +1236,7 @@ void OBSBasic::SetPreviewProgramMode(bool enabled)
|
|||
|
||||
programLabel = new QLabel(QTStr("StudioMode.Program"));
|
||||
programLabel->setSizePolicy(QSizePolicy::Preferred,
|
||||
QSizePolicy::Preferred);
|
||||
QSizePolicy::Preferred);
|
||||
programLabel->setAlignment(Qt::AlignHCenter | Qt::AlignBottom);
|
||||
programLabel->setProperty("themeID", "previewProgramLabels");
|
||||
|
||||
|
@ -1248,8 +1249,8 @@ void OBSBasic::SetPreviewProgramMode(bool enabled)
|
|||
programLayout->addWidget(programLabel);
|
||||
programLayout->addWidget(program);
|
||||
|
||||
bool labels = config_get_bool(GetGlobalConfig(),
|
||||
"BasicWindow", "StudioModeLabels");
|
||||
bool labels = config_get_bool(GetGlobalConfig(), "BasicWindow",
|
||||
"StudioModeLabels");
|
||||
|
||||
programLabel->setHidden(!labels);
|
||||
|
||||
|
@ -1257,14 +1258,15 @@ void OBSBasic::SetPreviewProgramMode(bool enabled)
|
|||
|
||||
ui->previewLayout->addWidget(programOptions);
|
||||
ui->previewLayout->addWidget(programWidget);
|
||||
ui->previewLayout->setAlignment(programOptions, Qt::AlignCenter);
|
||||
ui->previewLayout->setAlignment(programOptions,
|
||||
Qt::AlignCenter);
|
||||
|
||||
if (api)
|
||||
api->on_event(OBS_FRONTEND_EVENT_STUDIO_MODE_ENABLED);
|
||||
|
||||
blog(LOG_INFO, "Switched to Preview/Program mode");
|
||||
blog(LOG_INFO, "-----------------------------"
|
||||
"-------------------");
|
||||
"-------------------");
|
||||
} else {
|
||||
OBSSource actualProgramScene = OBSGetStrongRef(programScene);
|
||||
if (!actualProgramScene)
|
||||
|
@ -1299,7 +1301,7 @@ void OBSBasic::SetPreviewProgramMode(bool enabled)
|
|||
|
||||
blog(LOG_INFO, "Switched to regular Preview mode");
|
||||
blog(LOG_INFO, "-----------------------------"
|
||||
"-------------------");
|
||||
"-------------------");
|
||||
}
|
||||
|
||||
ResetUI();
|
||||
|
@ -1310,7 +1312,7 @@ void OBSBasic::RenderProgram(void *data, uint32_t cx, uint32_t cy)
|
|||
{
|
||||
GS_DEBUG_MARKER_BEGIN(GS_DEBUG_COLOR_DEFAULT, "RenderProgram");
|
||||
|
||||
OBSBasic *window = static_cast<OBSBasic*>(data);
|
||||
OBSBasic *window = static_cast<OBSBasic *>(data);
|
||||
obs_video_info ovi;
|
||||
|
||||
obs_get_video_info(&ovi);
|
||||
|
@ -1324,9 +1326,9 @@ void OBSBasic::RenderProgram(void *data, uint32_t cx, uint32_t cy)
|
|||
/* --------------------------------------- */
|
||||
|
||||
gs_ortho(0.0f, float(ovi.base_width), 0.0f, float(ovi.base_height),
|
||||
-100.0f, 100.0f);
|
||||
gs_set_viewport(window->programX, window->programY,
|
||||
window->programCX, window->programCY);
|
||||
-100.0f, 100.0f);
|
||||
gs_set_viewport(window->programX, window->programY, window->programCX,
|
||||
window->programCY);
|
||||
|
||||
window->DrawBackdrop(float(ovi.base_width), float(ovi.base_height));
|
||||
|
||||
|
@ -1351,9 +1353,9 @@ void OBSBasic::ResizeProgram(uint32_t cx, uint32_t cy)
|
|||
/* resize program panel to fix to the top section of the window */
|
||||
targetSize = GetPixelSize(program);
|
||||
GetScaleAndCenterPos(int(cx), int(cy),
|
||||
targetSize.width() - PREVIEW_EDGE_SIZE * 2,
|
||||
targetSize.height() - PREVIEW_EDGE_SIZE * 2,
|
||||
programX, programY, programScale);
|
||||
targetSize.width() - PREVIEW_EDGE_SIZE * 2,
|
||||
targetSize.height() - PREVIEW_EDGE_SIZE * 2,
|
||||
programX, programY, programScale);
|
||||
|
||||
programX += float(PREVIEW_EDGE_SIZE);
|
||||
programY += float(PREVIEW_EDGE_SIZE);
|
||||
|
@ -1371,7 +1373,8 @@ obs_data_array_t *OBSBasic::SaveTransitions()
|
|||
obs_data_t *sourceData = obs_data_create();
|
||||
obs_data_t *settings = obs_source_get_settings(tr);
|
||||
|
||||
obs_data_set_string(sourceData, "name", obs_source_get_name(tr));
|
||||
obs_data_set_string(sourceData, "name",
|
||||
obs_source_get_name(tr));
|
||||
obs_data_set_string(sourceData, "id", obs_obj_get_id(tr));
|
||||
obs_data_set_obj(sourceData, "settings", settings);
|
||||
|
||||
|
@ -1394,14 +1397,15 @@ void OBSBasic::LoadTransitions(obs_data_array_t *transitions)
|
|||
const char *id = obs_data_get_string(item, "id");
|
||||
obs_data_t *settings = obs_data_get_obj(item, "settings");
|
||||
|
||||
obs_source_t *source = obs_source_create_private(id, name,
|
||||
settings);
|
||||
obs_source_t *source =
|
||||
obs_source_create_private(id, name, settings);
|
||||
if (!obs_obj_invalid(source)) {
|
||||
InitTransition(source);
|
||||
ui->transitions->addItem(QT_UTF8(name),
|
||||
QVariant::fromValue(OBSSource(source)));
|
||||
ui->transitions->addItem(
|
||||
QT_UTF8(name),
|
||||
QVariant::fromValue(OBSSource(source)));
|
||||
ui->transitions->setCurrentIndex(
|
||||
ui->transitions->count() - 1);
|
||||
ui->transitions->count() - 1);
|
||||
}
|
||||
|
||||
obs_data_release(settings);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -53,16 +53,16 @@ class OBSBasicStats;
|
|||
|
||||
#define DESKTOP_AUDIO_1 Str("DesktopAudioDevice1")
|
||||
#define DESKTOP_AUDIO_2 Str("DesktopAudioDevice2")
|
||||
#define AUX_AUDIO_1 Str("AuxAudioDevice1")
|
||||
#define AUX_AUDIO_2 Str("AuxAudioDevice2")
|
||||
#define AUX_AUDIO_3 Str("AuxAudioDevice3")
|
||||
#define AUX_AUDIO_4 Str("AuxAudioDevice4")
|
||||
#define AUX_AUDIO_1 Str("AuxAudioDevice1")
|
||||
#define AUX_AUDIO_2 Str("AuxAudioDevice2")
|
||||
#define AUX_AUDIO_3 Str("AuxAudioDevice3")
|
||||
#define AUX_AUDIO_4 Str("AuxAudioDevice4")
|
||||
|
||||
#define SIMPLE_ENCODER_X264 "x264"
|
||||
#define SIMPLE_ENCODER_X264_LOWCPU "x264_lowcpu"
|
||||
#define SIMPLE_ENCODER_QSV "qsv"
|
||||
#define SIMPLE_ENCODER_NVENC "nvenc"
|
||||
#define SIMPLE_ENCODER_AMD "amd"
|
||||
#define SIMPLE_ENCODER_X264 "x264"
|
||||
#define SIMPLE_ENCODER_X264_LOWCPU "x264_lowcpu"
|
||||
#define SIMPLE_ENCODER_QSV "qsv"
|
||||
#define SIMPLE_ENCODER_NVENC "nvenc"
|
||||
#define SIMPLE_ENCODER_AMD "amd"
|
||||
|
||||
#define PREVIEW_EDGE_SIZE 10
|
||||
|
||||
|
@ -89,13 +89,14 @@ struct QuickTransition {
|
|||
|
||||
inline QuickTransition() {}
|
||||
inline QuickTransition(OBSSource source_, int duration_, int id_)
|
||||
: source (source_),
|
||||
duration (duration_),
|
||||
id (id_),
|
||||
renamedSignal (std::make_shared<OBSSignal>(
|
||||
obs_source_get_signal_handler(source),
|
||||
"rename", SourceRenamed, this))
|
||||
{}
|
||||
: source(source_),
|
||||
duration(duration_),
|
||||
id(id_),
|
||||
renamedSignal(std::make_shared<OBSSignal>(
|
||||
obs_source_get_signal_handler(source), "rename",
|
||||
SourceRenamed, this))
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
static void SourceRenamed(void *param, calldata_t *data);
|
||||
|
@ -124,19 +125,14 @@ class OBSBasic : public OBSMainWindow {
|
|||
friend class AutoConfigStreamPage;
|
||||
friend struct OBSStudioAPI;
|
||||
|
||||
enum class MoveDir {
|
||||
Up,
|
||||
Down,
|
||||
Left,
|
||||
Right
|
||||
};
|
||||
enum class MoveDir { Up, Down, Left, Right };
|
||||
|
||||
enum DropType {
|
||||
DropType_RawText,
|
||||
DropType_Text,
|
||||
DropType_Image,
|
||||
DropType_Media,
|
||||
DropType_Html
|
||||
DropType_Html,
|
||||
};
|
||||
|
||||
private:
|
||||
|
@ -144,7 +140,7 @@ private:
|
|||
|
||||
std::shared_ptr<Auth> auth;
|
||||
|
||||
std::vector<VolControl*> volumes;
|
||||
std::vector<VolControl *> volumes;
|
||||
|
||||
std::vector<OBSSignal> signalHandlers;
|
||||
|
||||
|
@ -172,7 +168,7 @@ private:
|
|||
QPointer<QDockWidget> statsDock;
|
||||
QPointer<OBSAbout> about;
|
||||
|
||||
QPointer<QTimer> cpuUsageTimer;
|
||||
QPointer<QTimer> cpuUsageTimer;
|
||||
os_cpu_usage_info_t *cpuUsageInfo = nullptr;
|
||||
|
||||
OBSService service;
|
||||
|
@ -188,16 +184,16 @@ private:
|
|||
gs_vertbuffer_t *boxBottom = nullptr;
|
||||
gs_vertbuffer_t *circle = nullptr;
|
||||
|
||||
bool sceneChanging = false;
|
||||
bool ignoreSelectionUpdate = false;
|
||||
bool sceneChanging = false;
|
||||
bool ignoreSelectionUpdate = false;
|
||||
|
||||
int previewX = 0, previewY = 0;
|
||||
int previewCX = 0, previewCY = 0;
|
||||
float previewScale = 0.0f;
|
||||
int previewX = 0, previewY = 0;
|
||||
int previewCX = 0, previewCY = 0;
|
||||
float previewScale = 0.0f;
|
||||
|
||||
ConfigFile basicConfig;
|
||||
ConfigFile basicConfig;
|
||||
|
||||
std::vector<SavedProjectorInfo*> savedProjectorsArray;
|
||||
std::vector<SavedProjectorInfo *> savedProjectorsArray;
|
||||
QPointer<QWidget> projectors[10];
|
||||
QList<QPointer<QWidget>> windowProjectors;
|
||||
|
||||
|
@ -210,26 +206,26 @@ private:
|
|||
QPointer<QPushButton> replayBufferButton;
|
||||
|
||||
QScopedPointer<QSystemTrayIcon> trayIcon;
|
||||
QPointer<QAction> sysTrayStream;
|
||||
QPointer<QAction> sysTrayRecord;
|
||||
QPointer<QAction> sysTrayReplayBuffer;
|
||||
QPointer<QAction> showHide;
|
||||
QPointer<QAction> exit;
|
||||
QPointer<QMenu> trayMenu;
|
||||
QPointer<QMenu> previewProjector;
|
||||
QPointer<QMenu> studioProgramProjector;
|
||||
QPointer<QMenu> multiviewProjectorMenu;
|
||||
QPointer<QMenu> previewProjectorSource;
|
||||
QPointer<QMenu> previewProjectorMain;
|
||||
QPointer<QMenu> sceneProjectorMenu;
|
||||
QPointer<QMenu> sourceProjector;
|
||||
QPointer<QMenu> scaleFilteringMenu;
|
||||
QPointer<QMenu> colorMenu;
|
||||
QPointer<QWidgetAction> colorWidgetAction;
|
||||
QPointer<ColorSelect> colorSelect;
|
||||
QPointer<QMenu> deinterlaceMenu;
|
||||
QPointer<QMenu> perSceneTransitionMenu;
|
||||
QPointer<QObject> shortcutFilter;
|
||||
QPointer<QAction> sysTrayStream;
|
||||
QPointer<QAction> sysTrayRecord;
|
||||
QPointer<QAction> sysTrayReplayBuffer;
|
||||
QPointer<QAction> showHide;
|
||||
QPointer<QAction> exit;
|
||||
QPointer<QMenu> trayMenu;
|
||||
QPointer<QMenu> previewProjector;
|
||||
QPointer<QMenu> studioProgramProjector;
|
||||
QPointer<QMenu> multiviewProjectorMenu;
|
||||
QPointer<QMenu> previewProjectorSource;
|
||||
QPointer<QMenu> previewProjectorMain;
|
||||
QPointer<QMenu> sceneProjectorMenu;
|
||||
QPointer<QMenu> sourceProjector;
|
||||
QPointer<QMenu> scaleFilteringMenu;
|
||||
QPointer<QMenu> colorMenu;
|
||||
QPointer<QWidgetAction> colorWidgetAction;
|
||||
QPointer<ColorSelect> colorSelect;
|
||||
QPointer<QMenu> deinterlaceMenu;
|
||||
QPointer<QMenu> perSceneTransitionMenu;
|
||||
QPointer<QObject> shortcutFilter;
|
||||
|
||||
QPointer<QWidget> programWidget;
|
||||
QPointer<QVBoxLayout> programLayout;
|
||||
|
@ -238,47 +234,47 @@ private:
|
|||
QScopedPointer<QThread> patronJsonThread;
|
||||
std::string patronJson;
|
||||
|
||||
void UpdateMultiviewProjectorMenu();
|
||||
void UpdateMultiviewProjectorMenu();
|
||||
|
||||
void DrawBackdrop(float cx, float cy);
|
||||
void DrawBackdrop(float cx, float cy);
|
||||
|
||||
void SetupEncoders();
|
||||
void SetupEncoders();
|
||||
|
||||
void CreateFirstRunSources();
|
||||
void CreateDefaultScene(bool firstStart);
|
||||
void CreateFirstRunSources();
|
||||
void CreateDefaultScene(bool firstStart);
|
||||
|
||||
void UpdateVolumeControlsDecayRate();
|
||||
void UpdateVolumeControlsPeakMeterType();
|
||||
void ClearVolumeControls();
|
||||
void UpdateVolumeControlsDecayRate();
|
||||
void UpdateVolumeControlsPeakMeterType();
|
||||
void ClearVolumeControls();
|
||||
|
||||
void UploadLog(const char *subdir, const char *file);
|
||||
void UploadLog(const char *subdir, const char *file);
|
||||
|
||||
void Save(const char *file);
|
||||
void Load(const char *file);
|
||||
void Save(const char *file);
|
||||
void Load(const char *file);
|
||||
|
||||
void InitHotkeys();
|
||||
void CreateHotkeys();
|
||||
void ClearHotkeys();
|
||||
void InitHotkeys();
|
||||
void CreateHotkeys();
|
||||
void ClearHotkeys();
|
||||
|
||||
bool InitService();
|
||||
bool InitService();
|
||||
|
||||
bool InitBasicConfigDefaults();
|
||||
void InitBasicConfigDefaults2();
|
||||
bool InitBasicConfig();
|
||||
bool InitBasicConfigDefaults();
|
||||
void InitBasicConfigDefaults2();
|
||||
bool InitBasicConfig();
|
||||
|
||||
void InitOBSCallbacks();
|
||||
void InitOBSCallbacks();
|
||||
|
||||
void InitPrimitives();
|
||||
void InitPrimitives();
|
||||
|
||||
void OnFirstLoad();
|
||||
void OnFirstLoad();
|
||||
|
||||
OBSSceneItem GetSceneItem(QListWidgetItem *item);
|
||||
OBSSceneItem GetCurrentSceneItem();
|
||||
OBSSceneItem GetSceneItem(QListWidgetItem *item);
|
||||
OBSSceneItem GetCurrentSceneItem();
|
||||
|
||||
bool QueryRemoveSource(obs_source_t *source);
|
||||
bool QueryRemoveSource(obs_source_t *source);
|
||||
|
||||
void TimedCheckForUpdates();
|
||||
void CheckForUpdates(bool manualUpdate);
|
||||
void TimedCheckForUpdates();
|
||||
void CheckForUpdates(bool manualUpdate);
|
||||
|
||||
void GetFPSCommon(uint32_t &num, uint32_t &den) const;
|
||||
void GetFPSInteger(uint32_t &num, uint32_t &den) const;
|
||||
|
@ -293,8 +289,8 @@ private:
|
|||
void ChangeSceneIndex(bool relative, int idx, int invalidIdx);
|
||||
|
||||
void TempFileOutput(const char *path, int vBitrate, int aBitrate);
|
||||
void TempStreamOutput(const char *url, const char *key,
|
||||
int vBitrate, int aBitrate);
|
||||
void TempStreamOutput(const char *url, const char *key, int vBitrate,
|
||||
int aBitrate);
|
||||
|
||||
void CloseDialogs();
|
||||
void ClearSceneData();
|
||||
|
@ -302,7 +298,7 @@ private:
|
|||
void Nudge(int dist, MoveDir dir);
|
||||
|
||||
OBSProjector *OpenProjector(obs_source_t *source, int monitor,
|
||||
QString title, ProjectorType type);
|
||||
QString title, ProjectorType type);
|
||||
|
||||
void GetAudioSourceFilters();
|
||||
void GetAudioSourceProperties();
|
||||
|
@ -327,8 +323,8 @@ private:
|
|||
|
||||
int GetTopSelectedSourceItem();
|
||||
|
||||
obs_hotkey_pair_id streamingHotkeys, recordingHotkeys,
|
||||
replayBufHotkeys, togglePreviewHotkeys;
|
||||
obs_hotkey_pair_id streamingHotkeys, recordingHotkeys, replayBufHotkeys,
|
||||
togglePreviewHotkeys;
|
||||
obs_hotkey_id forceStreamingStopHotkey;
|
||||
|
||||
void InitDefaultTransitions();
|
||||
|
@ -368,7 +364,7 @@ private:
|
|||
void SetPreviewProgramMode(bool enabled);
|
||||
void ResizeProgram(uint32_t cx, uint32_t cy);
|
||||
void SetCurrentScene(obs_scene_t *scene, bool force = false,
|
||||
bool direct = false);
|
||||
bool direct = false);
|
||||
static void RenderProgram(void *data, uint32_t cx, uint32_t cy);
|
||||
|
||||
std::vector<QuickTransition> quickTransitions;
|
||||
|
@ -386,8 +382,8 @@ private:
|
|||
int quickTransitionIdCounter = 1;
|
||||
bool overridingTransition = false;
|
||||
|
||||
int programX = 0, programY = 0;
|
||||
int programCX = 0, programCY = 0;
|
||||
int programX = 0, programY = 0;
|
||||
int programCX = 0, programCY = 0;
|
||||
float programScale = 0.0f;
|
||||
|
||||
int disableOutputsRef = 0;
|
||||
|
@ -407,9 +403,9 @@ private:
|
|||
|
||||
void EnumDialogs();
|
||||
|
||||
QList<QDialog*> visDialogs;
|
||||
QList<QDialog*> modalDialogs;
|
||||
QList<QMessageBox*> visMsgBoxes;
|
||||
QList<QDialog *> visDialogs;
|
||||
QList<QDialog *> modalDialogs;
|
||||
QList<QMessageBox *> visMsgBoxes;
|
||||
|
||||
QList<QPoint> visDlgPositions;
|
||||
|
||||
|
@ -457,15 +453,15 @@ public slots:
|
|||
|
||||
void SetTransition(OBSSource transition);
|
||||
void TransitionToScene(OBSScene scene, bool force = false,
|
||||
bool direct = false);
|
||||
bool direct = false);
|
||||
void TransitionToScene(OBSSource scene, bool force = false,
|
||||
bool direct = false, bool quickTransition = false);
|
||||
bool direct = false,
|
||||
bool quickTransition = false);
|
||||
void SetCurrentScene(OBSSource scene, bool force = false,
|
||||
bool direct = false);
|
||||
bool direct = false);
|
||||
|
||||
bool AddSceneCollection(
|
||||
bool create_new,
|
||||
const QString &name = QString());
|
||||
bool AddSceneCollection(bool create_new,
|
||||
const QString &name = QString());
|
||||
|
||||
void UpdatePatronJson(const QString &text, const QString &error);
|
||||
|
||||
|
@ -575,7 +571,7 @@ public:
|
|||
}
|
||||
|
||||
obs_service_t *GetService();
|
||||
void SetService(obs_service_t *service);
|
||||
void SetService(obs_service_t *service);
|
||||
|
||||
int GetTransitionDuration();
|
||||
|
||||
|
@ -588,29 +584,26 @@ public:
|
|||
bool Active() const;
|
||||
|
||||
void ResetUI();
|
||||
int ResetVideo();
|
||||
int ResetVideo();
|
||||
bool ResetAudio();
|
||||
|
||||
void ResetOutputs();
|
||||
|
||||
void ResetAudioDevice(const char *sourceId, const char *deviceId,
|
||||
const char *deviceDesc, int channel);
|
||||
const char *deviceDesc, int channel);
|
||||
|
||||
void NewProject();
|
||||
void LoadProject();
|
||||
|
||||
inline void GetDisplayRect(int &x, int &y, int &cx, int &cy)
|
||||
{
|
||||
x = previewX;
|
||||
y = previewY;
|
||||
x = previewX;
|
||||
y = previewY;
|
||||
cx = previewCX;
|
||||
cy = previewCY;
|
||||
}
|
||||
|
||||
inline bool SavingDisabled() const
|
||||
{
|
||||
return disableSaving;
|
||||
}
|
||||
inline bool SavingDisabled() const { return disableSaving; }
|
||||
|
||||
inline double GetCPUUsage() const
|
||||
{
|
||||
|
@ -620,7 +613,7 @@ public:
|
|||
void SaveService();
|
||||
bool LoadService();
|
||||
|
||||
inline Auth *GetAuth() {return auth.get();}
|
||||
inline Auth *GetAuth() { return auth.get(); }
|
||||
|
||||
inline void EnableOutputs(bool enable)
|
||||
{
|
||||
|
@ -635,7 +628,8 @@ public:
|
|||
QMenu *AddDeinterlacingMenu(QMenu *menu, obs_source_t *source);
|
||||
QMenu *AddScaleFilteringMenu(QMenu *menu, obs_sceneitem_t *item);
|
||||
QMenu *AddBackgroundColorMenu(QMenu *menu, QWidgetAction *widgetAction,
|
||||
ColorSelect *select, obs_sceneitem_t *item);
|
||||
ColorSelect *select,
|
||||
obs_sceneitem_t *item);
|
||||
void CreateSourcePopupMenu(int idx, bool preview);
|
||||
|
||||
void UpdateTitleBar();
|
||||
|
@ -691,7 +685,7 @@ private slots:
|
|||
void on_actionHorizontalCenter_triggered();
|
||||
|
||||
void on_scenes_currentItemChanged(QListWidgetItem *current,
|
||||
QListWidgetItem *prev);
|
||||
QListWidgetItem *prev);
|
||||
void on_scenes_customContextMenuRequested(const QPoint &pos);
|
||||
void on_actionAddScene_triggered();
|
||||
void on_actionRemoveScene_triggered();
|
||||
|
@ -728,8 +722,8 @@ private slots:
|
|||
|
||||
void on_preview_customContextMenuRequested(const QPoint &pos);
|
||||
void on_program_customContextMenuRequested(const QPoint &pos);
|
||||
void on_previewDisabledLabel_customContextMenuRequested(
|
||||
const QPoint &pos);
|
||||
void
|
||||
on_previewDisabledLabel_customContextMenuRequested(const QPoint &pos);
|
||||
|
||||
void on_actionNewSceneCollection_triggered();
|
||||
void on_actionDupSceneCollection_triggered();
|
||||
|
@ -779,7 +773,7 @@ private slots:
|
|||
void EditSceneItemName();
|
||||
|
||||
void SceneNameEdited(QWidget *editor,
|
||||
QAbstractItemDelegate::EndEditHint endHint);
|
||||
QAbstractItemDelegate::EndEditHint endHint);
|
||||
|
||||
void OpenSceneFilters();
|
||||
void OpenFilters();
|
||||
|
@ -825,8 +819,8 @@ public:
|
|||
|
||||
virtual config_t *Config() const override;
|
||||
|
||||
virtual int GetProfilePath(char *path, size_t size, const char *file)
|
||||
const override;
|
||||
virtual int GetProfilePath(char *path, size_t size,
|
||||
const char *file) const override;
|
||||
|
||||
static void InitBrowserPanelSafeBlock();
|
||||
|
||||
|
@ -839,8 +833,8 @@ class SceneRenameDelegate : public QStyledItemDelegate {
|
|||
|
||||
public:
|
||||
SceneRenameDelegate(QObject *parent);
|
||||
virtual void setEditorData(QWidget *editor, const QModelIndex &index)
|
||||
const override;
|
||||
virtual void setEditorData(QWidget *editor,
|
||||
const QModelIndex &index) const override;
|
||||
|
||||
protected:
|
||||
virtual bool eventFilter(QObject *editor, QEvent *event) override;
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#include "obs-app.hpp"
|
||||
#include "platform.hpp"
|
||||
|
||||
#define HANDLE_RADIUS 4.0f
|
||||
#define HANDLE_RADIUS 4.0f
|
||||
#define HANDLE_SEL_RADIUS (HANDLE_RADIUS * 1.5f)
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
|
||||
#define SUPPORTS_FRACTIONAL_SCALING
|
||||
|
@ -37,7 +37,7 @@ OBSBasicPreview::~OBSBasicPreview()
|
|||
|
||||
vec2 OBSBasicPreview::GetMouseEventPos(QMouseEvent *event)
|
||||
{
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
|
||||
#ifdef SUPPORTS_FRACTIONAL_SCALING
|
||||
float pixelRatio = main->devicePixelRatioF();
|
||||
#else
|
||||
|
@ -46,28 +46,28 @@ vec2 OBSBasicPreview::GetMouseEventPos(QMouseEvent *event)
|
|||
float scale = pixelRatio / main->previewScale;
|
||||
vec2 pos;
|
||||
vec2_set(&pos,
|
||||
(float(event->x()) - main->previewX / pixelRatio) * scale,
|
||||
(float(event->y()) - main->previewY / pixelRatio) * scale);
|
||||
(float(event->x()) - main->previewX / pixelRatio) * scale,
|
||||
(float(event->y()) - main->previewY / pixelRatio) * scale);
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
struct SceneFindData {
|
||||
const vec2 &pos;
|
||||
const vec2 &pos;
|
||||
OBSSceneItem item;
|
||||
bool selectBelow;
|
||||
bool selectBelow;
|
||||
|
||||
obs_sceneitem_t *group = nullptr;
|
||||
|
||||
SceneFindData(const SceneFindData &) = delete;
|
||||
SceneFindData(SceneFindData &&) = delete;
|
||||
SceneFindData& operator=(const SceneFindData &) = delete;
|
||||
SceneFindData& operator=(SceneFindData &&) = delete;
|
||||
SceneFindData &operator=(const SceneFindData &) = delete;
|
||||
SceneFindData &operator=(SceneFindData &&) = delete;
|
||||
|
||||
inline SceneFindData(const vec2 &pos_, bool selectBelow_)
|
||||
: pos (pos_),
|
||||
selectBelow (selectBelow_)
|
||||
{}
|
||||
: pos(pos_), selectBelow(selectBelow_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
static bool SceneItemHasVideo(obs_sceneitem_t *item)
|
||||
|
@ -77,21 +77,21 @@ static bool SceneItemHasVideo(obs_sceneitem_t *item)
|
|||
return (flags & OBS_SOURCE_VIDEO) != 0;
|
||||
}
|
||||
|
||||
static bool CloseFloat(float a, float b, float epsilon=0.01)
|
||||
static bool CloseFloat(float a, float b, float epsilon = 0.01)
|
||||
{
|
||||
using std::abs;
|
||||
return abs(a-b) <= epsilon;
|
||||
return abs(a - b) <= epsilon;
|
||||
}
|
||||
|
||||
static bool FindItemAtPos(obs_scene_t *scene, obs_sceneitem_t *item,
|
||||
void *param)
|
||||
void *param)
|
||||
{
|
||||
SceneFindData *data = reinterpret_cast<SceneFindData*>(param);
|
||||
matrix4 transform;
|
||||
matrix4 invTransform;
|
||||
vec3 transformedPos;
|
||||
vec3 pos3;
|
||||
vec3 pos3_;
|
||||
SceneFindData *data = reinterpret_cast<SceneFindData *>(param);
|
||||
matrix4 transform;
|
||||
matrix4 invTransform;
|
||||
vec3 transformedPos;
|
||||
vec3 pos3;
|
||||
vec3 pos3_;
|
||||
|
||||
if (!SceneItemHasVideo(item))
|
||||
return true;
|
||||
|
@ -147,54 +147,50 @@ static inline vec2 GetOBSScreenSize()
|
|||
|
||||
vec3 OBSBasicPreview::GetSnapOffset(const vec3 &tl, const vec3 &br)
|
||||
{
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
|
||||
vec2 screenSize = GetOBSScreenSize();
|
||||
vec3 clampOffset;
|
||||
|
||||
vec3_zero(&clampOffset);
|
||||
|
||||
const bool snap = config_get_bool(GetGlobalConfig(),
|
||||
"BasicWindow", "SnappingEnabled");
|
||||
const bool snap = config_get_bool(GetGlobalConfig(), "BasicWindow",
|
||||
"SnappingEnabled");
|
||||
if (snap == false)
|
||||
return clampOffset;
|
||||
|
||||
const bool screenSnap = config_get_bool(GetGlobalConfig(),
|
||||
"BasicWindow", "ScreenSnapping");
|
||||
const bool centerSnap = config_get_bool(GetGlobalConfig(),
|
||||
"BasicWindow", "CenterSnapping");
|
||||
const bool screenSnap = config_get_bool(
|
||||
GetGlobalConfig(), "BasicWindow", "ScreenSnapping");
|
||||
const bool centerSnap = config_get_bool(
|
||||
GetGlobalConfig(), "BasicWindow", "CenterSnapping");
|
||||
|
||||
const float clampDist = config_get_double(GetGlobalConfig(),
|
||||
"BasicWindow", "SnapDistance") / main->previewScale;
|
||||
"BasicWindow",
|
||||
"SnapDistance") /
|
||||
main->previewScale;
|
||||
const float centerX = br.x - (br.x - tl.x) / 2.0f;
|
||||
const float centerY = br.y - (br.y - tl.y) / 2.0f;
|
||||
|
||||
// Left screen edge.
|
||||
if (screenSnap &&
|
||||
fabsf(tl.x) < clampDist)
|
||||
if (screenSnap && fabsf(tl.x) < clampDist)
|
||||
clampOffset.x = -tl.x;
|
||||
// Right screen edge.
|
||||
if (screenSnap &&
|
||||
fabsf(clampOffset.x) < EPSILON &&
|
||||
if (screenSnap && fabsf(clampOffset.x) < EPSILON &&
|
||||
fabsf(screenSize.x - br.x) < clampDist)
|
||||
clampOffset.x = screenSize.x - br.x;
|
||||
// Horizontal center.
|
||||
if (centerSnap &&
|
||||
fabsf(screenSize.x - (br.x - tl.x)) > clampDist &&
|
||||
if (centerSnap && fabsf(screenSize.x - (br.x - tl.x)) > clampDist &&
|
||||
fabsf(screenSize.x / 2.0f - centerX) < clampDist)
|
||||
clampOffset.x = screenSize.x / 2.0f - centerX;
|
||||
|
||||
// Top screen edge.
|
||||
if (screenSnap &&
|
||||
fabsf(tl.y) < clampDist)
|
||||
if (screenSnap && fabsf(tl.y) < clampDist)
|
||||
clampOffset.y = -tl.y;
|
||||
// Bottom screen edge.
|
||||
if (screenSnap &&
|
||||
fabsf(clampOffset.y) < EPSILON &&
|
||||
if (screenSnap && fabsf(clampOffset.y) < EPSILON &&
|
||||
fabsf(screenSize.y - br.y) < clampDist)
|
||||
clampOffset.y = screenSize.y - br.y;
|
||||
// Vertical center.
|
||||
if (centerSnap &&
|
||||
fabsf(screenSize.y - (br.y - tl.y)) > clampDist &&
|
||||
if (centerSnap && fabsf(screenSize.y - (br.y - tl.y)) > clampDist &&
|
||||
fabsf(screenSize.y / 2.0f - centerY) < clampDist)
|
||||
clampOffset.y = screenSize.y / 2.0f - centerY;
|
||||
|
||||
|
@ -203,7 +199,7 @@ vec3 OBSBasicPreview::GetSnapOffset(const vec3 &tl, const vec3 &br)
|
|||
|
||||
OBSSceneItem OBSBasicPreview::GetItemAtPos(const vec2 &pos, bool selectBelow)
|
||||
{
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
|
||||
|
||||
OBSScene scene = main->GetCurrentScene();
|
||||
if (!scene)
|
||||
|
@ -215,12 +211,12 @@ OBSSceneItem OBSBasicPreview::GetItemAtPos(const vec2 &pos, bool selectBelow)
|
|||
}
|
||||
|
||||
static bool CheckItemSelected(obs_scene_t *scene, obs_sceneitem_t *item,
|
||||
void *param)
|
||||
void *param)
|
||||
{
|
||||
SceneFindData *data = reinterpret_cast<SceneFindData*>(param);
|
||||
matrix4 transform;
|
||||
vec3 transformedPos;
|
||||
vec3 pos3;
|
||||
SceneFindData *data = reinterpret_cast<SceneFindData *>(param);
|
||||
matrix4 transform;
|
||||
vec3 transformedPos;
|
||||
vec3 pos3;
|
||||
|
||||
if (!SceneItemHasVideo(item))
|
||||
return true;
|
||||
|
@ -240,7 +236,8 @@ static bool CheckItemSelected(obs_scene_t *scene, obs_sceneitem_t *item,
|
|||
|
||||
if (data->group) {
|
||||
matrix4 parent_transform;
|
||||
obs_sceneitem_get_draw_transform(data->group, &parent_transform);
|
||||
obs_sceneitem_get_draw_transform(data->group,
|
||||
&parent_transform);
|
||||
matrix4_mul(&transform, &transform, &parent_transform);
|
||||
}
|
||||
|
||||
|
@ -261,7 +258,7 @@ static bool CheckItemSelected(obs_scene_t *scene, obs_sceneitem_t *item,
|
|||
|
||||
bool OBSBasicPreview::SelectedAtPos(const vec2 &pos)
|
||||
{
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
|
||||
|
||||
OBSScene scene = main->GetCurrentScene();
|
||||
if (!scene)
|
||||
|
@ -273,46 +270,45 @@ bool OBSBasicPreview::SelectedAtPos(const vec2 &pos)
|
|||
}
|
||||
|
||||
struct HandleFindData {
|
||||
const vec2 &pos;
|
||||
const float radius;
|
||||
matrix4 parent_xform;
|
||||
const vec2 &pos;
|
||||
const float radius;
|
||||
matrix4 parent_xform;
|
||||
|
||||
OBSSceneItem item;
|
||||
ItemHandle handle = ItemHandle::None;
|
||||
ItemHandle handle = ItemHandle::None;
|
||||
|
||||
HandleFindData(const HandleFindData &) = delete;
|
||||
HandleFindData(HandleFindData &&) = delete;
|
||||
HandleFindData& operator=(const HandleFindData &) = delete;
|
||||
HandleFindData& operator=(HandleFindData &&) = delete;
|
||||
HandleFindData &operator=(const HandleFindData &) = delete;
|
||||
HandleFindData &operator=(HandleFindData &&) = delete;
|
||||
|
||||
inline HandleFindData(const vec2 &pos_, float scale)
|
||||
: pos (pos_),
|
||||
radius (HANDLE_SEL_RADIUS / scale)
|
||||
: pos(pos_), radius(HANDLE_SEL_RADIUS / scale)
|
||||
{
|
||||
matrix4_identity(&parent_xform);
|
||||
}
|
||||
|
||||
inline HandleFindData(const HandleFindData &hfd,
|
||||
obs_sceneitem_t *parent)
|
||||
: pos (hfd.pos),
|
||||
radius (hfd.radius),
|
||||
item (hfd.item),
|
||||
handle (hfd.handle)
|
||||
obs_sceneitem_t *parent)
|
||||
: pos(hfd.pos),
|
||||
radius(hfd.radius),
|
||||
item(hfd.item),
|
||||
handle(hfd.handle)
|
||||
{
|
||||
obs_sceneitem_get_draw_transform(parent, &parent_xform);
|
||||
}
|
||||
};
|
||||
|
||||
static bool FindHandleAtPos(obs_scene_t *scene, obs_sceneitem_t *item,
|
||||
void *param)
|
||||
void *param)
|
||||
{
|
||||
HandleFindData &data = *reinterpret_cast<HandleFindData*>(param);
|
||||
HandleFindData &data = *reinterpret_cast<HandleFindData *>(param);
|
||||
|
||||
if (!obs_sceneitem_selected(item)) {
|
||||
if (obs_sceneitem_is_group(item)) {
|
||||
HandleFindData newData(data, item);
|
||||
obs_sceneitem_group_enum_items(item, FindHandleAtPos,
|
||||
&newData);
|
||||
&newData);
|
||||
data.item = newData.item;
|
||||
data.handle = newData.handle;
|
||||
}
|
||||
|
@ -320,16 +316,15 @@ static bool FindHandleAtPos(obs_scene_t *scene, obs_sceneitem_t *item,
|
|||
return true;
|
||||
}
|
||||
|
||||
matrix4 transform;
|
||||
vec3 pos3;
|
||||
float closestHandle = data.radius;
|
||||
matrix4 transform;
|
||||
vec3 pos3;
|
||||
float closestHandle = data.radius;
|
||||
|
||||
vec3_set(&pos3, data.pos.x, data.pos.y, 0.0f);
|
||||
|
||||
obs_sceneitem_get_box_transform(item, &transform);
|
||||
|
||||
auto TestHandle = [&] (float x, float y, ItemHandle handle)
|
||||
{
|
||||
auto TestHandle = [&](float x, float y, ItemHandle handle) {
|
||||
vec3 handlePos = GetTransformedPos(x, y, transform);
|
||||
vec3_transform(&handlePos, &handlePos, &data.parent_xform);
|
||||
|
||||
|
@ -337,8 +332,8 @@ static bool FindHandleAtPos(obs_scene_t *scene, obs_sceneitem_t *item,
|
|||
if (dist < data.radius) {
|
||||
if (dist < closestHandle) {
|
||||
closestHandle = dist;
|
||||
data.handle = handle;
|
||||
data.item = item;
|
||||
data.handle = handle;
|
||||
data.item = item;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -370,10 +365,12 @@ static vec2 GetItemSize(obs_sceneitem_t *item)
|
|||
|
||||
obs_sceneitem_get_scale(item, &scale);
|
||||
obs_sceneitem_get_crop(item, &crop);
|
||||
size.x = float(obs_source_get_width(source) -
|
||||
crop.left - crop.right) * scale.x;
|
||||
size.y = float(obs_source_get_height(source) -
|
||||
crop.top - crop.bottom) * scale.y;
|
||||
size.x = float(obs_source_get_width(source) - crop.left -
|
||||
crop.right) *
|
||||
scale.x;
|
||||
size.y = float(obs_source_get_height(source) - crop.top -
|
||||
crop.bottom) *
|
||||
scale.y;
|
||||
}
|
||||
|
||||
return size;
|
||||
|
@ -381,7 +378,7 @@ static vec2 GetItemSize(obs_sceneitem_t *item)
|
|||
|
||||
void OBSBasicPreview::GetStretchHandleData(const vec2 &pos)
|
||||
{
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
|
||||
|
||||
OBSScene scene = main->GetCurrentScene();
|
||||
if (!scene)
|
||||
|
@ -397,13 +394,13 @@ void OBSBasicPreview::GetStretchHandleData(const vec2 &pos)
|
|||
HandleFindData data(scaled_pos, scale);
|
||||
obs_scene_enum_items(scene, FindHandleAtPos, &data);
|
||||
|
||||
stretchItem = std::move(data.item);
|
||||
stretchHandle = data.handle;
|
||||
stretchItem = std::move(data.item);
|
||||
stretchHandle = data.handle;
|
||||
|
||||
if (stretchHandle != ItemHandle::None) {
|
||||
matrix4 boxTransform;
|
||||
vec3 itemUL;
|
||||
float itemRot;
|
||||
vec3 itemUL;
|
||||
float itemRot;
|
||||
|
||||
stretchItemSize = GetItemSize(stretchItem);
|
||||
|
||||
|
@ -413,32 +410,31 @@ void OBSBasicPreview::GetStretchHandleData(const vec2 &pos)
|
|||
|
||||
/* build the item space conversion matrices */
|
||||
matrix4_identity(&itemToScreen);
|
||||
matrix4_rotate_aa4f(&itemToScreen, &itemToScreen,
|
||||
0.0f, 0.0f, 1.0f, RAD(itemRot));
|
||||
matrix4_translate3f(&itemToScreen, &itemToScreen,
|
||||
itemUL.x, itemUL.y, 0.0f);
|
||||
matrix4_rotate_aa4f(&itemToScreen, &itemToScreen, 0.0f, 0.0f,
|
||||
1.0f, RAD(itemRot));
|
||||
matrix4_translate3f(&itemToScreen, &itemToScreen, itemUL.x,
|
||||
itemUL.y, 0.0f);
|
||||
|
||||
matrix4_identity(&screenToItem);
|
||||
matrix4_translate3f(&screenToItem, &screenToItem,
|
||||
-itemUL.x, -itemUL.y, 0.0f);
|
||||
matrix4_rotate_aa4f(&screenToItem, &screenToItem,
|
||||
0.0f, 0.0f, 1.0f, RAD(-itemRot));
|
||||
matrix4_translate3f(&screenToItem, &screenToItem, -itemUL.x,
|
||||
-itemUL.y, 0.0f);
|
||||
matrix4_rotate_aa4f(&screenToItem, &screenToItem, 0.0f, 0.0f,
|
||||
1.0f, RAD(-itemRot));
|
||||
|
||||
obs_sceneitem_get_crop(stretchItem, &startCrop);
|
||||
obs_sceneitem_get_pos(stretchItem, &startItemPos);
|
||||
|
||||
obs_source_t *source = obs_sceneitem_get_source(stretchItem);
|
||||
cropSize.x = float(obs_source_get_width(source) -
|
||||
startCrop.left - startCrop.right);
|
||||
startCrop.left - startCrop.right);
|
||||
cropSize.y = float(obs_source_get_height(source) -
|
||||
startCrop.top - startCrop.bottom);
|
||||
startCrop.top - startCrop.bottom);
|
||||
|
||||
stretchGroup = obs_sceneitem_get_group(scene, stretchItem);
|
||||
if (stretchGroup) {
|
||||
obs_sceneitem_get_draw_transform(stretchGroup,
|
||||
&invGroupTransform);
|
||||
matrix4_inv(&invGroupTransform,
|
||||
&invGroupTransform);
|
||||
&invGroupTransform);
|
||||
matrix4_inv(&invGroupTransform, &invGroupTransform);
|
||||
obs_sceneitem_defer_group_resize_begin(stretchGroup);
|
||||
}
|
||||
}
|
||||
|
@ -480,8 +476,8 @@ void OBSBasicPreview::keyReleaseEvent(QKeyEvent *event)
|
|||
|
||||
void OBSBasicPreview::wheelEvent(QWheelEvent *event)
|
||||
{
|
||||
if (scrollMode && IsFixedScaling()
|
||||
&& event->orientation() == Qt::Vertical) {
|
||||
if (scrollMode && IsFixedScaling() &&
|
||||
event->orientation() == Qt::Vertical) {
|
||||
if (event->delta() > 0)
|
||||
SetScalingLevel(scalingLevel + 1);
|
||||
else if (event->delta() < 0)
|
||||
|
@ -512,7 +508,7 @@ void OBSBasicPreview::mousePressEvent(QMouseEvent *event)
|
|||
return;
|
||||
}
|
||||
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
|
||||
#ifdef SUPPORTS_FRACTIONAL_SCALING
|
||||
float pixelRatio = main->devicePixelRatioF();
|
||||
#else
|
||||
|
@ -549,7 +545,7 @@ void OBSBasicPreview::mousePressEvent(QMouseEvent *event)
|
|||
static bool select_one(obs_scene_t *scene, obs_sceneitem_t *item, void *param)
|
||||
{
|
||||
obs_sceneitem_t *selectedItem =
|
||||
reinterpret_cast<obs_sceneitem_t*>(param);
|
||||
reinterpret_cast<obs_sceneitem_t *>(param);
|
||||
if (obs_sceneitem_is_group(item))
|
||||
obs_sceneitem_group_enum_items(item, select_one, param);
|
||||
|
||||
|
@ -561,12 +557,12 @@ static bool select_one(obs_scene_t *scene, obs_sceneitem_t *item, void *param)
|
|||
|
||||
void OBSBasicPreview::DoSelect(const vec2 &pos)
|
||||
{
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
|
||||
|
||||
OBSScene scene = main->GetCurrentScene();
|
||||
OBSSceneItem item = GetItemAtPos(pos, true);
|
||||
OBSScene scene = main->GetCurrentScene();
|
||||
OBSSceneItem item = GetItemAtPos(pos, true);
|
||||
|
||||
obs_scene_enum_items(scene, select_one, (obs_sceneitem_t*)item);
|
||||
obs_scene_enum_items(scene, select_one, (obs_sceneitem_t *)item);
|
||||
}
|
||||
|
||||
void OBSBasicPreview::DoCtrlSelect(const vec2 &pos)
|
||||
|
@ -609,11 +605,11 @@ void OBSBasicPreview::mouseReleaseEvent(QMouseEvent *event)
|
|||
obs_sceneitem_defer_group_resize_end(stretchGroup);
|
||||
}
|
||||
|
||||
stretchItem = nullptr;
|
||||
stretchItem = nullptr;
|
||||
stretchGroup = nullptr;
|
||||
mouseDown = false;
|
||||
mouseMoved = false;
|
||||
cropping = false;
|
||||
mouseDown = false;
|
||||
mouseMoved = false;
|
||||
cropping = false;
|
||||
|
||||
OBSSceneItem item = GetItemAtPos(pos, true);
|
||||
hoveredPreviewItem = item;
|
||||
|
@ -626,13 +622,13 @@ struct SelectedItemBounds {
|
|||
};
|
||||
|
||||
static bool AddItemBounds(obs_scene_t *scene, obs_sceneitem_t *item,
|
||||
void *param)
|
||||
void *param)
|
||||
{
|
||||
SelectedItemBounds *data = reinterpret_cast<SelectedItemBounds*>(param);
|
||||
SelectedItemBounds *data =
|
||||
reinterpret_cast<SelectedItemBounds *>(param);
|
||||
vec3 t[4];
|
||||
|
||||
auto add_bounds = [data, &t] ()
|
||||
{
|
||||
auto add_bounds = [data, &t]() {
|
||||
for (const vec3 &v : t) {
|
||||
if (data->first) {
|
||||
vec3_copy(&data->tl, &v);
|
||||
|
@ -686,9 +682,9 @@ struct OffsetData {
|
|||
};
|
||||
|
||||
static bool GetSourceSnapOffset(obs_scene_t *scene, obs_sceneitem_t *item,
|
||||
void *param)
|
||||
void *param)
|
||||
{
|
||||
OffsetData *data = reinterpret_cast<OffsetData*>(param);
|
||||
OffsetData *data = reinterpret_cast<OffsetData *>(param);
|
||||
|
||||
if (obs_sceneitem_selected(item))
|
||||
return true;
|
||||
|
@ -696,12 +692,10 @@ static bool GetSourceSnapOffset(obs_scene_t *scene, obs_sceneitem_t *item,
|
|||
matrix4 boxTransform;
|
||||
obs_sceneitem_get_box_transform(item, &boxTransform);
|
||||
|
||||
vec3 t[4] = {
|
||||
GetTransformedPos(0.0f, 0.0f, boxTransform),
|
||||
GetTransformedPos(1.0f, 0.0f, boxTransform),
|
||||
GetTransformedPos(0.0f, 1.0f, boxTransform),
|
||||
GetTransformedPos(1.0f, 1.0f, boxTransform)
|
||||
};
|
||||
vec3 t[4] = {GetTransformedPos(0.0f, 0.0f, boxTransform),
|
||||
GetTransformedPos(1.0f, 0.0f, boxTransform),
|
||||
GetTransformedPos(0.0f, 1.0f, boxTransform),
|
||||
GetTransformedPos(1.0f, 1.0f, boxTransform)};
|
||||
|
||||
bool first = true;
|
||||
vec3 tl, br;
|
||||
|
@ -719,15 +713,15 @@ static bool GetSourceSnapOffset(obs_scene_t *scene, obs_sceneitem_t *item,
|
|||
}
|
||||
|
||||
// Snap to other source edges
|
||||
#define EDGE_SNAP(l, r, x, y) \
|
||||
do { \
|
||||
double dist = fabsf(l.x - data->r.x); \
|
||||
if (dist < data->clampDist && \
|
||||
fabsf(data->offset.x) < EPSILON && \
|
||||
data->tl.y < br.y && \
|
||||
data->br.y > tl.y && \
|
||||
(fabsf(data->offset.x) > dist || data->offset.x < EPSILON)) \
|
||||
data->offset.x = l.x - data->r.x; \
|
||||
#define EDGE_SNAP(l, r, x, y) \
|
||||
do { \
|
||||
double dist = fabsf(l.x - data->r.x); \
|
||||
if (dist < data->clampDist && \
|
||||
fabsf(data->offset.x) < EPSILON && data->tl.y < br.y && \
|
||||
data->br.y > tl.y && \
|
||||
(fabsf(data->offset.x) > dist || \
|
||||
data->offset.x < EPSILON)) \
|
||||
data->offset.x = l.x - data->r.x; \
|
||||
} while (false)
|
||||
|
||||
EDGE_SNAP(tl, br, x, y);
|
||||
|
@ -742,7 +736,7 @@ static bool GetSourceSnapOffset(obs_scene_t *scene, obs_sceneitem_t *item,
|
|||
|
||||
void OBSBasicPreview::SnapItemMovement(vec2 &offset)
|
||||
{
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
|
||||
OBSScene scene = main->GetCurrentScene();
|
||||
|
||||
SelectedItemBounds data;
|
||||
|
@ -755,10 +749,10 @@ void OBSBasicPreview::SnapItemMovement(vec2 &offset)
|
|||
|
||||
vec3 snapOffset = GetSnapOffset(data.tl, data.br);
|
||||
|
||||
const bool snap = config_get_bool(GetGlobalConfig(),
|
||||
"BasicWindow", "SnappingEnabled");
|
||||
const bool sourcesSnap = config_get_bool(GetGlobalConfig(),
|
||||
"BasicWindow", "SourceSnapping");
|
||||
const bool snap = config_get_bool(GetGlobalConfig(), "BasicWindow",
|
||||
"SnappingEnabled");
|
||||
const bool sourcesSnap = config_get_bool(
|
||||
GetGlobalConfig(), "BasicWindow", "SourceSnapping");
|
||||
if (snap == false)
|
||||
return;
|
||||
if (sourcesSnap == false) {
|
||||
|
@ -768,7 +762,9 @@ void OBSBasicPreview::SnapItemMovement(vec2 &offset)
|
|||
}
|
||||
|
||||
const float clampDist = config_get_double(GetGlobalConfig(),
|
||||
"BasicWindow", "SnapDistance") / main->previewScale;
|
||||
"BasicWindow",
|
||||
"SnapDistance") /
|
||||
main->previewScale;
|
||||
|
||||
OffsetData offsetData;
|
||||
offsetData.clampDist = clampDist;
|
||||
|
@ -794,7 +790,7 @@ static bool move_items(obs_scene_t *scene, obs_sceneitem_t *item, void *param)
|
|||
return true;
|
||||
|
||||
bool selected = obs_sceneitem_selected(item);
|
||||
vec2 *offset = reinterpret_cast<vec2*>(param);
|
||||
vec2 *offset = reinterpret_cast<vec2 *>(param);
|
||||
|
||||
if (obs_sceneitem_is_group(item) && !selected) {
|
||||
matrix4 transform;
|
||||
|
@ -822,7 +818,7 @@ static bool move_items(obs_scene_t *scene, obs_sceneitem_t *item, void *param)
|
|||
void OBSBasicPreview::MoveItems(const vec2 &pos)
|
||||
{
|
||||
Qt::KeyboardModifiers modifiers = QGuiApplication::keyboardModifiers();
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
|
||||
OBSScene scene = main->GetCurrentScene();
|
||||
|
||||
vec2 offset, moveOffset;
|
||||
|
@ -862,14 +858,14 @@ vec3 OBSBasicPreview::CalculateStretchPos(const vec3 &tl, const vec3 &br)
|
|||
}
|
||||
|
||||
void OBSBasicPreview::ClampAspect(vec3 &tl, vec3 &br, vec2 &size,
|
||||
const vec2 &baseSize)
|
||||
const vec2 &baseSize)
|
||||
{
|
||||
float baseAspect = baseSize.x / baseSize.y;
|
||||
float aspect = size.x / size.y;
|
||||
float baseAspect = baseSize.x / baseSize.y;
|
||||
float aspect = size.x / size.y;
|
||||
uint32_t stretchFlags = (uint32_t)stretchHandle;
|
||||
|
||||
if (stretchHandle == ItemHandle::TopLeft ||
|
||||
stretchHandle == ItemHandle::TopRight ||
|
||||
if (stretchHandle == ItemHandle::TopLeft ||
|
||||
stretchHandle == ItemHandle::TopRight ||
|
||||
stretchHandle == ItemHandle::BottomLeft ||
|
||||
stretchHandle == ItemHandle::BottomRight) {
|
||||
if (aspect < baseAspect) {
|
||||
|
@ -887,7 +883,7 @@ void OBSBasicPreview::ClampAspect(vec3 &tl, vec3 &br, vec2 &size,
|
|||
}
|
||||
|
||||
} else if (stretchHandle == ItemHandle::TopCenter ||
|
||||
stretchHandle == ItemHandle::BottomCenter) {
|
||||
stretchHandle == ItemHandle::BottomCenter) {
|
||||
if ((size.y >= 0.0f && size.x >= 0.0f) ||
|
||||
(size.y <= 0.0f && size.x <= 0.0f))
|
||||
size.x = size.y * baseAspect;
|
||||
|
@ -895,7 +891,7 @@ void OBSBasicPreview::ClampAspect(vec3 &tl, vec3 &br, vec2 &size,
|
|||
size.x = size.y * baseAspect * -1.0f;
|
||||
|
||||
} else if (stretchHandle == ItemHandle::CenterLeft ||
|
||||
stretchHandle == ItemHandle::CenterRight) {
|
||||
stretchHandle == ItemHandle::CenterRight) {
|
||||
if ((size.y >= 0.0f && size.x >= 0.0f) ||
|
||||
(size.y <= 0.0f && size.x <= 0.0f))
|
||||
size.y = size.x / baseAspect;
|
||||
|
@ -920,12 +916,12 @@ void OBSBasicPreview::ClampAspect(vec3 &tl, vec3 &br, vec2 &size,
|
|||
void OBSBasicPreview::SnapStretchingToScreen(vec3 &tl, vec3 &br)
|
||||
{
|
||||
uint32_t stretchFlags = (uint32_t)stretchHandle;
|
||||
vec3 newTL = GetTransformedPos(tl.x, tl.y, itemToScreen);
|
||||
vec3 newTR = GetTransformedPos(br.x, tl.y, itemToScreen);
|
||||
vec3 newBL = GetTransformedPos(tl.x, br.y, itemToScreen);
|
||||
vec3 newBR = GetTransformedPos(br.x, br.y, itemToScreen);
|
||||
vec3 boundingTL;
|
||||
vec3 boundingBR;
|
||||
vec3 newTL = GetTransformedPos(tl.x, tl.y, itemToScreen);
|
||||
vec3 newTR = GetTransformedPos(br.x, tl.y, itemToScreen);
|
||||
vec3 newBL = GetTransformedPos(tl.x, br.y, itemToScreen);
|
||||
vec3 newBR = GetTransformedPos(br.x, br.y, itemToScreen);
|
||||
vec3 boundingTL;
|
||||
vec3 boundingBR;
|
||||
|
||||
vec3_copy(&boundingTL, &newTL);
|
||||
vec3_min(&boundingTL, &boundingTL, &newTR);
|
||||
|
@ -984,14 +980,12 @@ void OBSBasicPreview::CropItem(const vec2 &pos)
|
|||
vec2 max_tl;
|
||||
vec2 max_br;
|
||||
|
||||
vec2_set(&max_tl,
|
||||
float(-crop.left) * scale.x,
|
||||
float(-crop.top) * scale.y);
|
||||
vec2_set(&max_br,
|
||||
stretchItemSize.x + crop.right * scale.x,
|
||||
stretchItemSize.y + crop.bottom * scale.y);
|
||||
vec2_set(&max_tl, float(-crop.left) * scale.x,
|
||||
float(-crop.top) * scale.y);
|
||||
vec2_set(&max_br, stretchItemSize.x + crop.right * scale.x,
|
||||
stretchItemSize.y + crop.bottom * scale.y);
|
||||
|
||||
typedef std::function<float (float, float)> minmax_func_t;
|
||||
typedef std::function<float(float, float)> minmax_func_t;
|
||||
|
||||
minmax_func_t min_x = scale.x < 0.0f ? maxfunc : minfunc;
|
||||
minmax_func_t min_y = scale.y < 0.0f ? maxfunc : minfunc;
|
||||
|
@ -1021,8 +1015,8 @@ void OBSBasicPreview::CropItem(const vec2 &pos)
|
|||
pos3.y = br.y = max_y(pos3.y, minY);
|
||||
}
|
||||
|
||||
#define ALIGN_X (ITEM_LEFT|ITEM_RIGHT)
|
||||
#define ALIGN_Y (ITEM_TOP|ITEM_BOTTOM)
|
||||
#define ALIGN_X (ITEM_LEFT | ITEM_RIGHT)
|
||||
#define ALIGN_Y (ITEM_TOP | ITEM_BOTTOM)
|
||||
vec3 newPos;
|
||||
vec3_zero(&newPos);
|
||||
|
||||
|
@ -1049,12 +1043,14 @@ void OBSBasicPreview::CropItem(const vec2 &pos)
|
|||
if (stretchFlags & ITEM_LEFT)
|
||||
crop.left += int(std::round(tl.x / scale.x));
|
||||
else if (stretchFlags & ITEM_RIGHT)
|
||||
crop.right += int(std::round((stretchItemSize.x - br.x) / scale.x));
|
||||
crop.right +=
|
||||
int(std::round((stretchItemSize.x - br.x) / scale.x));
|
||||
|
||||
if (stretchFlags & ITEM_TOP)
|
||||
crop.top += int(std::round(tl.y / scale.y));
|
||||
else if (stretchFlags & ITEM_BOTTOM)
|
||||
crop.bottom += int(std::round((stretchItemSize.y - br.y) / scale.y));
|
||||
crop.bottom +=
|
||||
int(std::round((stretchItemSize.y - br.y) / scale.y));
|
||||
|
||||
vec3_transform(&newPos, &newPos, &itemToScreen);
|
||||
newPos.x = std::round(newPos.x);
|
||||
|
@ -1075,7 +1071,7 @@ void OBSBasicPreview::CropItem(const vec2 &pos)
|
|||
obs_sceneitem_defer_update_begin(stretchItem);
|
||||
obs_sceneitem_set_crop(stretchItem, &crop);
|
||||
if (boundsType == OBS_BOUNDS_NONE)
|
||||
obs_sceneitem_set_pos(stretchItem, (vec2*)&newPos);
|
||||
obs_sceneitem_set_pos(stretchItem, (vec2 *)&newPos);
|
||||
obs_sceneitem_defer_update_end(stretchItem);
|
||||
}
|
||||
|
||||
|
@ -1109,19 +1105,20 @@ void OBSBasicPreview::StretchItem(const vec2 &pos)
|
|||
obs_source_t *source = obs_sceneitem_get_source(stretchItem);
|
||||
|
||||
vec2 baseSize;
|
||||
vec2_set(&baseSize,
|
||||
float(obs_source_get_width(source)),
|
||||
float(obs_source_get_height(source)));
|
||||
vec2_set(&baseSize, float(obs_source_get_width(source)),
|
||||
float(obs_source_get_height(source)));
|
||||
|
||||
vec2 size;
|
||||
vec2_set(&size,br. x - tl.x, br.y - tl.y);
|
||||
vec2_set(&size, br.x - tl.x, br.y - tl.y);
|
||||
|
||||
if (boundsType != OBS_BOUNDS_NONE) {
|
||||
if (shiftDown)
|
||||
ClampAspect(tl, br, size, baseSize);
|
||||
|
||||
if (tl.x > br.x) std::swap(tl.x, br.x);
|
||||
if (tl.y > br.y) std::swap(tl.y, br.y);
|
||||
if (tl.x > br.x)
|
||||
std::swap(tl.x, br.x);
|
||||
if (tl.y > br.y)
|
||||
std::swap(tl.y, br.y);
|
||||
|
||||
vec2_abs(&size, &size);
|
||||
|
||||
|
@ -1177,16 +1174,16 @@ void OBSBasicPreview::mouseMoveEvent(QMouseEvent *event)
|
|||
pos.y = std::round(pos.y);
|
||||
|
||||
if (stretchHandle != ItemHandle::None) {
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic*>(
|
||||
App()->GetMainWindow());
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic *>(
|
||||
App()->GetMainWindow());
|
||||
OBSScene scene = main->GetCurrentScene();
|
||||
obs_sceneitem_t *group = obs_sceneitem_get_group(
|
||||
scene, stretchItem);
|
||||
obs_sceneitem_t *group =
|
||||
obs_sceneitem_get_group(scene, stretchItem);
|
||||
if (group) {
|
||||
vec3 group_pos;
|
||||
vec3_set(&group_pos, pos.x, pos.y, 0.0f);
|
||||
vec3_transform(&group_pos, &group_pos,
|
||||
&invGroupTransform);
|
||||
&invGroupTransform);
|
||||
pos.x = group_pos.x;
|
||||
pos.y = group_pos.y;
|
||||
}
|
||||
|
@ -1230,13 +1227,13 @@ static void DrawSquareAtPos(float x, float y)
|
|||
gs_matrix_translate(&pos);
|
||||
|
||||
gs_matrix_translate3f(-HANDLE_RADIUS, -HANDLE_RADIUS, 0.0f);
|
||||
gs_matrix_scale3f(HANDLE_RADIUS*2, HANDLE_RADIUS*2, 1.0f);
|
||||
gs_matrix_scale3f(HANDLE_RADIUS * 2, HANDLE_RADIUS * 2, 1.0f);
|
||||
gs_draw(GS_TRISTRIP, 0, 0);
|
||||
gs_matrix_pop();
|
||||
}
|
||||
|
||||
static void DrawLine(float x1, float y1, float x2, float y2, float thickness,
|
||||
vec2 scale)
|
||||
vec2 scale)
|
||||
{
|
||||
float ySide = (y1 == y2) ? (y1 < 0.5f ? 1.0f : -1.0f) : 0.0f;
|
||||
float xSide = (x1 == x2) ? (x1 < 0.5f ? 1.0f : -1.0f) : 0.0f;
|
||||
|
@ -1245,9 +1242,9 @@ static void DrawLine(float x1, float y1, float x2, float y2, float thickness,
|
|||
|
||||
gs_vertex2f(x1, y1);
|
||||
gs_vertex2f(x1 + (xSide * (thickness / scale.x)),
|
||||
y1 + (ySide * (thickness / scale.y)));
|
||||
y1 + (ySide * (thickness / scale.y)));
|
||||
gs_vertex2f(x2 + (xSide * (thickness / scale.x)),
|
||||
y2 + (ySide * (thickness / scale.y)));
|
||||
y2 + (ySide * (thickness / scale.y)));
|
||||
gs_vertex2f(x2, y2);
|
||||
gs_vertex2f(x1, y1);
|
||||
|
||||
|
@ -1292,14 +1289,12 @@ static void DrawRect(float thickness, vec2 scale)
|
|||
|
||||
static inline bool crop_enabled(const obs_sceneitem_crop *crop)
|
||||
{
|
||||
return crop->left > 0 ||
|
||||
crop->top > 0 ||
|
||||
crop->right > 0 ||
|
||||
return crop->left > 0 || crop->top > 0 || crop->right > 0 ||
|
||||
crop->bottom > 0;
|
||||
}
|
||||
|
||||
bool OBSBasicPreview::DrawSelectedOverflow(obs_scene_t *scene,
|
||||
obs_sceneitem_t *item, void *param)
|
||||
obs_sceneitem_t *item, void *param)
|
||||
{
|
||||
if (obs_sceneitem_locked(item))
|
||||
return true;
|
||||
|
@ -1308,7 +1303,7 @@ bool OBSBasicPreview::DrawSelectedOverflow(obs_scene_t *scene,
|
|||
return true;
|
||||
|
||||
bool select = config_get_bool(GetGlobalConfig(), "BasicWindow",
|
||||
"OverflowSelectionHidden");
|
||||
"OverflowSelectionHidden");
|
||||
|
||||
if (!select && !obs_sceneitem_visible(item))
|
||||
return true;
|
||||
|
@ -1319,17 +1314,18 @@ bool OBSBasicPreview::DrawSelectedOverflow(obs_scene_t *scene,
|
|||
|
||||
gs_matrix_push();
|
||||
gs_matrix_mul(&mat);
|
||||
obs_sceneitem_group_enum_items(item, DrawSelectedOverflow, param);
|
||||
obs_sceneitem_group_enum_items(item, DrawSelectedOverflow,
|
||||
param);
|
||||
gs_matrix_pop();
|
||||
}
|
||||
|
||||
bool always = config_get_bool(GetGlobalConfig(), "BasicWindow",
|
||||
"OverflowAlwaysVisible");
|
||||
"OverflowAlwaysVisible");
|
||||
|
||||
if (!always && !obs_sceneitem_selected(item))
|
||||
return true;
|
||||
|
||||
OBSBasicPreview *prev = reinterpret_cast<OBSBasicPreview*>(param);
|
||||
OBSBasicPreview *prev = reinterpret_cast<OBSBasicPreview *>(param);
|
||||
|
||||
matrix4 boxTransform;
|
||||
matrix4 invBoxTransform;
|
||||
|
@ -1343,14 +1339,13 @@ bool OBSBasicPreview::DrawSelectedOverflow(obs_scene_t *scene,
|
|||
{{{1.f, 1.f, 0.f}}},
|
||||
};
|
||||
|
||||
bool visible = std::all_of(std::begin(bounds), std::end(bounds),
|
||||
[&](const vec3 &b)
|
||||
{
|
||||
vec3 pos;
|
||||
vec3_transform(&pos, &b, &boxTransform);
|
||||
vec3_transform(&pos, &pos, &invBoxTransform);
|
||||
return CloseFloat(pos.x, b.x) && CloseFloat(pos.y, b.y);
|
||||
});
|
||||
bool visible = std::all_of(
|
||||
std::begin(bounds), std::end(bounds), [&](const vec3 &b) {
|
||||
vec3 pos;
|
||||
vec3_transform(&pos, &b, &boxTransform);
|
||||
vec3_transform(&pos, &pos, &invBoxTransform);
|
||||
return CloseFloat(pos.x, b.x) && CloseFloat(pos.y, b.y);
|
||||
});
|
||||
|
||||
if (!visible)
|
||||
return true;
|
||||
|
@ -1360,9 +1355,9 @@ bool OBSBasicPreview::DrawSelectedOverflow(obs_scene_t *scene,
|
|||
obs_transform_info info;
|
||||
obs_sceneitem_get_info(item, &info);
|
||||
|
||||
gs_effect_t *solid = obs_get_base_effect(OBS_EFFECT_REPEAT);
|
||||
gs_eparam_t *image = gs_effect_get_param_by_name(solid, "image");
|
||||
gs_eparam_t *scale = gs_effect_get_param_by_name(solid, "scale");
|
||||
gs_effect_t *solid = obs_get_base_effect(OBS_EFFECT_REPEAT);
|
||||
gs_eparam_t *image = gs_effect_get_param_by_name(solid, "image");
|
||||
gs_eparam_t *scale = gs_effect_get_param_by_name(solid, "scale");
|
||||
|
||||
vec2 s;
|
||||
vec2_set(&s, boxTransform.x.x / 96, boxTransform.y.y / 96);
|
||||
|
@ -1389,7 +1384,7 @@ bool OBSBasicPreview::DrawSelectedOverflow(obs_scene_t *scene,
|
|||
}
|
||||
|
||||
bool OBSBasicPreview::DrawSelectedItem(obs_scene_t *scene,
|
||||
obs_sceneitem_t *item, void *param)
|
||||
obs_sceneitem_t *item, void *param)
|
||||
{
|
||||
if (obs_sceneitem_locked(item))
|
||||
return true;
|
||||
|
@ -1407,11 +1402,11 @@ bool OBSBasicPreview::DrawSelectedItem(obs_scene_t *scene,
|
|||
gs_matrix_pop();
|
||||
}
|
||||
|
||||
OBSBasicPreview *prev = reinterpret_cast<OBSBasicPreview*>(param);
|
||||
OBSBasicPreview *prev = reinterpret_cast<OBSBasicPreview *>(param);
|
||||
OBSBasic *main = OBSBasic::Get();
|
||||
|
||||
bool hovered = prev->hoveredPreviewItem == item ||
|
||||
prev->hoveredListItem == item;
|
||||
prev->hoveredListItem == item;
|
||||
bool selected = obs_sceneitem_selected(item);
|
||||
|
||||
if (!selected && !hovered)
|
||||
|
@ -1437,14 +1432,13 @@ bool OBSBasicPreview::DrawSelectedItem(obs_scene_t *scene,
|
|||
vec4_set(&green, 0.0f, 1.0f, 0.0f, 1.0f);
|
||||
vec4_set(&blue, 0.0f, 0.5f, 1.0f, 1.0f);
|
||||
|
||||
bool visible = std::all_of(std::begin(bounds), std::end(bounds),
|
||||
[&](const vec3 &b)
|
||||
{
|
||||
vec3 pos;
|
||||
vec3_transform(&pos, &b, &boxTransform);
|
||||
vec3_transform(&pos, &pos, &invBoxTransform);
|
||||
return CloseFloat(pos.x, b.x) && CloseFloat(pos.y, b.y);
|
||||
});
|
||||
bool visible = std::all_of(
|
||||
std::begin(bounds), std::end(bounds), [&](const vec3 &b) {
|
||||
vec3 pos;
|
||||
vec3_transform(&pos, &b, &boxTransform);
|
||||
vec3_transform(&pos, &pos, &invBoxTransform);
|
||||
return CloseFloat(pos.x, b.x) && CloseFloat(pos.y, b.y);
|
||||
});
|
||||
|
||||
if (!visible)
|
||||
return true;
|
||||
|
@ -1471,17 +1465,17 @@ bool OBSBasicPreview::DrawSelectedItem(obs_scene_t *scene,
|
|||
gs_eparam_t *colParam = gs_effect_get_param_by_name(eff, "color");
|
||||
|
||||
if (info.bounds_type == OBS_BOUNDS_NONE && crop_enabled(&crop)) {
|
||||
#define DRAW_SIDE(side, x1, y1, x2, y2) \
|
||||
if (hovered && !selected) \
|
||||
gs_effect_set_vec4(colParam, &blue); \
|
||||
else if (crop.side > 0) \
|
||||
gs_effect_set_vec4(colParam, &green); \
|
||||
DrawLine(x1, y1, x2, y2, HANDLE_RADIUS / 2, boxScale); \
|
||||
gs_effect_set_vec4(colParam, &red);
|
||||
#define DRAW_SIDE(side, x1, y1, x2, y2) \
|
||||
if (hovered && !selected) \
|
||||
gs_effect_set_vec4(colParam, &blue); \
|
||||
else if (crop.side > 0) \
|
||||
gs_effect_set_vec4(colParam, &green); \
|
||||
DrawLine(x1, y1, x2, y2, HANDLE_RADIUS / 2, boxScale); \
|
||||
gs_effect_set_vec4(colParam, &red);
|
||||
|
||||
DRAW_SIDE(left, 0.0f, 0.0f, 0.0f, 1.0f);
|
||||
DRAW_SIDE(top, 0.0f, 0.0f, 1.0f, 0.0f);
|
||||
DRAW_SIDE(right, 1.0f, 0.0f, 1.0f, 1.0f);
|
||||
DRAW_SIDE(left, 0.0f, 0.0f, 0.0f, 1.0f);
|
||||
DRAW_SIDE(top, 0.0f, 0.0f, 1.0f, 0.0f);
|
||||
DRAW_SIDE(right, 1.0f, 0.0f, 1.0f, 1.0f);
|
||||
DRAW_SIDE(bottom, 0.0f, 1.0f, 1.0f, 1.0f);
|
||||
#undef DRAW_SIDE
|
||||
} else {
|
||||
|
@ -1522,7 +1516,7 @@ void OBSBasicPreview::DrawOverflow()
|
|||
return;
|
||||
|
||||
bool hidden = config_get_bool(GetGlobalConfig(), "BasicWindow",
|
||||
"OverflowHidden");
|
||||
"OverflowHidden");
|
||||
|
||||
if (hidden)
|
||||
return;
|
||||
|
@ -1535,7 +1529,7 @@ void OBSBasicPreview::DrawOverflow()
|
|||
overflow = gs_texture_create_from_file(path.c_str());
|
||||
}
|
||||
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
|
||||
|
||||
OBSScene scene = main->GetCurrentScene();
|
||||
|
||||
|
@ -1558,10 +1552,10 @@ void OBSBasicPreview::DrawSceneEditing()
|
|||
|
||||
GS_DEBUG_MARKER_BEGIN(GS_DEBUG_COLOR_DEFAULT, "DrawSceneEditing");
|
||||
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
|
||||
|
||||
gs_effect_t *solid = obs_get_base_effect(OBS_EFFECT_SOLID);
|
||||
gs_technique_t *tech = gs_effect_get_technique(solid, "Solid");
|
||||
gs_effect_t *solid = obs_get_base_effect(OBS_EFFECT_SOLID);
|
||||
gs_technique_t *tech = gs_effect_get_technique(solid, "Solid");
|
||||
|
||||
vec4 color;
|
||||
vec4_set(&color, 1.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
@ -1592,13 +1586,16 @@ void OBSBasicPreview::ResetScrollingOffset()
|
|||
vec2_zero(&scrollingOffset);
|
||||
}
|
||||
|
||||
void OBSBasicPreview::SetScalingLevel(int32_t newScalingLevelVal) {
|
||||
float newScalingAmountVal = pow(ZOOM_SENSITIVITY, float(newScalingLevelVal));
|
||||
void OBSBasicPreview::SetScalingLevel(int32_t newScalingLevelVal)
|
||||
{
|
||||
float newScalingAmountVal =
|
||||
pow(ZOOM_SENSITIVITY, float(newScalingLevelVal));
|
||||
scalingLevel = newScalingLevelVal;
|
||||
SetScalingAmount(newScalingAmountVal);
|
||||
}
|
||||
|
||||
void OBSBasicPreview::SetScalingAmount(float newScalingAmountVal) {
|
||||
void OBSBasicPreview::SetScalingAmount(float newScalingAmountVal)
|
||||
{
|
||||
scrollingOffset.x *= newScalingAmountVal / scalingAmount;
|
||||
scrollingOffset.y *= newScalingAmountVal / scalingAmount;
|
||||
scalingAmount = newScalingAmountVal;
|
||||
|
|
|
@ -9,23 +9,23 @@
|
|||
class OBSBasic;
|
||||
class QMouseEvent;
|
||||
|
||||
#define ITEM_LEFT (1<<0)
|
||||
#define ITEM_RIGHT (1<<1)
|
||||
#define ITEM_TOP (1<<2)
|
||||
#define ITEM_BOTTOM (1<<3)
|
||||
#define ITEM_LEFT (1 << 0)
|
||||
#define ITEM_RIGHT (1 << 1)
|
||||
#define ITEM_TOP (1 << 2)
|
||||
#define ITEM_BOTTOM (1 << 3)
|
||||
|
||||
#define ZOOM_SENSITIVITY 1.125f
|
||||
|
||||
enum class ItemHandle : uint32_t {
|
||||
None = 0,
|
||||
TopLeft = ITEM_TOP | ITEM_LEFT,
|
||||
TopCenter = ITEM_TOP,
|
||||
TopRight = ITEM_TOP | ITEM_RIGHT,
|
||||
CenterLeft = ITEM_LEFT,
|
||||
CenterRight = ITEM_RIGHT,
|
||||
BottomLeft = ITEM_BOTTOM | ITEM_LEFT,
|
||||
None = 0,
|
||||
TopLeft = ITEM_TOP | ITEM_LEFT,
|
||||
TopCenter = ITEM_TOP,
|
||||
TopRight = ITEM_TOP | ITEM_RIGHT,
|
||||
CenterLeft = ITEM_LEFT,
|
||||
CenterRight = ITEM_RIGHT,
|
||||
BottomLeft = ITEM_BOTTOM | ITEM_LEFT,
|
||||
BottomCenter = ITEM_BOTTOM,
|
||||
BottomRight = ITEM_BOTTOM | ITEM_RIGHT
|
||||
BottomRight = ITEM_BOTTOM | ITEM_RIGHT,
|
||||
};
|
||||
|
||||
class OBSBasicPreview : public OBSQTDisplay {
|
||||
|
@ -35,40 +35,40 @@ class OBSBasicPreview : public OBSQTDisplay {
|
|||
|
||||
private:
|
||||
obs_sceneitem_crop startCrop;
|
||||
vec2 startItemPos;
|
||||
vec2 cropSize;
|
||||
vec2 startItemPos;
|
||||
vec2 cropSize;
|
||||
OBSSceneItem stretchGroup;
|
||||
OBSSceneItem stretchItem;
|
||||
ItemHandle stretchHandle = ItemHandle::None;
|
||||
vec2 stretchItemSize;
|
||||
matrix4 screenToItem;
|
||||
matrix4 itemToScreen;
|
||||
matrix4 invGroupTransform;
|
||||
ItemHandle stretchHandle = ItemHandle::None;
|
||||
vec2 stretchItemSize;
|
||||
matrix4 screenToItem;
|
||||
matrix4 itemToScreen;
|
||||
matrix4 invGroupTransform;
|
||||
|
||||
gs_texture_t *overflow = nullptr;
|
||||
|
||||
vec2 startPos;
|
||||
vec2 lastMoveOffset;
|
||||
vec2 scrollingFrom;
|
||||
vec2 scrollingOffset;
|
||||
bool mouseDown = false;
|
||||
bool mouseMoved = false;
|
||||
bool mouseOverItems = false;
|
||||
bool cropping = false;
|
||||
bool locked = false;
|
||||
bool scrollMode = false;
|
||||
bool fixedScaling = false;
|
||||
int32_t scalingLevel = 0;
|
||||
float scalingAmount = 1.0f;
|
||||
vec2 startPos;
|
||||
vec2 lastMoveOffset;
|
||||
vec2 scrollingFrom;
|
||||
vec2 scrollingOffset;
|
||||
bool mouseDown = false;
|
||||
bool mouseMoved = false;
|
||||
bool mouseOverItems = false;
|
||||
bool cropping = false;
|
||||
bool locked = false;
|
||||
bool scrollMode = false;
|
||||
bool fixedScaling = false;
|
||||
int32_t scalingLevel = 0;
|
||||
float scalingAmount = 1.0f;
|
||||
|
||||
obs_sceneitem_t *hoveredPreviewItem = nullptr;
|
||||
obs_sceneitem_t *hoveredListItem = nullptr;
|
||||
obs_sceneitem_t *hoveredListItem = nullptr;
|
||||
|
||||
static vec2 GetMouseEventPos(QMouseEvent *event);
|
||||
static bool DrawSelectedOverflow(obs_scene_t *scene,
|
||||
obs_sceneitem_t *item, void *param);
|
||||
obs_sceneitem_t *item, void *param);
|
||||
static bool DrawSelectedItem(obs_scene_t *scene, obs_sceneitem_t *item,
|
||||
void *param);
|
||||
void *param);
|
||||
|
||||
static OBSSceneItem GetItemAtPos(const vec2 &pos, bool selectBelow);
|
||||
static bool SelectedAtPos(const vec2 &pos);
|
||||
|
@ -110,11 +110,14 @@ public:
|
|||
void DrawOverflow();
|
||||
void DrawSceneEditing();
|
||||
|
||||
inline void SetLocked(bool newLockedVal) {locked = newLockedVal;}
|
||||
inline void ToggleLocked() {locked = !locked;}
|
||||
inline bool Locked() const {return locked;}
|
||||
inline void SetLocked(bool newLockedVal) { locked = newLockedVal; }
|
||||
inline void ToggleLocked() { locked = !locked; }
|
||||
inline bool Locked() const { return locked; }
|
||||
|
||||
inline void SetFixedScaling(bool newFixedScalingVal) { fixedScaling = newFixedScalingVal; }
|
||||
inline void SetFixedScaling(bool newFixedScalingVal)
|
||||
{
|
||||
fixedScaling = newFixedScalingVal;
|
||||
}
|
||||
inline bool IsFixedScaling() const { return fixedScaling; }
|
||||
|
||||
void SetScalingLevel(int32_t newScalingLevelVal);
|
||||
|
@ -123,14 +126,17 @@ public:
|
|||
inline float GetScalingAmount() const { return scalingAmount; }
|
||||
|
||||
void ResetScrollingOffset();
|
||||
inline void SetScrollingOffset(float x, float y) {vec2_set(&scrollingOffset, x, y);}
|
||||
inline float GetScrollX() const {return scrollingOffset.x;}
|
||||
inline float GetScrollY() const {return scrollingOffset.y;}
|
||||
inline void SetScrollingOffset(float x, float y)
|
||||
{
|
||||
vec2_set(&scrollingOffset, x, y);
|
||||
}
|
||||
inline float GetScrollX() const { return scrollingOffset.x; }
|
||||
inline float GetScrollY() const { return scrollingOffset.y; }
|
||||
|
||||
/* use libobs allocator for alignment because the matrices itemToScreen
|
||||
* and screenToItem may contain SSE data, which will cause SSE
|
||||
* instructions to crash if the data is not aligned to at least a 16
|
||||
* byte boundary. */
|
||||
static inline void* operator new(size_t size) {return bmalloc(size);}
|
||||
static inline void operator delete(void* ptr) {bfree(ptr);}
|
||||
static inline void *operator new(size_t size) { return bmalloc(size); }
|
||||
static inline void operator delete(void *ptr) { bfree(ptr); }
|
||||
};
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue