未验证 提交 c27a8e7a 编写于 作者: J Jim 提交者: GitHub

Merge pull request #1664 from Xaymar/feature-property-groups

libobs/UI: Add Property Grouping
......@@ -19,6 +19,7 @@
#include <QMenu>
#include <QStackedWidget>
#include <QDir>
#include <QGroupBox>
#include "double-slider.hpp"
#include "slider-ignorewheel.hpp"
#include "spinBox-ignorewheel.hpp"
......@@ -1332,6 +1333,44 @@ void OBSPropertiesView::AddFrameRate(obs_property_t *prop, bool &warning,
});
}
void OBSPropertiesView::AddGroup(obs_property_t *prop, QFormLayout *layout)
{
const char *name = obs_property_name(prop);
bool val = obs_data_get_bool(settings, name);
const char *desc = obs_property_description(prop);
enum obs_group_type type = obs_property_group_type(prop);
// Create GroupBox
QGroupBox *groupBox = new QGroupBox(QT_UTF8(desc));
groupBox->setCheckable(type == OBS_GROUP_CHECKABLE);
groupBox->setChecked(groupBox->isCheckable() ? val : true);
groupBox->setAccessibleName("group");
groupBox->setEnabled(obs_property_enabled(prop));
// Create Layout and build content
QFormLayout *subLayout = new QFormLayout();
subLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
groupBox->setLayout(subLayout);
obs_properties_t *content = obs_property_group_content(prop);
obs_property_t *el = obs_properties_first(content);
while (el != nullptr) {
AddProperty(el, subLayout);
obs_property_next(&el);
}
// Insert into UI
layout->setWidget(layout->rowCount(),
QFormLayout::ItemRole::SpanningRole, groupBox);
// Register Group Widget
WidgetInfo *info = new WidgetInfo(this, prop, groupBox);
children.emplace_back(info);
// Signals
connect(groupBox, SIGNAL(toggled()), info, SLOT(ControlChanged()));
}
void OBSPropertiesView::AddProperty(obs_property_t *property,
QFormLayout *layout)
{
......@@ -1381,6 +1420,8 @@ void OBSPropertiesView::AddProperty(obs_property_t *property,
case OBS_PROPERTY_FRAME_RATE:
AddFrameRate(property, warning, layout, label);
break;
case OBS_PROPERTY_GROUP:
AddGroup(property, layout);
}
if (widget && !obs_property_enabled(property))
......@@ -1388,7 +1429,8 @@ void OBSPropertiesView::AddProperty(obs_property_t *property,
if (!label &&
type != OBS_PROPERTY_BOOL &&
type != OBS_PROPERTY_BUTTON)
type != OBS_PROPERTY_BUTTON &&
type != OBS_PROPERTY_GROUP)
label = new QLabel(QT_UTF8(obs_property_description(property)));
if (warning && label) //TODO: select color based on background color
......@@ -1707,6 +1749,13 @@ bool WidgetInfo::FontChanged(const char *setting)
return true;
}
void WidgetInfo::GroupChanged(const char *setting)
{
QGroupBox *groupbox = static_cast<QGroupBox*>(widget);
obs_data_set_bool(view->settings, setting,
groupbox->isCheckable() ? groupbox->isChecked() : true);
}
void WidgetInfo::EditableListChanged()
{
const char *setting = obs_property_name(property);
......@@ -1776,6 +1825,7 @@ void WidgetInfo::ControlChanged()
if (!FrameRateChanged(widget, setting, view->settings))
return;
break;
case OBS_PROPERTY_GROUP: GroupChanged(setting); return;
}
if (view->callback && !view->deferUpdate)
......
......@@ -33,6 +33,7 @@ private:
void ListChanged(const char *setting);
bool ColorChanged(const char *setting);
bool FontChanged(const char *setting);
void GroupChanged(const char *setting);
void EditableListChanged();
void ButtonClicked();
......@@ -103,6 +104,8 @@ private:
void AddFrameRate(obs_property_t *prop, bool &warning,
QFormLayout *layout, QLabel *&label);
void AddGroup(obs_property_t *prop, QFormLayout *layout);
void AddProperty(obs_property_t *property, QFormLayout *layout);
void resizeEvent(QResizeEvent *event) override;
......
......@@ -86,6 +86,11 @@ struct frame_rate_data {
DARRAY(struct frame_rate_range) ranges;
};
struct group_data {
enum obs_group_type type;
obs_properties_t *content;
};
static inline void path_data_free(struct path_data *data)
{
bfree(data->default_path);
......@@ -140,6 +145,10 @@ static inline void frame_rate_data_free(struct frame_rate_data *data)
da_free(data->ranges);
}
static inline void group_data_free(struct group_data *data) {
obs_properties_destroy(data->content);
}
struct obs_properties;
struct obs_property {
......@@ -166,6 +175,7 @@ struct obs_properties {
struct obs_property *first_property;
struct obs_property **last;
struct obs_property *parent;
};
obs_properties_t *obs_properties_create(void)
......@@ -223,6 +233,8 @@ static void obs_property_destroy(struct obs_property *property)
editable_list_data_free(get_property_data(property));
else if (property->type == OBS_PROPERTY_FRAME_RATE)
frame_rate_data_free(get_property_data(property));
else if (property->type == OBS_PROPERTY_GROUP)
group_data_free(get_property_data(property));
bfree(property->name);
bfree(property->desc);
......@@ -265,12 +277,26 @@ obs_property_t *obs_properties_get(obs_properties_t *props, const char *name)
if (strcmp(property->name, name) == 0)
return property;
if (property->type == OBS_PROPERTY_GROUP) {
obs_properties_t *group =
obs_property_group_content(property);
obs_property_t *found = obs_properties_get(group, name);
if (found != NULL) {
return found;
}
}
property = property->next;
}
return NULL;
}
obs_properties_t *obs_properties_get_parent(obs_properties_t *props)
{
return props->parent ? props->parent->parent : NULL;
}
void obs_properties_remove_by_name(obs_properties_t *props, const char *name)
{
if (!props)
......@@ -338,6 +364,7 @@ static inline size_t get_property_size(enum obs_property_type type)
case OBS_PROPERTY_EDITABLE_LIST:
return sizeof(struct editable_list_data);
case OBS_PROPERTY_FRAME_RATE:return sizeof(struct frame_rate_data);
case OBS_PROPERTY_GROUP: return sizeof(struct group_data);
}
return 0;
......@@ -362,7 +389,18 @@ static inline struct obs_property *new_prop(struct obs_properties *props,
return p;
}
static inline bool has_prop(struct obs_properties *props, const char *name)
static inline obs_properties_t *get_topmost_parent(obs_properties_t *props)
{
obs_properties_t *parent = props;
obs_properties_t *last_parent = parent;
while (parent) {
last_parent = parent;
parent = obs_properties_get_parent(parent);
}
return last_parent;
}
static inline bool contains_prop(struct obs_properties *props, const char *name)
{
struct obs_property *p = props->first_property;
......@@ -372,12 +410,23 @@ static inline bool has_prop(struct obs_properties *props, const char *name)
return true;
}
if (p->type == OBS_PROPERTY_GROUP) {
if (contains_prop(obs_property_group_content(p), name)) {
return true;
}
}
p = p->next;
}
return false;
}
static inline bool has_prop(struct obs_properties *props, const char *name)
{
return contains_prop(get_topmost_parent(props), name);
}
static inline void *get_property_data(struct obs_property *prop)
{
return (uint8_t*)prop + sizeof(struct obs_property);
......@@ -578,6 +627,70 @@ obs_property_t *obs_properties_add_frame_rate(obs_properties_t *props,
return p;
}
static bool check_property_group_recursion(obs_properties_t *parent,
obs_properties_t *group)
{
/* Scan the group for the parent. */
obs_property_t *current_property = group->first_property;
while (current_property) {
if (current_property->type == OBS_PROPERTY_GROUP) {
obs_properties_t *cprops =
obs_property_group_content(current_property);
if (cprops == parent) {
/* Contains find_props */
return true;
} else if (cprops == group) {
/* Contains self, shouldn't be possible but
* lets verify anyway. */
return true;
}
check_property_group_recursion(cprops, group);
}
current_property = current_property->next;
}
return false;
}
static bool check_property_group_duplicates(obs_properties_t *parent,
obs_properties_t *group)
{
obs_property_t *current_property = group->first_property;
while (current_property) {
if (has_prop(parent, current_property->name)) {
return true;
}
current_property = current_property->next;
}
return false;
}
obs_property_t *obs_properties_add_group(obs_properties_t *props,
const char *name, const char *desc, enum obs_group_type type,
obs_properties_t *group)
{
if (!props || has_prop(props, name)) return NULL;
if (!group) return NULL;
/* Prevent recursion. */
if (props == group) return NULL;
if (check_property_group_recursion(props, group)) return NULL;
/* Prevent duplicate properties */
if (check_property_group_duplicates(props, group)) return NULL;
obs_property_t *p = new_prop(props, name, desc, OBS_PROPERTY_GROUP);
group->parent = p;
struct group_data *data = get_property_data(p);
data->type = type;
data->content = group;
return p;
}
/* ------------------------------------------------------------------------- */
static inline bool is_combo(struct obs_property *p)
......@@ -630,9 +743,11 @@ bool obs_property_modified(obs_property_t *p, obs_data_t *settings)
{
if (p) {
if (p->modified) {
return p->modified(p->parent, p, settings);
obs_properties_t *top = get_topmost_parent(p->parent);
return p->modified(top, p, settings);
} else if (p->modified2) {
return p->modified2(p->priv, p->parent, p, settings);
obs_properties_t *top = get_topmost_parent(p->parent);
return p->modified2(p->priv, top, p, settings);
}
}
return false;
......@@ -645,9 +760,10 @@ bool obs_property_button_clicked(obs_property_t *p, void *obj)
struct button_data *data = get_type_data(p,
OBS_PROPERTY_BUTTON);
if (data && data->callback) {
obs_properties_t *top = get_topmost_parent(p->parent);
if (p->priv)
return data->callback(p->parent, p, p->priv);
return data->callback(p->parent, p,
return data->callback(top, p, p->priv);
return data->callback(top, p,
(context ? context->data : NULL));
}
}
......@@ -1137,3 +1253,15 @@ enum obs_text_type obs_proprety_text_type(obs_property_t *p)
{
return obs_property_text_type(p);
}
enum obs_group_type obs_property_group_type(obs_property_t *p)
{
struct group_data *data = get_type_data(p, OBS_PROPERTY_GROUP);
return data ? data->type : OBS_COMBO_INVALID;
}
obs_properties_t *obs_property_group_content(obs_property_t *p)
{
struct group_data *data = get_type_data(p, OBS_PROPERTY_GROUP);
return data ? data->content : NULL;
}
......@@ -55,6 +55,7 @@ enum obs_property_type {
OBS_PROPERTY_FONT,
OBS_PROPERTY_EDITABLE_LIST,
OBS_PROPERTY_FRAME_RATE,
OBS_PROPERTY_GROUP,
};
enum obs_combo_format {
......@@ -93,6 +94,12 @@ enum obs_number_type {
OBS_NUMBER_SLIDER
};
enum obs_group_type {
OBS_COMBO_INVALID,
OBS_GROUP_NORMAL,
OBS_GROUP_CHECKABLE,
};
#define OBS_FONT_BOLD (1<<0)
#define OBS_FONT_ITALIC (1<<1)
#define OBS_FONT_UNDERLINE (1<<2)
......@@ -122,6 +129,8 @@ EXPORT obs_property_t *obs_properties_first(obs_properties_t *props);
EXPORT obs_property_t *obs_properties_get(obs_properties_t *props,
const char *property);
EXPORT obs_properties_t *obs_properties_get_parent(obs_properties_t *props);
/** Remove a property from a properties list.
*
* Removes a property from a properties list. Only valid in either
......@@ -231,6 +240,11 @@ EXPORT obs_property_t *obs_properties_add_editable_list(obs_properties_t *props,
EXPORT obs_property_t *obs_properties_add_frame_rate(obs_properties_t *props,
const char *name, const char *description);
EXPORT obs_property_t *obs_properties_add_group(obs_properties_t *props,
const char *name, const char *description, enum obs_group_type type,
obs_properties_t *group);
/* ------------------------------------------------------------------------- */
/**
......@@ -349,6 +363,9 @@ EXPORT struct media_frames_per_second obs_property_frame_rate_fps_range_min(
EXPORT struct media_frames_per_second obs_property_frame_rate_fps_range_max(
obs_property_t *p, size_t idx);
EXPORT enum obs_group_type obs_property_group_type(obs_property_t *p);
EXPORT obs_properties_t *obs_property_group_content(obs_property_t *p);
#ifndef SWIG
DEPRECATED
EXPORT enum obs_text_type obs_proprety_text_type(obs_property_t *p);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册