UI: Add grouping

This commit is contained in:
jp9000
2018-06-04 04:01:39 -07:00
parent 46cce067f0
commit 88b6c63964
19 changed files with 1769 additions and 245 deletions
+75 -206
View File
@@ -54,6 +54,7 @@
#include "display-helpers.hpp"
#include "volume-control.hpp"
#include "remote-text.hpp"
#include "source-tree.hpp"
#ifdef _WIN32
#include "win-update/win-update.hpp"
@@ -148,8 +149,6 @@ OBSBasic::OBSBasic(QWidget *parent)
copyActionsDynamicProperties();
ui->sources->setItemDelegate(new VisibilityItemDelegate(ui->sources));
char styleSheetPath[512];
int ret = GetProfilePath(styleSheetPath, sizeof(styleSheetPath),
"stylesheet.qss");
@@ -201,13 +200,6 @@ OBSBasic::OBSBasic(QWidget *parent)
SLOT(SceneNameEdited(QWidget*,
QAbstractItemDelegate::EndEditHint)));
connect(ui->sources->itemDelegate(),
SIGNAL(closeEditor(QWidget*,
QAbstractItemDelegate::EndEditHint)),
this,
SLOT(SceneItemNameEdited(QWidget*,
QAbstractItemDelegate::EndEditHint)));
cpuUsageInfo = os_cpu_usage_info_start();
cpuUsageTimer = new QTimer(this);
connect(cpuUsageTimer, SIGNAL(timeout()),
@@ -2024,7 +2016,7 @@ OBSSceneItem OBSBasic::GetSceneItem(QListWidgetItem *item)
OBSSceneItem OBSBasic::GetCurrentSceneItem()
{
return GetSceneItem(GetTopSelectedSourceItem());
return ui->sources->Get(GetTopSelectedSourceItem());
}
void OBSBasic::UpdatePreviewScalingMenu()
@@ -2047,32 +2039,6 @@ void OBSBasic::UpdatePreviewScalingMenu()
scalingAmount == float(ovi.output_width) / float(ovi.base_width));
}
void OBSBasic::UpdateSources(OBSScene scene)
{
ClearListItems(ui->sources);
obs_scene_enum_items(scene,
[] (obs_scene_t *scene, obs_sceneitem_t *item, void *p)
{
OBSBasic *window = static_cast<OBSBasic*>(p);
window->InsertSceneItem(item);
UNUSED_PARAMETER(scene);
return true;
}, this);
}
void OBSBasic::InsertSceneItem(obs_sceneitem_t *item)
{
QListWidgetItem *listItem = new QListWidgetItem();
SetOBSRef(listItem, OBSSceneItem(item));
ui->sources->insertItem(0, listItem);
ui->sources->setCurrentRow(0, QItemSelectionModel::ClearAndSelect);
SetupVisibilityItem(ui->sources, listItem, item);
}
void OBSBasic::CreateInteractionWindow(obs_source_t *source)
{
if (interaction)
@@ -2199,7 +2165,7 @@ void OBSBasic::RemoveScene(OBSSource source)
if (sel != nullptr) {
if (sel == ui->scenes->currentItem())
ClearListItems(ui->sources);
ui->sources->Clear();
delete sel;
}
@@ -2221,7 +2187,7 @@ void OBSBasic::AddSceneItem(OBSSceneItem item)
obs_scene_t *scene = obs_sceneitem_get_scene(item);
if (GetCurrentScene() == scene)
InsertSceneItem(item);
ui->sources->Add(item);
SaveProject();
@@ -2237,14 +2203,7 @@ void OBSBasic::AddSceneItem(OBSSceneItem item)
void OBSBasic::RemoveSceneItem(OBSSceneItem item)
{
for (int i = 0; i < ui->sources->count(); i++) {
QListWidgetItem *listItem = ui->sources->item(i);
if (GetOBSRef<OBSSceneItem>(listItem) == item) {
DeleteListItem(ui->sources, listItem);
break;
}
}
ui->sources->Remove(item);
SaveProject();
@@ -2276,8 +2235,6 @@ void OBSBasic::UpdateSceneSelection(OBSSource source)
ui->scenes->setCurrentItem(items.first());
sceneChanging = false;
UpdateSources(scene);
OBSScene curScene =
GetOBSRef<OBSScene>(ui->scenes->currentItem());
if (api && scene != curScene)
@@ -2322,19 +2279,7 @@ void OBSBasic::SelectSceneItem(OBSScene scene, OBSSceneItem item, bool select)
if (scene != GetCurrentScene() || ignoreSelectionUpdate)
return;
for (int i = 0; i < ui->sources->count(); i++) {
QListWidgetItem *witem = ui->sources->item(i);
QVariant data =
witem->data(static_cast<int>(QtDataRole::OBSRef));
if (!data.canConvert<OBSSceneItem>())
continue;
if (item != data.value<OBSSceneItem>())
continue;
witem->setSelected(select);
break;
}
ui->sources->SelectItem(item, select);
}
static inline bool SourceMixerHidden(obs_source_t *source)
@@ -2664,7 +2609,8 @@ void OBSBasic::DeactivateAudioSource(OBSSource source)
bool OBSBasic::QueryRemoveSource(obs_source_t *source)
{
if (obs_source_get_type(source) == OBS_SOURCE_TYPE_SCENE) {
if (obs_source_get_type(source) == OBS_SOURCE_TYPE_SCENE &&
!obs_sceneitem_group_from_source(source)) {
int count = ui->scenes->count();
if (count == 1) {
@@ -2830,62 +2776,12 @@ void OBSBasic::RemoveSelectedSceneItem()
}
}
struct ReorderInfo {
int idx = 0;
OBSBasic *window;
inline ReorderInfo(OBSBasic *window_) : window(window_) {}
};
void OBSBasic::ReorderSceneItem(obs_sceneitem_t *item, size_t idx)
{
int count = ui->sources->count();
int idx_inv = count - (int)idx - 1;
for (int i = 0; i < count; i++) {
QListWidgetItem *listItem = ui->sources->item(i);
OBSSceneItem sceneItem = GetOBSRef<OBSSceneItem>(listItem);
if (sceneItem == item) {
if ((int)idx_inv != i) {
bool sel = (ui->sources->currentRow() == i);
listItem = TakeListItem(ui->sources, i);
if (listItem) {
ui->sources->insertItem(idx_inv,
listItem);
SetupVisibilityItem(ui->sources,
listItem, item);
if (sel)
ui->sources->setCurrentRow(
idx_inv);
}
}
break;
}
}
}
void OBSBasic::ReorderSources(OBSScene scene)
{
ReorderInfo info(this);
if (scene != GetCurrentScene() || ui->sources->IgnoreReorder())
return;
obs_scene_enum_items(scene,
[] (obs_scene_t*, obs_sceneitem_t *item, void *p)
{
ReorderInfo *info =
reinterpret_cast<ReorderInfo*>(p);
info->window->ReorderSceneItem(item,
info->idx++);
return true;
}, &info);
ui->sources->ReorderItems();
SaveProject();
}
@@ -3410,7 +3306,7 @@ void OBSBasic::ClearSceneData()
ClearVolumeControls();
ClearListItems(ui->scenes);
ClearListItems(ui->sources);
ui->sources->Clear();
ClearQuickTransitions();
ui->transitions->clear();
@@ -3800,44 +3696,10 @@ void OBSBasic::MoveSceneToBottom()
ui->scenes->count() - 1);
}
void OBSBasic::on_sources_itemSelectionChanged()
{
SignalBlocker sourcesSignalBlocker(ui->sources);
auto updateItemSelection = [&]()
{
ignoreSelectionUpdate = true;
for (int i = 0; i < ui->sources->count(); i++)
{
QListWidgetItem *wItem = ui->sources->item(i);
OBSSceneItem item = GetOBSRef<OBSSceneItem>(wItem);
obs_sceneitem_select(item, wItem->isSelected());
}
ignoreSelectionUpdate = false;
};
using updateItemSelection_t = decltype(updateItemSelection);
obs_scene_atomic_update(GetCurrentScene(),
[](void *data, obs_scene_t *)
{
(*static_cast<updateItemSelection_t*>(data))();
}, static_cast<void*>(&updateItemSelection));
}
void OBSBasic::EditSceneItemName()
{
QListWidgetItem *item = GetTopSelectedSourceItem();
Qt::ItemFlags flags = item->flags();
OBSSceneItem sceneItem= GetOBSRef<OBSSceneItem>(item);
obs_source_t *source = obs_sceneitem_get_source(sceneItem);
const char *name = obs_source_get_name(source);
item->setText(QT_UTF8(name));
item->setFlags(flags | Qt::ItemIsEditable);
ui->sources->removeItemWidget(item);
ui->sources->editItem(item);
item->setFlags(flags);
int idx = GetTopSelectedSourceItem();
ui->sources->Edit(idx);
}
void OBSBasic::SetDeinterlacingMode()
@@ -3937,7 +3799,7 @@ QMenu *OBSBasic::AddScaleFilteringMenu(obs_sceneitem_t *item)
return menu;
}
void OBSBasic::CreateSourcePopupMenu(QListWidgetItem *item, bool preview)
void OBSBasic::CreateSourcePopupMenu(int idx, bool preview)
{
QMenu popup(this);
QPointer<QMenu> previewProjector;
@@ -3978,6 +3840,17 @@ void OBSBasic::CreateSourcePopupMenu(QListWidgetItem *item, bool preview)
ui->actionCopyFilters->setEnabled(false);
ui->actionCopySource->setEnabled(false);
if (ui->sources->MultipleBaseSelected()) {
popup.addSeparator();
popup.addAction(QTStr("Basic.Main.GroupItems"),
ui->sources, SLOT(GroupSelectedItems()));
} else if (ui->sources->GroupsSelected()) {
popup.addSeparator();
popup.addAction(QTStr("Basic.Main.Ungroup"),
ui->sources, SLOT(UngroupSelectedGroups()));
}
popup.addSeparator();
popup.addAction(ui->actionCopySource);
popup.addAction(ui->actionPasteRef);
@@ -3989,11 +3862,11 @@ void OBSBasic::CreateSourcePopupMenu(QListWidgetItem *item, bool preview)
popup.addAction(ui->actionPasteFilters);
popup.addSeparator();
if (item) {
if (idx != -1) {
if (addSourceMenu)
popup.addSeparator();
OBSSceneItem sceneItem = GetSceneItem(item);
OBSSceneItem sceneItem = ui->sources->Get(idx);
obs_source_t *source = obs_sceneitem_get_source(sceneItem);
uint32_t flags = obs_source_get_output_flags(source);
bool isAsyncVideo = (flags & OBS_SOURCE_ASYNC_VIDEO) ==
@@ -4064,20 +3937,10 @@ void OBSBasic::CreateSourcePopupMenu(QListWidgetItem *item, bool preview)
void OBSBasic::on_sources_customContextMenuRequested(const QPoint &pos)
{
if (ui->scenes->count())
CreateSourcePopupMenu(ui->sources->itemAt(pos), false);
}
void OBSBasic::on_sources_itemDoubleClicked(QListWidgetItem *witem)
{
if (!witem)
return;
OBSSceneItem item = GetSceneItem(witem);
OBSSource source = obs_sceneitem_get_source(item);
if (source)
CreatePropertiesWindow(source);
if (ui->scenes->count()) {
QModelIndex idx = ui->sources->indexAt(pos);
CreateSourcePopupMenu(idx.row(), false);
}
}
void OBSBasic::on_scenes_itemDoubleClicked(QListWidgetItem *witem)
@@ -4161,6 +4024,12 @@ QMenu *OBSBasic::CreateAddSourcePopupMenu()
addSource(popup, "scene", Str("Basic.Scene"));
popup->addSeparator();
QAction *addGroup = new QAction(QTStr("Group"), this);
connect(addGroup, SIGNAL(triggered(bool)),
ui->sources, SLOT(AddGroup()));
popup->addAction(addGroup);
if (!foundDeprecated) {
delete deprecated;
deprecated = nullptr;
@@ -4171,6 +4040,7 @@ QMenu *OBSBasic::CreateAddSourcePopupMenu()
popup = nullptr;
} else if (foundDeprecated) {
popup->addSeparator();
popup->addMenu(deprecated);
}
@@ -4206,20 +4076,24 @@ void OBSBasic::on_actionAddSource_triggered()
AddSourcePopupMenu(QCursor::pos());
}
static bool remove_items(obs_scene_t *, obs_sceneitem_t *item, void *param)
{
vector<OBSSceneItem> &items =
*reinterpret_cast<vector<OBSSceneItem>*>(param);
if (obs_sceneitem_selected(item)) {
items.emplace_back(item);
} else if (obs_sceneitem_is_group(item)) {
obs_sceneitem_group_enum_items(item, remove_items, &items);
}
return true;
};
void OBSBasic::on_actionRemoveSource_triggered()
{
vector<OBSSceneItem> items;
auto func = [] (obs_scene_t *, obs_sceneitem_t *item, void *param)
{
vector<OBSSceneItem> &items =
*reinterpret_cast<vector<OBSSceneItem>*>(param);
if (obs_sceneitem_selected(item))
items.emplace_back(item);
return true;
};
obs_scene_enum_items(GetCurrentScene(), func, &items);
obs_scene_enum_items(GetCurrentScene(), remove_items, &items);
if (!items.size())
return;
@@ -4484,26 +4358,6 @@ void OBSBasic::SceneNameEdited(QWidget *editor,
UNUSED_PARAMETER(endHint);
}
void OBSBasic::SceneItemNameEdited(QWidget *editor,
QAbstractItemDelegate::EndEditHint endHint)
{
OBSSceneItem item = GetCurrentSceneItem();
QLineEdit *edit = qobject_cast<QLineEdit*>(editor);
string text = QT_TO_UTF8(edit->text().trimmed());
if (!item)
return;
obs_source_t *source = obs_sceneitem_get_source(item);
RenameListItem(this, ui->sources, source, text);
QListWidgetItem *listItem = ui->sources->currentItem();
listItem->setText(QString());
SetupVisibilityItem(ui->sources, listItem, item);
UNUSED_PARAMETER(endHint);
}
void OBSBasic::OpenFilters()
{
OBSSceneItem item = GetCurrentSceneItem();
@@ -5150,13 +5004,11 @@ void OBSBasic::on_actionShowProfileFolder_triggered()
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
}
QListWidgetItem *OBSBasic::GetTopSelectedSourceItem()
int OBSBasic::GetTopSelectedSourceItem()
{
QList<QListWidgetItem*> selectedItems = ui->sources->selectedItems();
QListWidgetItem *topItem = nullptr;
if (selectedItems.size() != 0)
topItem = selectedItems[0];
return topItem;
QModelIndexList selectedItems =
ui->sources->selectionModel()->selectedIndexes();
return selectedItems.count() ? selectedItems[0].row() : -1;
}
void OBSBasic::on_preview_customContextMenuRequested(const QPoint &pos)
@@ -5613,6 +5465,22 @@ static bool nudge_callback(obs_scene_t*, obs_sceneitem_t *item, void *param)
struct vec2 pos;
if (!obs_sceneitem_selected(item)) {
if (obs_sceneitem_is_group(item)) {
struct vec3 offset3;
vec3_set(&offset3, offset.x, offset.y, 0.0f);
struct matrix4 matrix;
obs_sceneitem_get_draw_transform(item, &matrix);
vec4_set(&matrix.t, 0.0f, 0.0f, 0.0f, 1.0f);
matrix4_inv(&matrix, &matrix);
vec3_transform(&offset3, &offset3, &matrix);
struct vec2 new_offset;
vec2_set(&new_offset, offset3.x, offset3.y);
obs_sceneitem_group_enum_items(item, nudge_callback,
&new_offset);
}
return true;
}
@@ -6188,12 +6056,13 @@ bool OBSBasic::sysTrayMinimizeToTray()
void OBSBasic::on_actionCopySource_triggered()
{
on_actionCopyTransform_triggered();
OBSSceneItem item = GetCurrentSceneItem();
if (!item)
return;
if (!!obs_sceneitem_is_group(item))
return;
on_actionCopyTransform_triggered();
OBSSource source = obs_sceneitem_get_source(item);