123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434 |
- #include "SourceTreeModel.hpp"
- #include <widgets/OBSBasic.hpp>
- #include <qt-wrappers.hpp>
- #include "moc_SourceTreeModel.cpp"
- static inline OBSScene GetCurrentScene()
- {
- OBSBasic *main = OBSBasic::Get();
- return main->GetCurrentScene();
- }
- void SourceTreeModel::OBSFrontendEvent(enum obs_frontend_event event, void *ptr)
- {
- SourceTreeModel *stm = static_cast<SourceTreeModel *>(ptr);
- switch (event) {
- case OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED:
- stm->SceneChanged();
- break;
- case OBS_FRONTEND_EVENT_EXIT:
- stm->Clear();
- obs_frontend_remove_event_callback(OBSFrontendEvent, stm);
- break;
- case OBS_FRONTEND_EVENT_SCENE_COLLECTION_CLEANUP:
- stm->Clear();
- break;
- default:
- break;
- }
- }
- void SourceTreeModel::Clear()
- {
- beginResetModel();
- items.clear();
- endResetModel();
- hasGroups = false;
- }
- static bool enumItem(obs_scene_t *, obs_sceneitem_t *item, void *ptr)
- {
- QVector<OBSSceneItem> &items = *static_cast<QVector<OBSSceneItem> *>(ptr);
- obs_source_t *src = obs_sceneitem_get_source(item);
- if (obs_source_removed(src)) {
- return true;
- }
- if (obs_sceneitem_is_group(item)) {
- OBSDataAutoRelease data = obs_sceneitem_get_private_settings(item);
- bool collapse = obs_data_get_bool(data, "collapsed");
- if (!collapse) {
- obs_scene_t *scene = obs_sceneitem_group_get_scene(item);
- obs_scene_enum_items(scene, enumItem, &items);
- }
- }
- items.insert(0, item);
- return true;
- }
- void SourceTreeModel::SceneChanged()
- {
- OBSScene scene = GetCurrentScene();
- beginResetModel();
- items.clear();
- obs_scene_enum_items(scene, enumItem, &items);
- endResetModel();
- UpdateGroupState(false);
- st->ResetWidgets();
- for (int i = 0; i < items.count(); i++) {
- bool select = obs_sceneitem_selected(items[i]);
- QModelIndex index = createIndex(i, 0);
- 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)
- {
- OBSSceneItem item = items[oldIdx];
- items.remove(oldIdx);
- items.insert(newIdx, item);
- }
- /* reorders list optimally with model reorder funcs */
- void SourceTreeModel::ReorderItems()
- {
- OBSScene scene = GetCurrentScene();
- QVector<OBSSceneItem> newitems;
- obs_scene_enum_items(scene, enumItem, &newitems);
- /* if item list has changed size, do full reset */
- if (newitems.count() != items.count()) {
- SceneChanged();
- return;
- }
- for (;;) {
- int idx1Old = 0;
- int idx1New = 0;
- int count;
- int i;
- /* find first starting changed item index */
- for (i = 0; i < newitems.count(); i++) {
- obs_sceneitem_t *oldItem = items[i];
- obs_sceneitem_t *newItem = newitems[i];
- if (oldItem != newItem) {
- idx1Old = i;
- break;
- }
- }
- /* if everything is the same, break */
- if (i == newitems.count()) {
- break;
- }
- /* find new starting index */
- for (i = idx1Old + 1; i < newitems.count(); i++) {
- obs_sceneitem_t *oldItem = items[idx1Old];
- obs_sceneitem_t *newItem = newitems[i];
- if (oldItem == newItem) {
- idx1New = i;
- break;
- }
- }
- /* if item could not be found, do full reset */
- if (i == newitems.count()) {
- SceneChanged();
- return;
- }
- /* get move count */
- for (count = 1; (idx1New + count) < newitems.count(); count++) {
- int oldIdx = idx1Old + count;
- int newIdx = idx1New + count;
- obs_sceneitem_t *oldItem = items[oldIdx];
- obs_sceneitem_t *newItem = newitems[newIdx];
- if (oldItem != newItem) {
- break;
- }
- }
- /* move items */
- beginMoveRows(QModelIndex(), idx1Old, idx1Old + count - 1, QModelIndex(), idx1New + count);
- for (i = 0; i < count; i++) {
- int to = idx1New + count;
- if (to > idx1Old)
- to--;
- MoveItem(items, idx1Old, to);
- }
- endMoveRows();
- }
- }
- void SourceTreeModel::Add(obs_sceneitem_t *item)
- {
- if (obs_sceneitem_is_group(item)) {
- SceneChanged();
- } else {
- beginInsertRows(QModelIndex(), 0, 0);
- items.insert(0, item);
- endInsertRows();
- st->UpdateWidget(createIndex(0, 0, nullptr), item);
- }
- }
- void SourceTreeModel::Remove(obs_sceneitem_t *item)
- {
- int idx = -1;
- for (int i = 0; i < items.count(); i++) {
- if (items[i] == item) {
- idx = i;
- break;
- }
- }
- if (idx == -1)
- return;
- int startIdx = idx;
- int endIdx = idx;
- bool is_group = obs_sceneitem_is_group(item);
- if (is_group) {
- obs_scene_t *scene = obs_sceneitem_group_get_scene(item);
- for (int i = endIdx + 1; i < items.count(); i++) {
- obs_sceneitem_t *subitem = items[i];
- obs_scene_t *subscene = obs_sceneitem_get_scene(subitem);
- if (subscene == scene)
- endIdx = i;
- else
- break;
- }
- }
- beginRemoveRows(QModelIndex(), startIdx, endIdx);
- items.remove(idx, endIdx - startIdx + 1);
- endRemoveRows();
- if (is_group)
- UpdateGroupState(true);
- OBSBasic::Get()->UpdateContextBarDeferred();
- }
- OBSSceneItem SourceTreeModel::Get(int idx)
- {
- if (idx == -1 || idx >= items.count())
- return OBSSceneItem();
- return items[idx];
- }
- SourceTreeModel::SourceTreeModel(SourceTree *st_) : QAbstractListModel(st_), st(st_)
- {
- obs_frontend_add_event_callback(OBSFrontendEvent, this);
- }
- int SourceTreeModel::rowCount(const QModelIndex &parent) const
- {
- return parent.isValid() ? 0 : items.count();
- }
- QVariant SourceTreeModel::data(const QModelIndex &index, int role) const
- {
- if (role == Qt::AccessibleTextRole) {
- OBSSceneItem item = items[index.row()];
- obs_source_t *source = obs_sceneitem_get_source(item);
- return QVariant(QT_UTF8(obs_source_get_name(source)));
- }
- return QVariant();
- }
- Qt::ItemFlags SourceTreeModel::flags(const QModelIndex &index) const
- {
- if (!index.isValid())
- return QAbstractListModel::flags(index) | Qt::ItemIsDropEnabled;
- obs_sceneitem_t *item = items[index.row()];
- bool is_group = obs_sceneitem_is_group(item);
- return QAbstractListModel::flags(index) | Qt::ItemIsEditable | Qt::ItemIsDragEnabled |
- (is_group ? Qt::ItemIsDropEnabled : Qt::NoItemFlags);
- }
- Qt::DropActions SourceTreeModel::supportedDropActions() const
- {
- return QAbstractItemModel::supportedDropActions() | Qt::MoveAction;
- }
- QString SourceTreeModel::GetNewGroupName()
- {
- OBSScene scene = GetCurrentScene();
- QString name = QTStr("Group");
- int i = 2;
- for (;;) {
- OBSSourceAutoRelease group = obs_get_source_by_name(QT_TO_UTF8(name));
- if (!group)
- break;
- name = QTStr("Basic.Main.Group").arg(QString::number(i++));
- }
- return name;
- }
- void SourceTreeModel::AddGroup()
- {
- QString name = GetNewGroupName();
- obs_sceneitem_t *group = obs_scene_add_group(GetCurrentScene(), QT_TO_UTF8(name));
- if (!group)
- return;
- beginInsertRows(QModelIndex(), 0, 0);
- items.insert(0, group);
- endInsertRows();
- st->UpdateWidget(createIndex(0, 0, nullptr), group);
- UpdateGroupState(true);
- QMetaObject::invokeMethod(st, "Edit", Qt::QueuedConnection, Q_ARG(int, 0));
- }
- void SourceTreeModel::GroupSelectedItems(QModelIndexList &indices)
- {
- if (indices.count() == 0)
- return;
- OBSBasic *main = OBSBasic::Get();
- OBSScene scene = GetCurrentScene();
- QString name = GetNewGroupName();
- QVector<obs_sceneitem_t *> item_order;
- for (int i = indices.count() - 1; i >= 0; i--) {
- obs_sceneitem_t *item = items[indices[i].row()];
- item_order << item;
- }
- st->undoSceneData = main->BackupScene(scene);
- obs_sceneitem_t *item = obs_scene_insert_group(scene, QT_TO_UTF8(name), item_order.data(), item_order.size());
- if (!item) {
- st->undoSceneData = nullptr;
- return;
- }
- main->undo_s.push_disabled();
- for (obs_sceneitem_t *item : item_order)
- obs_sceneitem_select(item, false);
- hasGroups = true;
- st->UpdateWidgets(true);
- obs_sceneitem_select(item, true);
- /* ----------------------------------------------------------------- */
- /* obs_scene_insert_group triggers a full refresh of scene items via */
- /* the item_add signal. No need to insert a row, just edit the one */
- /* that's created automatically. */
- int newIdx = indices[0].row();
- QMetaObject::invokeMethod(st, "NewGroupEdit", Qt::QueuedConnection, Q_ARG(int, newIdx));
- }
- void SourceTreeModel::UngroupSelectedGroups(QModelIndexList &indices)
- {
- OBSBasic *main = OBSBasic::Get();
- if (indices.count() == 0)
- return;
- OBSScene scene = main->GetCurrentScene();
- OBSData undoData = main->BackupScene(scene);
- for (int i = indices.count() - 1; i >= 0; i--) {
- obs_sceneitem_t *item = items[indices[i].row()];
- obs_sceneitem_group_ungroup(item);
- }
- SceneChanged();
- OBSData redoData = main->BackupScene(scene);
- main->CreateSceneUndoRedoAction(QTStr("Basic.Main.Ungroup"), undoData, redoData);
- }
- void SourceTreeModel::ExpandGroup(obs_sceneitem_t *item)
- {
- int itemIdx = items.indexOf(item);
- if (itemIdx == -1)
- return;
- itemIdx++;
- obs_scene_t *scene = obs_sceneitem_group_get_scene(item);
- QVector<OBSSceneItem> subItems;
- obs_scene_enum_items(scene, enumItem, &subItems);
- if (!subItems.size())
- return;
- beginInsertRows(QModelIndex(), itemIdx, itemIdx + subItems.size() - 1);
- for (int i = 0; i < subItems.size(); i++)
- items.insert(i + itemIdx, subItems[i]);
- endInsertRows();
- st->UpdateWidgets();
- }
- void SourceTreeModel::CollapseGroup(obs_sceneitem_t *item)
- {
- int startIdx = -1;
- int endIdx = -1;
- obs_scene_t *scene = obs_sceneitem_group_get_scene(item);
- for (int i = 0; i < items.size(); i++) {
- obs_scene_t *itemScene = obs_sceneitem_get_scene(items[i]);
- if (itemScene == scene) {
- if (startIdx == -1)
- startIdx = i;
- endIdx = i;
- }
- }
- if (startIdx == -1)
- return;
- beginRemoveRows(QModelIndex(), startIdx, endIdx);
- items.remove(startIdx, endIdx - startIdx + 1);
- endRemoveRows();
- }
- void SourceTreeModel::UpdateGroupState(bool update)
- {
- bool nowHasGroups = false;
- for (auto &item : items) {
- if (obs_sceneitem_is_group(item)) {
- nowHasGroups = true;
- break;
- }
- }
- if (nowHasGroups != hasGroups) {
- hasGroups = nowHasGroups;
- if (update) {
- st->UpdateWidgets(true);
- }
- }
- }
|