From 01f0cab97d222f5cd4d7468f730370e76f08b42a Mon Sep 17 00:00:00 2001 From: CodeYan01 <65320293+CodeYan01@users.noreply.github.com> Date: Thu, 12 Jan 2023 01:01:14 +0800 Subject: [PATCH] UI: Refactor editable list modification Previously would unnecessarily recreating the data array for every modification (adding/removing/reordering/editing). This clears the fields in the associated data array that other code/scripts would add, such as an ID field for each item that could be used to distinguish each item from their duplicates in the list. I initially wanted to remove EditableListChanged, but it no longer saved the item selection whenever the list is modified, so I kept the function and just changed it to update the selected state in the data array. --- UI/properties-view.cpp | 97 +++++++++++++++++++++++++++++++++++++----- UI/properties-view.hpp | 6 +++ 2 files changed, 93 insertions(+), 10 deletions(-) diff --git a/UI/properties-view.cpp b/UI/properties-view.cpp index 7d8838b3603a2..025b104d0db27 100644 --- a/UI/properties-view.cpp +++ b/UI/properties-view.cpp @@ -709,6 +709,11 @@ void OBSPropertiesView::AddEditableList(obs_property_t *prop, { const char *name = obs_property_name(prop); OBSDataArrayAutoRelease array = obs_data_get_array(settings, name); + if (array == NULL) { + array = obs_data_array_create(); + obs_data_set_array(settings, name, array); + } + QListWidget *list = new QListWidget(); size_t count = obs_data_array_count(array); @@ -731,8 +736,8 @@ void OBSPropertiesView::AddEditableList(obs_property_t *prop, WidgetInfo *info = new WidgetInfo(this, prop, list); list->setDragDropMode(QAbstractItemView::InternalMove); - connect(list->model(), &QAbstractItemModel::rowsMoved, - [info]() { info->EditableListChanged(); }); + connect(list->model(), &QAbstractItemModel::rowsMoved, info, + &WidgetInfo::EditListReordered); QVBoxLayout *sideLayout = new QVBoxLayout(); NewButton(sideLayout, info, "addIconSmall", &WidgetInfo::EditListAdd); @@ -1992,24 +1997,52 @@ void WidgetInfo::GroupChanged(const char *setting) : true); } +void WidgetInfo::EditListReordered(const QModelIndex &sourceParent, + int sourceStart, int sourceEnd, + const QModelIndex &destinationParent, + int destinationRow) +{ + UNUSED_PARAMETER(sourceParent); + UNUSED_PARAMETER(destinationParent); + + const char *setting = obs_property_name(property); + OBSDataArrayAutoRelease array = + obs_data_get_array(view->settings, setting); + + for (int i = sourceStart; i <= sourceEnd; i++) { + OBSDataAutoRelease arrayItem = obs_data_array_item(array, i); + obs_data_array_insert(array, destinationRow, arrayItem); + // if moved to top, destination row increases + obs_data_array_erase(array, (i > destinationRow) ? i + 1 : i); + ++destinationRow; + } + EditableListChanged(); +} + +void WidgetInfo::EditableListArrayPushBack(obs_data_array_t *array, + const char *text) +{ + OBSDataAutoRelease arrayItem = obs_data_create(); + obs_data_set_string(arrayItem, "value", text); + obs_data_set_bool(arrayItem, "selected", false); + obs_data_set_bool(arrayItem, "hidden", false); + obs_data_array_push_back(array, arrayItem); +} + void WidgetInfo::EditableListChanged() { const char *setting = obs_property_name(property); QListWidget *list = reinterpret_cast(widget); - OBSDataArrayAutoRelease array = obs_data_array_create(); + OBSDataArrayAutoRelease array = + obs_data_get_array(view->settings, setting); for (int i = 0; i < list->count(); i++) { QListWidgetItem *item = list->item(i); - OBSDataAutoRelease arrayItem = obs_data_create(); - obs_data_set_string(arrayItem, "value", - QT_TO_UTF8(item->text())); + OBSDataAutoRelease arrayItem = obs_data_array_item(array, i); obs_data_set_bool(arrayItem, "selected", item->isSelected()); obs_data_set_bool(arrayItem, "hidden", item->isHidden()); - obs_data_array_push_back(array, arrayItem); } - obs_data_set_array(view->settings, setting, array); - ControlChanged(); } @@ -2263,6 +2296,9 @@ void WidgetInfo::EditListAddText() { QListWidget *list = reinterpret_cast(widget); const char *desc = obs_property_description(property); + const char *setting = obs_property_name(property); + OBSDataArrayAutoRelease array = + obs_data_get_array(view->settings, setting); EditableItemDialog dialog(widget->window(), QString(), false); auto title = QTStr("Basic.PropertiesWindow.AddEditableListEntry") @@ -2276,6 +2312,7 @@ void WidgetInfo::EditListAddText() return; list->addItem(text); + EditableListArrayPushBack(array, QT_TO_UTF8(text)); EditableListChanged(); } @@ -2286,6 +2323,9 @@ void WidgetInfo::EditListAddFiles() const char *filter = obs_property_editable_list_filter(property); const char *default_path = obs_property_editable_list_default_path(property); + const char *setting = obs_property_name(property); + OBSDataArrayAutoRelease array = + obs_data_get_array(view->settings, setting); QString title = QTStr("Basic.PropertiesWindow.AddEditableListFiles") .arg(QT_UTF8(desc)); @@ -2301,6 +2341,9 @@ void WidgetInfo::EditListAddFiles() return; list->addItems(files); + for (QString &file : files) { + EditableListArrayPushBack(array, QT_TO_UTF8(file)); + } EditableListChanged(); } @@ -2310,6 +2353,9 @@ void WidgetInfo::EditListAddDir() const char *desc = obs_property_description(property); const char *default_path = obs_property_editable_list_default_path(property); + const char *setting = obs_property_name(property); + OBSDataArrayAutoRelease array = + obs_data_get_array(view->settings, setting); QString title = QTStr("Basic.PropertiesWindow.AddEditableListDir") .arg(QT_UTF8(desc)); @@ -2325,6 +2371,7 @@ void WidgetInfo::EditListAddDir() return; list->addItem(dir); + EditableListArrayPushBack(array, QT_TO_UTF8(dir)); EditableListChanged(); } @@ -2332,9 +2379,15 @@ void WidgetInfo::EditListRemove() { QListWidget *list = reinterpret_cast(widget); QList items = list->selectedItems(); + const char *setting = obs_property_name(property); + OBSDataArrayAutoRelease array = + obs_data_get_array(view->settings, setting); - for (QListWidgetItem *item : items) + for (qsizetype i = items.size() - 1; i >= 0; i--) { + QListWidgetItem *item = items.at(i); + obs_data_array_erase(array, list->row(item)); delete item; + } EditableListChanged(); } @@ -2343,6 +2396,7 @@ void WidgetInfo::EditListEdit() QListWidget *list = reinterpret_cast(widget); enum obs_editable_list_type type = obs_property_editable_list_type(property); + const char *setting = obs_property_name(property); const char *desc = obs_property_description(property); const char *filter = obs_property_editable_list_filter(property); QList selectedItems = list->selectedItems(); @@ -2351,6 +2405,10 @@ void WidgetInfo::EditListEdit() return; QListWidgetItem *item = selectedItems[0]; + int row = list->row(item); + OBSDataArrayAutoRelease array = + obs_data_get_array(view->settings, setting); + OBSDataAutoRelease arrayItem = obs_data_array_item(array, row); if (type == OBS_EDITABLE_LIST_TYPE_FILES) { QDir pathDir(item->text()); @@ -2367,6 +2425,7 @@ void WidgetInfo::EditListEdit() return; item->setText(path); + obs_data_set_string(arrayItem, "value", QT_TO_UTF8(path)); EditableListChanged(); return; } @@ -2385,6 +2444,7 @@ void WidgetInfo::EditListEdit() return; item->setText(text); + obs_data_set_string(arrayItem, "value", QT_TO_UTF8(text)); EditableListChanged(); } @@ -2392,6 +2452,9 @@ void WidgetInfo::EditListUp() { QListWidget *list = reinterpret_cast(widget); int lastItemRow = -1; + const char *setting = obs_property_name(property); + OBSDataArrayAutoRelease array = + obs_data_get_array(view->settings, setting); for (int i = 0; i < list->count(); i++) { QListWidgetItem *item = list->item(i); @@ -2405,6 +2468,11 @@ void WidgetInfo::EditListUp() list->takeItem(row); list->insertItem(lastItemRow, item); item->setSelected(true); + + OBSDataAutoRelease arrayItem = + obs_data_array_item(array, row); + obs_data_array_insert(array, lastItemRow, arrayItem); + obs_data_array_erase(array, row + 1); } else { lastItemRow = row; } @@ -2417,6 +2485,9 @@ void WidgetInfo::EditListDown() { QListWidget *list = reinterpret_cast(widget); int lastItemRow = list->count(); + const char *setting = obs_property_name(property); + OBSDataArrayAutoRelease array = + obs_data_get_array(view->settings, setting); for (int i = list->count() - 1; i >= 0; i--) { QListWidgetItem *item = list->item(i); @@ -2430,6 +2501,12 @@ void WidgetInfo::EditListDown() list->takeItem(row); list->insertItem(lastItemRow, item); item->setSelected(true); + + OBSDataAutoRelease arrayItem = + obs_data_array_item(array, row); + obs_data_array_insert(array, lastItemRow + 1, + arrayItem); + obs_data_array_erase(array, row); } else { lastItemRow = row; } diff --git a/UI/properties-view.hpp b/UI/properties-view.hpp index e520dcdde2c90..89546b1317fba 100644 --- a/UI/properties-view.hpp +++ b/UI/properties-view.hpp @@ -47,6 +47,8 @@ class WidgetInfo : public QObject { void ButtonClicked(); void TogglePasswordText(bool checked); + void EditableListArrayPushBack(obs_data_array_t *array, + const char *text); public: inline WidgetInfo(OBSPropertiesView *view_, obs_property_t *prop, @@ -79,6 +81,10 @@ public slots: void EditListEdit(); void EditListUp(); void EditListDown(); + void EditListReordered(const QModelIndex &sourceParent, int sourceStart, + int sourceEnd, + const QModelIndex &destinationParent, + int destinationRow); }; /* ------------------------------------------------------------------------- */