@@ -17,10 +17,15 @@
# include <QPlainTextEdit>
# include <QDialogButtonBox>
# include <QMenu>
# include <QStackedWidget>
# include "double-slider.hpp"
# include "qt-wrappers.hpp"
# include "properties-view.hpp"
# include "properties-view.moc.hpp"
# include "obs-app.hpp"
# include <cstdlib>
# include <initializer_list>
# include <string>
using namespace std ;
@@ -46,6 +51,41 @@ static inline long long color_to_int(QColor color)
shift ( color . alpha ( ) , 24 ) ;
}
namespace {
struct frame_rate_tag {
enum tag_type {
SIMPLE ,
RATIONAL ,
USER ,
} type = SIMPLE ;
const char * val = nullptr ;
frame_rate_tag ( ) = default ;
explicit frame_rate_tag ( tag_type type )
: type ( type )
{ }
explicit frame_rate_tag ( const char * val )
: type ( USER ) ,
val ( val )
{ }
static frame_rate_tag simple ( ) { return frame_rate_tag { SIMPLE } ; }
static frame_rate_tag rational ( ) { return frame_rate_tag { RATIONAL } ; }
} ;
struct common_frame_rate {
const char * fps_name ;
media_frames_per_second fps ;
} ;
}
Q_DECLARE_METATYPE ( frame_rate_tag ) ;
Q_DECLARE_METATYPE ( media_frames_per_second ) ;
void OBSPropertiesView : : ReloadProperties ( )
{
if ( obj ) {
@@ -634,6 +674,589 @@ void OBSPropertiesView::AddFont(obs_property_t *prop, QFormLayout *layout,
obs_data_release ( font_obj ) ;
}
namespace std {
template < >
struct default_delete < obs_data_t > {
void operator ( ) ( obs_data_t * data )
{
obs_data_release ( data ) ;
}
} ;
template < >
struct default_delete < obs_data_item_t > {
void operator ( ) ( obs_data_item_t * item )
{
obs_data_item_release ( & item ) ;
}
} ;
}
template < typename T >
static double make_epsilon ( T val )
{
return val * 0.00001 ;
}
static bool matches_range ( media_frames_per_second & match ,
media_frames_per_second fps ,
const frame_rate_range_t & pair )
{
auto val = media_frames_per_second_to_frame_interval ( fps ) ;
auto max_ = media_frames_per_second_to_frame_interval ( pair . first ) ;
auto min_ = media_frames_per_second_to_frame_interval ( pair . second ) ;
if ( min_ < = val & & val < = max_ ) {
match = fps ;
return true ;
}
return false ;
}
static bool matches_ranges ( media_frames_per_second & best_match ,
media_frames_per_second fps ,
const frame_rate_ranges_t & fps_ranges , bool exact = false )
{
auto convert_fn = media_frames_per_second_to_frame_interval ;
auto val = convert_fn ( fps ) ;
auto epsilon = make_epsilon ( val ) ;
bool match = false ;
auto best_dist = numeric_limits < double > : : max ( ) ;
for ( auto & pair : fps_ranges ) {
auto max_ = convert_fn ( pair . first ) ;
auto min_ = convert_fn ( pair . second ) ;
/*blog(LOG_INFO, "%lg ≤ %lg ≤ %lg? %s %s %s",
min_, val, max_,
fabsl(min_ - val) < epsilon ? "true" : "false",
min_ <= val && val <= max_ ? "true" : "false",
fabsl(min_ - val) < epsilon ? "true" :
"false");*/
if ( matches_range ( best_match , fps , pair ) )
return true ;
if ( exact )
continue ;
auto min_dist = fabsl ( min_ - val ) ;
auto max_dist = fabsl ( max_ - val ) ;
if ( min_dist < epsilon & & min_dist < best_dist ) {
best_match = pair . first ;
match = true ;
continue ;
}
if ( max_dist < epsilon & & max_dist < best_dist ) {
best_match = pair . second ;
match = true ;
continue ;
}
}
return match ;
}
static media_frames_per_second make_fps ( uint32_t num , uint32_t den )
{
media_frames_per_second fps { } ;
fps . numerator = num ;
fps . denominator = den ;
return fps ;
}
static const common_frame_rate common_fps [ ] = {
{ " 60 " , { 60 , 1 } } ,
{ " 59.94 " , { 60000 , 1001 } } ,
{ " 50 " , { 50 , 1 } } ,
{ " 48 " , { 48 , 1 } } ,
{ " 30 " , { 30 , 1 } } ,
{ " 29.97 " , { 30000 , 1001 } } ,
{ " 25 " , { 25 , 1 } } ,
{ " 24 " , { 24 , 1 } } ,
{ " 23.976 " , { 24000 , 1001 } } ,
} ;
static void UpdateSimpleFPSSelection ( OBSFrameRatePropertyWidget * fpsProps ,
const media_frames_per_second * current_fps )
{
if ( ! current_fps | | ! media_frames_per_second_is_valid ( * current_fps ) ) {
fpsProps - > simpleFPS - > setCurrentIndex ( 0 ) ;
return ;
}
auto combo = fpsProps - > simpleFPS ;
auto num = combo - > count ( ) ;
for ( int i = 0 ; i < num ; i + + ) {
auto variant = combo - > itemData ( i ) ;
if ( ! variant . canConvert < media_frames_per_second > ( ) )
continue ;
auto fps = variant . value < media_frames_per_second > ( ) ;
if ( fps ! = * current_fps )
continue ;
combo - > setCurrentIndex ( i ) ;
return ;
}
combo - > setCurrentIndex ( 0 ) ;
}
static void AddFPSRanges ( vector < common_frame_rate > & items ,
const frame_rate_ranges_t & ranges )
{
auto InsertFPS = [ & ] ( media_frames_per_second fps )
{
auto fps_val = media_frames_per_second_to_fps ( fps ) ;
auto end_ = end ( items ) ;
auto i = begin ( items ) ;
for ( ; i ! = end_ ; i + + ) {
auto i_fps_val = media_frames_per_second_to_fps ( i - > fps ) ;
if ( fabsl ( i_fps_val - fps_val ) < 0.01 )
return ;
if ( i_fps_val > fps_val )
continue ;
break ;
}
items . insert ( i , { nullptr , fps } ) ;
} ;
for ( auto & range : ranges ) {
InsertFPS ( range . first ) ;
InsertFPS ( range . second ) ;
}
}
static QWidget * CreateSimpleFPSValues ( OBSFrameRatePropertyWidget * fpsProps ,
bool & selected , const media_frames_per_second * current_fps )
{
auto widget = new QWidget { } ;
widget - > setSizePolicy ( QSizePolicy : : Expanding , QSizePolicy : : Expanding ) ;
auto layout = new QVBoxLayout { } ;
layout - > setContentsMargins ( 0 , 0 , 0 , 0 ) ;
auto items = vector < common_frame_rate > { } ;
items . reserve ( sizeof ( common_fps ) / sizeof ( common_frame_rate ) ) ;
auto combo = fpsProps - > simpleFPS = new QComboBox { } ;
combo - > addItem ( " " , QVariant : : fromValue ( make_fps ( 0 , 0 ) ) ) ;
for ( const auto & fps : common_fps ) {
media_frames_per_second best_match { } ;
if ( ! matches_ranges ( best_match , fps . fps , fpsProps - > fps_ranges ) )
continue ;
items . push_back ( { fps . fps_name , best_match } ) ;
}
AddFPSRanges ( items , fpsProps - > fps_ranges ) ;
for ( const auto & item : items ) {
auto var = QVariant : : fromValue ( item . fps ) ;
auto name = item . fps_name ?
QString ( item . fps_name ) :
QString ( " %1 " )
. arg ( media_frames_per_second_to_fps ( item . fps ) ) ;
combo - > addItem ( name , var ) ;
bool select = current_fps & & * current_fps = = item . fps ;
if ( select ) {
combo - > setCurrentIndex ( combo - > count ( ) - 1 ) ;
selected = true ;
}
}
layout - > addWidget ( combo , 0 , Qt : : AlignTop ) ;
widget - > setLayout ( layout ) ;
return widget ;
}
static void UpdateRationalFPSWidgets ( OBSFrameRatePropertyWidget * fpsProps ,
const media_frames_per_second * current_fps )
{
if ( ! current_fps | | ! media_frames_per_second_is_valid ( * current_fps ) ) {
fpsProps - > numEdit - > setValue ( 0 ) ;
fpsProps - > denEdit - > setValue ( 0 ) ;
return ;
}
auto combo = fpsProps - > fpsRange ;
auto num = combo - > count ( ) ;
for ( int i = 0 ; i < num ; i + + ) {
auto variant = combo - > itemData ( i ) ;
if ( ! variant . canConvert < size_t > ( ) )
continue ;
auto idx = variant . value < size_t > ( ) ;
if ( fpsProps - > fps_ranges . size ( ) < idx )
continue ;
media_frames_per_second match { } ;
if ( ! matches_range ( match , * current_fps ,
fpsProps - > fps_ranges [ idx ] ) )
continue ;
combo - > setCurrentIndex ( i ) ;
break ;
}
fpsProps - > numEdit - > setValue ( current_fps - > numerator ) ;
fpsProps - > denEdit - > setValue ( current_fps - > denominator ) ;
}
static QWidget * CreateRationalFPS ( OBSFrameRatePropertyWidget * fpsProps ,
bool & selected , const media_frames_per_second * current_fps )
{
auto widget = new QWidget { } ;
widget - > setSizePolicy ( QSizePolicy : : Expanding , QSizePolicy : : Expanding ) ;
auto layout = new QFormLayout { } ;
layout - > setContentsMargins ( 0 , 0 , 0 , 0 ) ;
layout - > setSpacing ( 4 ) ;
auto str = QTStr ( " Basic.PropertiesView.FPS.ValidFPSRanges " ) ;
auto rlabel = new QLabel { str } ;
auto combo = fpsProps - > fpsRange = new QComboBox { } ;
auto convert_fps = media_frames_per_second_to_fps ;
//auto convert_fi = media_frames_per_second_to_frame_interval;
for ( size_t i = 0 ; i < fpsProps - > fps_ranges . size ( ) ; i + + ) {
auto & pair = fpsProps - > fps_ranges [ i ] ;
combo - > addItem ( QString { " %1 - %2 " }
. arg ( convert_fps ( pair . first ) )
. arg ( convert_fps ( pair . second ) ) ,
QVariant : : fromValue ( i ) ) ;
media_frames_per_second match ;
if ( ! current_fps | | ! matches_range ( match , * current_fps , pair ) )
continue ;
combo - > setCurrentIndex ( combo - > count ( ) - 1 ) ;
selected = true ;
}
layout - > addRow ( rlabel , combo ) ;
auto num_edit = fpsProps - > numEdit = new QSpinBox { } ;
auto den_edit = fpsProps - > denEdit = new QSpinBox { } ;
num_edit - > setRange ( 0 , INT_MAX ) ;
den_edit - > setRange ( 0 , INT_MAX ) ;
if ( current_fps ) {
num_edit - > setValue ( current_fps - > numerator ) ;
den_edit - > setValue ( current_fps - > denominator ) ;
}
layout - > addRow ( QTStr ( " Basic.Settings.Video.Numerator " ) , num_edit ) ;
layout - > addRow ( QTStr ( " Basic.Settings.Video.Denominator " ) , den_edit ) ;
widget - > setLayout ( layout ) ;
return widget ;
}
static OBSFrameRatePropertyWidget * CreateFrameRateWidget ( obs_property_t * prop ,
bool & warning , const char * option ,
media_frames_per_second * current_fps ,
frame_rate_ranges_t & fps_ranges )
{
auto widget = new OBSFrameRatePropertyWidget { } ;
auto hlayout = new QHBoxLayout { } ;
hlayout - > setContentsMargins ( 0 , 0 , 0 , 0 ) ;
swap ( widget - > fps_ranges , fps_ranges ) ;
auto combo = widget - > modeSelect = new QComboBox { } ;
combo - > addItem ( QTStr ( " Basic.PropertiesView.FPS.Simple " ) ,
QVariant : : fromValue ( frame_rate_tag : : simple ( ) ) ) ;
combo - > addItem ( QTStr ( " Basic.PropertiesView.FPS.Rational " ) ,
QVariant : : fromValue ( frame_rate_tag : : rational ( ) ) ) ;
auto num = obs_property_frame_rate_options_count ( prop ) ;
if ( num )
combo - > insertSeparator ( combo - > count ( ) ) ;
bool option_found = false ;
for ( size_t i = 0 ; i < num ; i + + ) {
auto name = obs_property_frame_rate_option_name ( prop , i ) ;
auto desc = obs_property_frame_rate_option_description ( prop , i ) ;
combo - > addItem ( desc , QVariant : : fromValue ( frame_rate_tag { name } ) ) ;
if ( ! name | | ! option | | string ( name ) ! = option )
continue ;
option_found = true ;
combo - > setCurrentIndex ( combo - > count ( ) - 1 ) ;
}
hlayout - > addWidget ( combo , 0 , Qt : : AlignTop ) ;
auto stack = widget - > modeDisplay = new QStackedWidget { } ;
bool match_found = option_found ;
auto AddWidget = [ & ] ( decltype ( CreateRationalFPS ) func )
{
bool selected = false ;
stack - > addWidget ( func ( widget , selected , current_fps ) ) ;
if ( match_found | | ! selected )
return ;
match_found = true ;
stack - > setCurrentIndex ( stack - > count ( ) - 1 ) ;
combo - > setCurrentIndex ( stack - > count ( ) - 1 ) ;
} ;
AddWidget ( CreateSimpleFPSValues ) ;
AddWidget ( CreateRationalFPS ) ;
stack - > addWidget ( new QWidget { } ) ;
if ( option_found )
stack - > setCurrentIndex ( stack - > count ( ) - 1 ) ;
else if ( ! match_found ) {
int idx = current_fps ? 1 : 0 ; // Rational for "unsupported"
// Simple as default
stack - > setCurrentIndex ( idx ) ;
combo - > setCurrentIndex ( idx ) ;
warning = true ;
}
hlayout - > addWidget ( stack , 0 , Qt : : AlignTop ) ;
auto label_area = widget - > labels = new QWidget { } ;
label_area - > setSizePolicy ( QSizePolicy : : Expanding ,
QSizePolicy : : Expanding ) ;
auto vlayout = new QVBoxLayout { } ;
vlayout - > setContentsMargins ( 0 , 0 , 0 , 0 ) ;
auto fps_label = widget - > currentFPS = new QLabel { " FPS: 22 " } ;
auto time_label = widget - > timePerFrame =
new QLabel { " Frame Interval: 0.123 ms " } ;
auto min_label = widget - > minLabel = new QLabel { " Min FPS: 1/1 " } ;
auto max_label = widget - > maxLabel = new QLabel { " Max FPS: 2/1 " } ;
min_label - > setHidden ( true ) ;
max_label - > setHidden ( true ) ;
auto flags = Qt : : TextSelectableByMouse | Qt : : TextSelectableByKeyboard ;
min_label - > setTextInteractionFlags ( flags ) ;
max_label - > setTextInteractionFlags ( flags ) ;
vlayout - > addWidget ( fps_label ) ;
vlayout - > addWidget ( time_label ) ;
vlayout - > addWidget ( min_label ) ;
vlayout - > addWidget ( max_label ) ;
label_area - > setLayout ( vlayout ) ;
hlayout - > addWidget ( label_area , 0 , Qt : : AlignTop ) ;
widget - > setLayout ( hlayout ) ;
return widget ;
}
static void UpdateMinMaxLabels ( OBSFrameRatePropertyWidget * w )
{
auto Hide = [ & ] ( bool hide )
{
w - > minLabel - > setHidden ( hide ) ;
w - > maxLabel - > setHidden ( hide ) ;
} ;
auto variant = w - > modeSelect - > currentData ( ) ;
if ( ! variant . canConvert < frame_rate_tag > ( ) | |
variant . value < frame_rate_tag > ( ) . type ! =
frame_rate_tag : : RATIONAL ) {
Hide ( true ) ;
return ;
}
variant = w - > fpsRange - > currentData ( ) ;
if ( ! variant . canConvert < size_t > ( ) ) {
Hide ( true ) ;
return ;
}
auto idx = variant . value < size_t > ( ) ;
if ( idx > = w - > fps_ranges . size ( ) ) {
Hide ( true ) ;
return ;
}
Hide ( false ) ;
auto min = w - > fps_ranges [ idx ] . first ;
auto max = w - > fps_ranges [ idx ] . second ;
w - > minLabel - > setText ( QString ( " Min FPS: %1/%2 " )
. arg ( min . numerator )
. arg ( min . denominator ) ) ;
w - > maxLabel - > setText ( QString ( " Max FPS: %1/%2 " )
. arg ( max . numerator )
. arg ( max . denominator ) ) ;
}
static void UpdateFPSLabels ( OBSFrameRatePropertyWidget * w )
{
UpdateMinMaxLabels ( w ) ;
unique_ptr < obs_data_item_t > obj {
obs_data_item_byname ( w - > settings , w - > name ) } ;
media_frames_per_second fps { } ;
media_frames_per_second * valid_fps = nullptr ;
if ( obs_data_item_get_autoselect_frames_per_second ( obj . get ( ) , & fps ,
nullptr ) | |
obs_data_item_get_frames_per_second ( obj . get ( ) , & fps ,
nullptr ) )
valid_fps = & fps ;
const char * option = nullptr ;
obs_data_item_get_frames_per_second ( obj . get ( ) , nullptr , & option ) ;
if ( ! valid_fps ) {
w - > currentFPS - > setHidden ( true ) ;
w - > timePerFrame - > setHidden ( true ) ;
if ( ! option )
w - > warningLabel - > setStyleSheet (
" QLabel { color: red; } " ) ;
return ;
}
w - > currentFPS - > setHidden ( false ) ;
w - > timePerFrame - > setHidden ( false ) ;
media_frames_per_second match { } ;
if ( ! option & & ! matches_ranges ( match , * valid_fps , w - > fps_ranges , true ) )
w - > warningLabel - > setStyleSheet ( " QLabel { color: red; } " ) ;
else
w - > warningLabel - > setStyleSheet ( " " ) ;
auto convert_to_fps = media_frames_per_second_to_fps ;
auto convert_to_frame_interval =
media_frames_per_second_to_frame_interval ;
w - > currentFPS - > setText ( QString ( " FPS: %1 " )
. arg ( convert_to_fps ( * valid_fps ) ) ) ;
w - > timePerFrame - > setText ( QString ( " Frame Interval: %1 ms " )
. arg ( convert_to_frame_interval ( * valid_fps ) * 1000 ) ) ;
}
void OBSPropertiesView : : AddFrameRate ( obs_property_t * prop , bool & warning ,
QFormLayout * layout , QLabel * & label )
{
const char * name = obs_property_name ( prop ) ;
bool enabled = obs_property_enabled ( prop ) ;
unique_ptr < obs_data_item_t > obj { obs_data_item_byname ( settings , name ) } ;
const char * option = nullptr ;
obs_data_item_get_frames_per_second ( obj . get ( ) , nullptr , & option ) ;
media_frames_per_second fps { } ;
media_frames_per_second * valid_fps = nullptr ;
if ( obs_data_item_get_frames_per_second ( obj . get ( ) , & fps , nullptr ) )
valid_fps = & fps ;
frame_rate_ranges_t fps_ranges ;
size_t num = obs_property_frame_rate_fps_ranges_count ( prop ) ;
fps_ranges . reserve ( num ) ;
for ( size_t i = 0 ; i < num ; i + + )
fps_ranges . emplace_back (
obs_property_frame_rate_fps_range_min ( prop , i ) ,
obs_property_frame_rate_fps_range_max ( prop , i ) ) ;
auto widget = CreateFrameRateWidget ( prop , warning , option , valid_fps ,
fps_ranges ) ;
auto info = new WidgetInfo ( this , prop , widget ) ;
widget - > name = name ;
widget - > settings = settings ;
widget - > modeSelect - > setEnabled ( enabled ) ;
widget - > simpleFPS - > setEnabled ( enabled ) ;
widget - > fpsRange - > setEnabled ( enabled ) ;
widget - > numEdit - > setEnabled ( enabled ) ;
widget - > denEdit - > setEnabled ( enabled ) ;
label = widget - > warningLabel =
new QLabel { obs_property_description ( prop ) } ;
layout - > addRow ( label , widget ) ;
children . emplace_back ( info ) ;
UpdateFPSLabels ( widget ) ;
auto stack = widget - > modeDisplay ;
auto combo = widget - > modeSelect ;
auto comboIndexChanged = static_cast < void ( QComboBox : : * ) ( int ) > (
& QComboBox : : currentIndexChanged ) ;
connect ( combo , comboIndexChanged , stack ,
[ = ] ( int index )
{
bool out_of_bounds = index > = stack - > count ( ) ;
auto idx = out_of_bounds ? stack - > count ( ) - 1 : index ;
stack - > setCurrentIndex ( idx ) ;
if ( widget - > updating )
return ;
UpdateFPSLabels ( widget ) ;
emit info - > ControlChanged ( ) ;
} ) ;
connect ( widget - > simpleFPS , comboIndexChanged , [ = ] ( int )
{
if ( widget - > updating )
return ;
emit info - > ControlChanged ( ) ;
} ) ;
connect ( widget - > fpsRange , comboIndexChanged , [ = ] ( int )
{
if ( widget - > updating )
return ;
UpdateFPSLabels ( widget ) ;
} ) ;
auto sbValueChanged = static_cast < void ( QSpinBox : : * ) ( int ) > (
& QSpinBox : : valueChanged ) ;
connect ( widget - > numEdit , sbValueChanged , [ = ] ( int )
{
if ( widget - > updating )
return ;
emit info - > ControlChanged ( ) ;
} ) ;
connect ( widget - > denEdit , sbValueChanged , [ = ] ( int )
{
if ( widget - > updating )
return ;
emit info - > ControlChanged ( ) ;
} ) ;
}
void OBSPropertiesView : : AddProperty ( obs_property_t * property ,
QFormLayout * layout )
{
@@ -680,6 +1303,9 @@ void OBSPropertiesView::AddProperty(obs_property_t *property,
case OBS_PROPERTY_EDITABLE_LIST :
AddEditableList ( property , layout , label ) ;
break ;
case OBS_PROPERTY_FRAME_RATE :
AddFrameRate ( property , warning , layout , label ) ;
break ;
}
if ( widget & & ! obs_property_enabled ( property ) )
@@ -713,6 +1339,112 @@ void OBSPropertiesView::SignalChanged()
emit Changed ( ) ;
}
static bool FrameRateChangedVariant ( const QVariant & variant ,
media_frames_per_second & fps , obs_data_item_t * & obj ,
const media_frames_per_second * valid_fps )
{
if ( ! variant . canConvert < media_frames_per_second > ( ) )
return false ;
fps = variant . value < media_frames_per_second > ( ) ;
if ( valid_fps & & fps = = * valid_fps )
return false ;
obs_data_item_set_frames_per_second ( & obj , fps , nullptr ) ;
return true ;
}
static bool FrameRateChangedCommon ( OBSFrameRatePropertyWidget * w ,
obs_data_item_t * & obj , const media_frames_per_second * valid_fps )
{
media_frames_per_second fps { } ;
if ( ! FrameRateChangedVariant ( w - > simpleFPS - > currentData ( ) , fps , obj ,
valid_fps ) )
return false ;
UpdateRationalFPSWidgets ( w , & fps ) ;
return true ;
}
static bool FrameRateChangedRational ( OBSFrameRatePropertyWidget * w ,
obs_data_item_t * & obj , const media_frames_per_second * valid_fps )
{
auto num = w - > numEdit - > value ( ) ;
auto den = w - > denEdit - > value ( ) ;
auto fps = make_fps ( num , den ) ;
if ( valid_fps & & media_frames_per_second_is_valid ( fps ) & &
fps = = * valid_fps )
return false ;
obs_data_item_set_frames_per_second ( & obj , fps , nullptr ) ;
UpdateSimpleFPSSelection ( w , & fps ) ;
return true ;
}
static bool FrameRateChanged ( QWidget * widget , const char * name ,
OBSData & settings )
{
auto w = qobject_cast < OBSFrameRatePropertyWidget * > ( widget ) ;
if ( ! w )
return false ;
auto variant = w - > modeSelect - > currentData ( ) ;
if ( ! variant . canConvert < frame_rate_tag > ( ) )
return false ;
auto StopUpdating = [ & ] ( void * )
{
w - > updating = false ;
} ;
unique_ptr < void , decltype ( StopUpdating ) > signalGuard (
static_cast < void * > ( w ) , StopUpdating ) ;
w - > updating = true ;
if ( ! obs_data_has_user_value ( settings , name ) )
obs_data_set_obj ( settings , name , nullptr ) ;
unique_ptr < obs_data_item_t > obj { obs_data_item_byname ( settings , name ) } ;
auto obj_ptr = obj . get ( ) ;
auto CheckObj = [ & ] ( )
{
if ( ! obj_ptr )
obj . release ( ) ;
} ;
const char * option = nullptr ;
obs_data_item_get_frames_per_second ( obj . get ( ) , nullptr , & option ) ;
media_frames_per_second fps { } ;
media_frames_per_second * valid_fps = nullptr ;
if ( obs_data_item_get_frames_per_second ( obj . get ( ) , & fps , nullptr ) )
valid_fps = & fps ;
auto tag = variant . value < frame_rate_tag > ( ) ;
switch ( tag . type ) {
case frame_rate_tag : : SIMPLE :
if ( ! FrameRateChangedCommon ( w , obj_ptr , valid_fps ) )
return false ;
break ;
case frame_rate_tag : : RATIONAL :
if ( ! FrameRateChangedRational ( w , obj_ptr , valid_fps ) )
return false ;
break ;
case frame_rate_tag : : USER :
if ( tag . val & & option & & strcmp ( tag . val , option ) = = 0 )
return false ;
obs_data_item_set_frames_per_second ( & obj_ptr , { } , tag . val ) ;
break ;
}
UpdateFPSLabels ( w ) ;
CheckObj ( ) ;
return true ;
}
void WidgetInfo : : BoolChanged ( const char * setting )
{
QCheckBox * checkbox = static_cast < QCheckBox * > ( widget ) ;
@@ -938,6 +1670,10 @@ void WidgetInfo::ControlChanged()
return ;
break ;
case OBS_PROPERTY_EDITABLE_LIST : return ;
case OBS_PROPERTY_FRAME_RATE :
if ( ! FrameRateChanged ( widget , setting , view - > settings ) )
return ;
break ;
}
if ( view - > callback & & ! view - > deferUpdate )