Răsfoiți Sursa

UI: Don't recreate entire Hotkey Settings tab

This replaces the programmatic generation of the hotkeys tab with XML.
Also fixes a memory leak. Reuses concepts from LoadAudioSources().
Matt Gajownik 3 ani în urmă
părinte
comite
e00195ad6f

+ 86 - 25
UI/forms/OBSBasicSettings.ui

@@ -4690,31 +4690,87 @@
          </item>
         </layout>
        </widget>
-       <widget class="QScrollArea" name="hotkeyPage">
-        <property name="widgetResizable">
-         <bool>true</bool>
-        </property>
-        <widget class="QWidget" name="hotkeyWidget">
-         <property name="geometry">
-          <rect>
-           <x>0</x>
-           <y>0</y>
-           <width>98</width>
-           <height>28</height>
-          </rect>
-         </property>
-         <layout class="QFormLayout" name="hotkeyLayout">
-          <property name="fieldGrowthPolicy">
-           <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
-          </property>
-          <property name="labelAlignment">
-           <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
-          </property>
-          <property name="verticalSpacing">
-           <number>0</number>
-          </property>
-         </layout>
-        </widget>
+       <widget class="QWidget" name="hotkeyPage">
+        <layout class="QVBoxLayout" name="verticalLayout_25">
+         <item>
+          <layout class="QGridLayout" name="hotkeySearchLayout">
+           <item row="0" column="0">
+            <widget class="QLabel" name="hotkeySearchLabel">
+             <property name="text">
+              <string>Basic.Settings.Hotkeys.Filter</string>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="1">
+            <widget class="QLineEdit" name="hotkeyFilterSearch"/>
+           </item>
+           <item row="0" column="2">
+            <widget class="QLabel" name="hotkeyFilterLabel">
+             <property name="text">
+              <string>Basic.Settings.Hotkeys.FilterByHotkey</string>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="3">
+            <widget class="OBSHotkeyEdit" name="hotkeyFilterInput"/>
+           </item>
+           <item row="0" column="4">
+            <widget class="QPushButton" name="hotkeyFilterReset">
+             <property name="minimumSize">
+              <size>
+               <width>24</width>
+               <height>24</height>
+              </size>
+             </property>
+             <property name="maximumSize">
+              <size>
+               <width>24</width>
+               <height>24</height>
+              </size>
+             </property>
+             <property name="baseSize">
+              <size>
+               <width>24</width>
+               <height>24</height>
+              </size>
+             </property>
+             <property name="toolTip">
+              <string>Clear</string>
+             </property>
+             <property name="flat">
+              <bool>true</bool>
+             </property>
+             <property name="themeID" stdset="0">
+              <string>trashIcon</string>
+             </property>
+             <property name="fixedSize" stdset="0">
+              <size>
+               <width>24</width>
+               <height>24</height>
+              </size>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </item>
+         <item>
+          <widget class="QScrollArea" name="hotkeyScrollArea">
+           <property name="widgetResizable">
+            <bool>true</bool>
+           </property>
+           <widget class="QWidget" name="hotkeyScrollContents">
+            <layout class="QFormLayout" name="hotkeyFormLayout">
+             <property name="labelAlignment">
+              <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+             </property>
+             <property name="verticalSpacing">
+              <number>0</number>
+             </property>
+            </layout>
+           </widget>
+          </widget>
+         </item>
+        </layout>
        </widget>
        <widget class="QWidget" name="advancedPage">
         <layout class="QVBoxLayout" name="verticalLayout_16">
@@ -5572,6 +5628,11 @@
    <extends>QPushButton</extends>
    <header>url-push-button.hpp</header>
   </customwidget>
+  <customwidget>
+   <class>OBSHotkeyEdit</class>
+   <extends>QLineEdit</extends>
+   <header>hotkey-edit.hpp</header>
+  </customwidget>
  </customwidgets>
  <tabstops>
   <tabstop>listWidget</tabstop>

+ 4 - 4
UI/hotkey-edit.cpp

