UI, libobs: Add ability to lock individual scene items

Adds a lock checkbox to allow the user to lock a specific scene item.

Closes jp9000/obs-studio#949
This commit is contained in:
cg2121 2017-06-17 19:10:42 -05:00 committed by jp9000
parent 5c2328cca2
commit fce078d997
13 changed files with 144 additions and 0 deletions

View file

@ -161,6 +161,7 @@ set(obs_SOURCES
adv-audio-control.cpp
item-widget-helpers.cpp
visibility-checkbox.cpp
locked-checkbox.cpp
vertical-scroll-area.cpp
visibility-item-widget.cpp
slider-absoluteset-style.cpp
@ -208,6 +209,7 @@ set(obs_HEADERS
adv-audio-control.hpp
item-widget-helpers.hpp
visibility-checkbox.hpp
locked-checkbox.hpp
vertical-scroll-area.hpp
visibility-item-widget.hpp
slider-absoluteset-style.hpp

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

View file

@ -14,6 +14,8 @@
<file>images/up.png</file>
<file>images/obs.png</file>
<file>images/tray_active.png</file>
<file>images/locked_mask.png</file>
<file>images/unlocked_mask.png</file>
</qresource>
<qresource prefix="/settings">
<file>images/settings/advanced.png</file>

36
UI/locked-checkbox.cpp Normal file
View file

@ -0,0 +1,36 @@
#include <QPaintEvent>
#include <QPixmap>
#include <QPainter>
#include "locked-checkbox.hpp"
#include <util/c99defs.h>
LockedCheckBox::LockedCheckBox() : QCheckBox()
{
lockedImage =
QPixmap::fromImage(QImage(":/res/images/locked_mask.png"));
unlockedImage =
QPixmap::fromImage(QImage(":/res/images/unlocked_mask.png"));
setMinimumSize(16, 16);
setStyleSheet("outline: none;");
}
void LockedCheckBox::paintEvent(QPaintEvent *event)
{
UNUSED_PARAMETER(event);
QPixmap &pixmap = isChecked() ? lockedImage : unlockedImage;
QImage image(pixmap.size(), QImage::Format_ARGB32);
QPainter draw(&image);
draw.setCompositionMode(QPainter::CompositionMode_Source);
draw.drawPixmap(0, 0, pixmap.width(), pixmap.height(), pixmap);
draw.setCompositionMode(QPainter::CompositionMode_SourceIn);
draw.fillRect(QRectF(QPointF(0.0f, 0.0f), pixmap.size()),
palette().color(foregroundRole()));
QPainter p(this);
p.drawPixmap(0, 0, image.width(), image.height(),
QPixmap::fromImage(image));
}

17
UI/locked-checkbox.hpp Normal file
View file

@ -0,0 +1,17 @@
#include <QCheckBox>
#include <QPixmap>
class QPaintEvernt;
class LockedCheckBox : public QCheckBox {
Q_OBJECT
QPixmap lockedImage;
QPixmap unlockedImage;
public:
LockedCheckBox();
protected:
void paintEvent(QPaintEvent *event) override;
};

View file

@ -1,5 +1,6 @@
#include "visibility-item-widget.hpp"
#include "visibility-checkbox.hpp"
#include "locked-checkbox.hpp"
#include "qt-wrappers.hpp"
#include "obs-app.hpp"
#include <QListWidget>
@ -49,6 +50,7 @@ VisibilityItemWidget::VisibilityItemWidget(obs_sceneitem_t *item_)
{
const char *name = obs_source_get_name(source);
bool enabled = obs_sceneitem_visible(item);
bool locked = obs_sceneitem_locked(item);
obs_scene_t *scene = obs_sceneitem_get_scene(item);
obs_source_t *sceneSource = obs_scene_get_source(scene);
@ -60,13 +62,23 @@ VisibilityItemWidget::VisibilityItemWidget(obs_sceneitem_t *item_)
#endif
vis->setChecked(enabled);
lock = new LockedCheckBox();
lock->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
/* Fix for non-apple systems where the spacing would be too big */
#ifndef __APPLE__
lock->setMaximumSize(16, 16);
#endif
lock->setChecked(locked);
label = new QLabel(QT_UTF8(name));
label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
QHBoxLayout *itemLayout = new QHBoxLayout();
itemLayout->addWidget(vis);
itemLayout->addWidget(lock);
itemLayout->addWidget(label);
itemLayout->setContentsMargins(5, 2, 5, 2);
itemLayout->setSpacing(2);
setLayout(itemLayout);
setStyleSheet("background-color: rgba(255, 255, 255, 0);");
@ -80,6 +92,9 @@ VisibilityItemWidget::VisibilityItemWidget(obs_sceneitem_t *item_)
connect(vis, SIGNAL(clicked(bool)),
this, SLOT(VisibilityClicked(bool)));
connect(lock, SIGNAL(clicked(bool)),
this, SLOT(LockClicked(bool)));
}
VisibilityItemWidget::~VisibilityItemWidget()
@ -137,6 +152,18 @@ void VisibilityItemWidget::OBSSceneItemVisible(void *param, calldata_t *data)
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");
bool locked = calldata_bool(data, "locked");
if (window->item == curItem)
QMetaObject::invokeMethod(window, "SourceLocked",
Q_ARG(bool, locked));
}
void VisibilityItemWidget::OBSSourceEnabled(void *param, calldata_t *data)
{
VisibilityItemWidget *window =
@ -165,12 +192,24 @@ void VisibilityItemWidget::VisibilityClicked(bool visible)
obs_source_set_enabled(source, visible);
}
void VisibilityItemWidget::LockClicked(bool locked)
{
if (item)
obs_sceneitem_set_locked(item, locked);
}
void VisibilityItemWidget::SourceEnabled(bool enabled)
{
if (vis->isChecked() != enabled)
vis->setChecked(enabled);
}
void VisibilityItemWidget::SourceLocked(bool locked)
{
if (lock->isChecked() != locked)
lock->setChecked(locked);
}
void VisibilityItemWidget::SourceRenamed(QString name)
{
if (label && name != label->text())

View file

@ -9,6 +9,7 @@ class QLineEdit;
class QListWidget;
class QListWidgetItem;
class VisibilityCheckBox;
class LockedCheckBox;
class VisibilityItemWidget : public QWidget {
Q_OBJECT
@ -18,6 +19,7 @@ private:
OBSSource source;
QLabel *label = nullptr;
VisibilityCheckBox *vis = nullptr;
LockedCheckBox *lock = nullptr;
QString oldName;
OBSSignal sceneRemoveSignal;
@ -31,6 +33,7 @@ private:
static void OBSSceneRemove(void *param, calldata_t *data);
static void OBSSceneItemRemove(void *param, calldata_t *data);
static void OBSSceneItemVisible(void *param, calldata_t *data);
static void OBSSceneItemLocked(void *param, calldata_t *data);
static void OBSSourceEnabled(void *param, calldata_t *data);
static void OBSSourceRenamed(void *param, calldata_t *data);
@ -38,8 +41,10 @@ private:
private slots:
void VisibilityClicked(bool visible);
void LockClicked(bool locked);
void SourceEnabled(bool enabled);
void SourceRenamed(QString name);
void SourceLocked(bool locked);
public:
VisibilityItemWidget(obs_source_t *source);

View file

@ -5004,6 +5004,9 @@ void OBSBasic::Nudge(int dist, MoveDir dir)
auto func = [] (obs_scene_t*, obs_sceneitem_t *item, void *param)
{
if (obs_sceneitem_locked(item))
return true;
MoveInfo *info = reinterpret_cast<MoveInfo*>(param);
struct vec2 dir;
struct vec2 pos;

View file

@ -75,6 +75,8 @@ static bool FindItemAtPos(obs_scene_t *scene, obs_sceneitem_t *item,
if (!SceneItemHasVideo(item))
return true;
if (obs_sceneitem_locked(item))
return true;
vec3_set(&pos3, data->pos.x, data->pos.y, 0.0f);
@ -674,6 +676,9 @@ void OBSBasicPreview::SnapItemMovement(vec2 &offset)
static bool move_items(obs_scene_t *scene, obs_sceneitem_t *item, void *param)
{
if (obs_sceneitem_locked(item))
return true;
vec2 *offset = reinterpret_cast<vec2*>(param);
if (obs_sceneitem_selected(item)) {
@ -1084,6 +1089,9 @@ static inline bool crop_enabled(const obs_sceneitem_crop *crop)
bool OBSBasicPreview::DrawSelectedItem(obs_scene_t *scene,
obs_sceneitem_t *item, void *param)
{
if (obs_sceneitem_locked(item))
return true;
if (!obs_sceneitem_selected(item))
return true;
@ -1183,6 +1191,7 @@ void OBSBasicPreview::DrawSceneEditing()
gs_technique_begin_pass(tech, 0);
OBSScene scene = main->GetCurrentScene();
if (scene)
obs_scene_enum_items(scene, DrawSelectedItem, this);

View file

@ -590,6 +590,7 @@ static void scene_load_item(struct obs_scene *scene, obs_data_t *item_data)
const char *scale_filter_str;
struct obs_scene_item *item;
bool visible;
bool lock;
if (!source) {
blog(LOG_WARNING, "[scene_load_item] Source %s not found!",
@ -616,10 +617,12 @@ static void scene_load_item(struct obs_scene *scene, obs_data_t *item_data)
item->rot = (float)obs_data_get_double(item_data, "rot");
item->align = (uint32_t)obs_data_get_int(item_data, "align");
visible = obs_data_get_bool(item_data, "visible");
lock = obs_data_get_bool(item_data, "locked");
obs_data_get_vec2(item_data, "pos", &item->pos);
obs_data_get_vec2(item_data, "scale", &item->scale);
set_visibility(item, visible);
obs_sceneitem_set_locked(item, lock);
item->bounds_type =
(enum obs_bounds_type)obs_data_get_int(item_data,
@ -697,6 +700,7 @@ static void scene_save_item(obs_data_array_t *array,
obs_data_set_string(item_data, "name", name);
obs_data_set_bool (item_data, "visible", item->user_visible);
obs_data_set_bool (item_data, "locked", item->locked);
obs_data_set_double(item_data, "rot", item->rot);
obs_data_set_vec2 (item_data, "pos", &item->pos);
obs_data_set_vec2 (item_data, "scale", &item->scale);
@ -1347,6 +1351,7 @@ obs_sceneitem_t *obs_scene_add(obs_scene_t *scene, obs_source_t *source)
item->align = OBS_ALIGN_TOP | OBS_ALIGN_LEFT;
item->actions_mutex = mutex;
item->user_visible = true;
item->locked = false;
os_atomic_set_long(&item->active_refs, 1);
vec2_set(&item->scale, 1.0f, 1.0f);
matrix4_identity(&item->draw_transform);
@ -1773,6 +1778,27 @@ bool obs_sceneitem_set_visible(obs_sceneitem_t *item, bool visible)
return true;
}
bool obs_sceneitem_locked(const obs_sceneitem_t *item)
{
return item ? item->locked : false;
}
bool obs_sceneitem_set_locked(obs_sceneitem_t *item, bool lock)
{
if (!item)
return false;
if (item->locked == lock)
return false;
if (!item->parent)
return false;
item->locked = lock;
return true;
}
static bool sceneitems_match(obs_scene_t *scene, obs_sceneitem_t * const *items,
size_t size, bool *order_matches)
{

View file

@ -41,6 +41,7 @@ struct obs_scene_item {
bool user_visible;
bool visible;
bool selected;
bool locked;
gs_texrender_t *item_render;
struct obs_sceneitem_crop crop;

View file

@ -1251,8 +1251,12 @@ EXPORT obs_scene_t *obs_sceneitem_get_scene(const obs_sceneitem_t *item);
/** Gets the source of a scene item. */
EXPORT obs_source_t *obs_sceneitem_get_source(const obs_sceneitem_t *item);
/* FIXME: The following functions should be deprecated and replaced with a way
* to specify savable private user data. -Jim */
EXPORT void obs_sceneitem_select(obs_sceneitem_t *item, bool select);
EXPORT bool obs_sceneitem_selected(const obs_sceneitem_t *item);
EXPORT bool obs_sceneitem_locked(const obs_sceneitem_t *item);
EXPORT bool obs_sceneitem_set_locked(obs_sceneitem_t *item, bool lock);
/* Functions for getting/setting specific orientation of a scene item */
EXPORT void obs_sceneitem_set_pos(obs_sceneitem_t *item, const struct vec2 *pos);