@@ -175,7 +175,7 @@ void OBSHotkeyEdit::ClearKey()
 
 void OBSHotkeyEdit::UpdateDuplicationState()
 {
-	if (dupeIcon->isVisible() != hasDuplicate) {
+	if (dupeIcon && dupeIcon->isVisible() != hasDuplicate) {
 		dupeIcon->setVisible(hasDuplicate);
 		update();
 	}
@@ -194,8 +194,8 @@ void OBSHotkeyEdit::InitSignalHandler()
 
 void OBSHotkeyEdit::CreateDupeIcon()
 {
-	dupeIcon = this->addAction(settings->GetHotkeyConflictIcon(),
-				   ActionPosition::TrailingPosition);
+	dupeIcon = addAction(settings->GetHotkeyConflictIcon(),
+			     ActionPosition::TrailingPosition);
 	dupeIcon->setToolTip(QTStr("Basic.Settings.Hotkeys.DuplicateWarning"));
 	QObject::connect(dupeIcon, &QAction::triggered,
 			 [=] { emit SearchKey(key); });
@@ -274,7 +274,7 @@ void OBSHotkeyWidget::Save(std::vector<obs_key_combination_t> &combinations)
 
 void OBSHotkeyWidget::AddEdit(obs_key_combination combo, int idx)
 {
-	auto edit = new OBSHotkeyEdit(combo, settings);
+	auto edit = new OBSHotkeyEdit(parentWidget(), combo, settings);
 	edit->setToolTip(toolTip);
 
 	auto revert = new QPushButton;

+ 17 - 4
UI/hotkey-edit.hpp

@@ -62,9 +62,9 @@ class OBSHotkeyEdit : public QLineEdit {
 	Q_OBJECT;
 
 public:
-	OBSHotkeyEdit(obs_key_combination_t original,
+	OBSHotkeyEdit(QWidget *parent, obs_key_combination_t original,
 		      OBSBasicSettings *settings)
-		: QLineEdit(nullptr), original(original), settings(settings)
+		: QLineEdit(parent), original(original), settings(settings)
 	{
 #ifdef __APPLE__
 		// disable the input cursor on OSX, focus should be clear
@@ -77,6 +77,19 @@ public:
 		CreateDupeIcon();
 		ResetKey();
 	}
+	OBSHotkeyEdit(QWidget *parent = nullptr)
+		: QLineEdit(parent), original({}), settings(nullptr)
+	{
+#ifdef __APPLE__
+		// disable the input cursor on OSX, focus should be clear
+		// enough with the default focus frame
+		setReadOnly(true);
+#endif
+		setAttribute(Qt::WA_InputMethodEnabled, false);
+		setAttribute(Qt::WA_MacShowFocusRect, true);
+		InitSignalHandler();
+		ResetKey();
+	}
 
 	obs_key_combination_t original;
 	obs_key_combination_t key;
@@ -116,10 +129,10 @@ class OBSHotkeyWidget : public QWidget {
 	Q_OBJECT;
 
 public:
-	OBSHotkeyWidget(obs_hotkey_id id, std::string name,
+	OBSHotkeyWidget(QWidget *parent, obs_hotkey_id id, std::string name,
 			OBSBasicSettings *settings,
 			const std::vector<obs_key_combination_t> &combos = {})
-		: QWidget(nullptr),
+		: QWidget(parent),
 		  id(id),
 		  name(name),
 		  bindingsChanged(obs_get_signal_handler(),

+ 93 - 101
UI/window-basic-settings.cpp

@@ -2620,11 +2620,11 @@ LayoutHotkey(OBSBasicSettings *settings, obs_hotkey_id id, obs_hotkey_t *key,
 
 	auto combos = keys.find(id);
 	if (combos == std::end(keys))
-		hw = new OBSHotkeyWidget(id, obs_hotkey_get_name(key),
+		hw = new OBSHotkeyWidget(settings, id, obs_hotkey_get_name(key),
 					 settings);
 	else
-		hw = new OBSHotkeyWidget(id, obs_hotkey_get_name(key), settings,
-					 combos->second);
+		hw = new OBSHotkeyWidget(settings, id, obs_hotkey_get_name(key),
+					 settings, combos->second);
 
 	hw->label = label;
 	label->widget = hw;
@@ -2700,7 +2700,17 @@ static inline void AddHotkeys(
 void OBSBasicSettings::LoadHotkeySettings(obs_hotkey_id ignoreKey)
 {
 	hotkeys.clear();
-	ui->hotkeyPage->takeWidget()->deleteLater();
+	if (ui->hotkeyFormLayout->rowCount() > 0) {
+		QLayoutItem *forDeletion = ui->hotkeyFormLayout->takeAt(0);
+		forDeletion->widget()->deleteLater();
+		delete forDeletion;
+	}
+	ui->hotkeyFilterSearch->blockSignals(true);
+	ui->hotkeyFilterInput->blockSignals(true);
+	ui->hotkeyFilterSearch->setText("");
+	ui->hotkeyFilterInput->ResetKey();
+	ui->hotkeyFilterSearch->blockSignals(false);
+	ui->hotkeyFilterInput->blockSignals(false);
 
 	using keys_t = map<obs_hotkey_id, vector<obs_key_combination_t>>;
 	keys_t keys;
@@ -2717,104 +2727,14 @@ void OBSBasicSettings::LoadHotkeySettings(obs_hotkey_id ignoreKey)
 		},
 		&keys);
 
-	auto layout = new QVBoxLayout();
-	ui->hotkeyPage->setLayout(layout);
-
-	auto widget = new QWidget();
-	auto scrollArea = new QScrollArea();
-	scrollArea->setWidgetResizable(true);
-	scrollArea->setWidget(widget);
-
-	auto hotkeysLayout = new QFormLayout();
+	QFormLayout *hotkeysLayout = new QFormLayout();
 	hotkeysLayout->setVerticalSpacing(0);
 	hotkeysLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
 	hotkeysLayout->setLabelAlignment(Qt::AlignRight | Qt::AlignTrailing |
 					 Qt::AlignVCenter);
-	widget->setLayout(hotkeysLayout);
-
-	auto filterLayout = new QGridLayout();
-	auto filterLabel = new QLabel(QTStr("Basic.Settings.Hotkeys.Filter"));
-	auto filter = new QLineEdit();
-	auto filterHotkeyLabel =
-		new QLabel(QTStr("Basic.Settings.Hotkeys.FilterByHotkey"));
-	auto filterHotkeyInput = new OBSHotkeyEdit({}, this);
-	auto filterReset = new QPushButton;
-	filterReset->setProperty("themeID", "trashIcon");
-	filterReset->setToolTip(QTStr("Clear"));
-	filterReset->setFixedSize(24, 24);
-	filterReset->setFlat(true);
-
-	auto setRowVisible = [=](int row, bool visible, QLayoutItem *label) {
-		label->widget()->setVisible(visible);
-
-		auto field = hotkeysLayout->itemAt(row, QFormLayout::FieldRole);
-		if (field)
-			field->widget()->setVisible(visible);
-	};
-
-	auto searchFunction = [=](const QString &text,
-				  obs_key_combination_t filterCombo) {
-		std::vector<obs_key_combination_t> combos;
-		bool showHotkey;
-		scrollArea->ensureVisible(0, 0);
-		scrollArea->setUpdatesEnabled(false);
-
-		for (int i = 0; i < hotkeysLayout->rowCount(); i++) {
-			auto label = hotkeysLayout->itemAt(
-				i, QFormLayout::LabelRole);
-			if (!label)
-				continue;
-
-			OBSHotkeyLabel *item =
-				qobject_cast<OBSHotkeyLabel *>(label->widget());
-			if (!item)
-				continue;
-
-			item->widget->GetCombinations(combos);
-			QString fullname =
-				item->property("fullName").value<QString>();
-
-			showHotkey =
-				text.isEmpty() ||
-				fullname.toLower().contains(text.toLower());
-
-			if (showHotkey &&
-			    !obs_key_combination_is_empty(filterCombo)) {
-				showHotkey = false;
-				for (auto combo : combos) {
-					if (combo == filterCombo) {
-						showHotkey = true;
-						continue;
-					}
-				}
-			}
-			setRowVisible(i, showHotkey, label);
-		}
-		scrollArea->setUpdatesEnabled(true);
-	};
-
-	connect(filter, &QLineEdit::textChanged, this, [=](const QString text) {
-		searchFunction(text, filterHotkeyInput->key);
-	});
-
-	connect(filterHotkeyInput, &OBSHotkeyEdit::KeyChanged, this,
-		[=](obs_key_combination_t combo) {
-			searchFunction(filter->text(), combo);
-		});
-
-	connect(filterReset, &QPushButton::clicked, this, [=]() {
-		filter->setText("");
-		filterHotkeyInput->ResetKey();
-	});
-
-	filterLayout->addWidget(filterLabel, 0, 0);
-	filterLayout->addWidget(filter, 0, 1);
-	filterLayout->addWidget(filterHotkeyLabel, 0, 2);
-	filterLayout->addWidget(filterHotkeyInput, 0, 3);
-	filterLayout->addWidget(filterReset, 0, 4);
-
-	layout->addLayout(filterLayout);
-	layout->addWidget(scrollArea);
+	auto hotkeyChildWidget = new QWidget();
+	hotkeyChildWidget->setLayout(hotkeysLayout);
+	ui->hotkeyFormLayout->addRow(hotkeyChildWidget);
 
 	using namespace std;
 	using encoders_elem_t =
@@ -2938,9 +2858,9 @@ void OBSBasicSettings::LoadHotkeySettings(obs_hotkey_id ignoreKey)
 		});
 		connect(hw, &OBSHotkeyWidget::SearchKey,
 			[=](obs_key_combination_t combo) {
-				filter->setText("");
-				filterHotkeyInput->HandleNewKey(combo);
-				filterHotkeyInput->KeyChanged(combo);
+				ui->hotkeyFilterSearch->setText("");
+				ui->hotkeyFilterInput->HandleNewKey(combo);
+				ui->hotkeyFilterInput->KeyChanged(combo);
 			});
 	};
 
@@ -4343,6 +4263,78 @@ void OBSBasicSettings::HotkeysChanged()
 		EnableApplyButton(true);
 }
 
+void OBSBasicSettings::SearchHotkeys(const QString &text,
+				     obs_key_combination_t filterCombo)
+{
+
+	if (ui->hotkeyFormLayout->rowCount() == 0)
+		return;
+
+	std::vector<obs_key_combination_t> combos;
+	bool showHotkey;
+	ui->hotkeyScrollArea->ensureVisible(0, 0);
+	ui->hotkeyScrollArea->setUpdatesEnabled(false);
+
+	QLayoutItem *hotkeysItem = ui->hotkeyFormLayout->itemAt(0);
+	QWidget *hotkeys = hotkeysItem->widget();
+	if (!hotkeys)
+		return;
+
+	QFormLayout *hotkeysLayout =
+		qobject_cast<QFormLayout *>(hotkeys->layout());
+
+	for (int i = 0; i < hotkeysLayout->rowCount(); i++) {
+		auto label = hotkeysLayout->itemAt(i, QFormLayout::LabelRole);
+		if (!label)
+			continue;
+
+		OBSHotkeyLabel *item =
+			qobject_cast<OBSHotkeyLabel *>(label->widget());
+		if (!item)
+			continue;
+
+		item->widget->GetCombinations(combos);
+		QString fullname = item->property("fullName").value<QString>();
+
+		showHotkey = text.isEmpty() ||
+			     fullname.toLower().contains(text.toLower());
+
+		if (showHotkey && !obs_key_combination_is_empty(filterCombo)) {
+			showHotkey = false;
+			for (auto combo : combos) {
+				if (combo == filterCombo) {
+					showHotkey = true;
+					continue;
+				}
+			}
+		}
+
+		label->widget()->setVisible(showHotkey);
+
+		auto field = hotkeysLayout->itemAt(i, QFormLayout::FieldRole);
+		if (field)
+			field->widget()->setVisible(showHotkey);
+	}
+	ui->hotkeyScrollArea->setUpdatesEnabled(true);
+}
+
+void OBSBasicSettings::on_hotkeyFilterReset_clicked()
+{
+	ui->hotkeyFilterSearch->setText("");
+	ui->hotkeyFilterInput->ResetKey();
+}
+
+void OBSBasicSettings::on_hotkeyFilterSearch_textChanged(const QString text)
+{
+	SearchHotkeys(text, ui->hotkeyFilterInput->key);
+}
+
+void OBSBasicSettings::on_hotkeyFilterInput_KeyChanged(
+	obs_key_combination_t combo)
+{
+	SearchHotkeys(ui->hotkeyFilterSearch->text(), combo);
+}
+
 static bool MarkHotkeyConflicts(OBSHotkeyLabel *item1, OBSHotkeyLabel *item2)
 {
 	if (item1->pairPartner == item2)

+ 7 - 0
UI/window-basic-settings.hpp

@@ -268,6 +268,10 @@ private slots:
 	void on_useStreamKey_clicked();
 	void on_useAuth_toggled();
 
+	void on_hotkeyFilterReset_clicked();
+	void on_hotkeyFilterSearch_textChanged(const QString text);
+	void on_hotkeyFilterInput_KeyChanged(obs_key_combination_t combo);
+
 private:
 	/* output */
 	void LoadSimpleOutputSettings();
@@ -303,6 +307,9 @@ private:
 	void SaveAdvancedSettings();
 	void SaveSettings();
 
+	void SearchHotkeys(const QString &text,
+			   obs_key_combination_t filterCombo);
+
 	void UpdateSimpleOutStreamDelayEstimate();
 	void UpdateAdvOutStreamDelayEstimate();