Bläddra i källkod

frontend: Update Plugin Manager v1 UI

Warchamp7 1 månad sedan
förälder
incheckning
9a3fe95211

+ 7 - 4
frontend/data/locale/en-US.ini

@@ -118,6 +118,7 @@ SceneFilters="Open Scene Filters"
 List="List"
 Grid="Grid"
 Automatic="Automatic"
+ComingSoon="Coming Soon"
 
 # warning for plugin load failures
 PluginsFailedToLoad.Title="Plugin Load Error"
@@ -1622,10 +1623,12 @@ MultitrackVideo.IncompatibleSettings.AudioChannels="%1 is not currently compatib
 MultitrackVideo.IncompatibleSettings.AudioChannelsSingle="[Audio → General → Channels] needs to be set to '%1'"
 MultitrackVideo.IncompatibleSettings.AudioChannelsMultiple="%1 requires multiple different settings for [Audio → General → Channels]"
 
-#Plugin ManagerW
+# Plugin Manager window
 Basic.OpenPluginManager="Plugin Manager"
 PluginManager="Plugin Manager"
-PluginManager.HelpText="Plugin Manager"
-PluginManager.Restart="Restart OBS?"
-PluginManager.NeedsRestart="To apply these changes, OBS needs to restart. Do you want to restart now?"
+PluginManager.Restart="OBS Studio must be restarted to apply plugin changes"
 PluginManager.MissingPlugin="[PLUGIN NOT FOUND]"
+PluginManager.Section.Discover="Browse"
+PluginManager.Section.Manage="Installed"
+PluginManager.Section.Updates="Updates"
+PluginManager.Section.Manage.Title="Manage Enabled Plugins"

+ 84 - 21
frontend/data/themes/Yami.obt

@@ -98,8 +98,8 @@
     --spacing_base_value: calc(2 + calc(var(--obsPadding) / 2));
 
     --highlight_width: 1px;
-    --highlight_color: var(--primary_lighter); 
-    
+    --highlight_color: var(--primary_lighter);
+
     /* TODO: Better Accessibility focus state */
     /* TODO: Move Accessibilty Colors to Theme config system */
     --border_highlight: "transparent";
@@ -144,7 +144,7 @@
     --scrollbar_size: 12px;
     --settings_scrollbar_size: calc(var(--scrollbar_size) + 9px);
     --scrollbar_handle: var(--grey4);
-    
+
     --scrollbar_bg: var(--grey6);
     --scrollbar_hover: var(--grey3);
     --scrollbar_down: var(--grey2);
@@ -275,6 +275,11 @@
     background-color: var(--bg_base);
 }
 
+.text-title {
+    font-size: var(--font_large);
+    font-weight: bold;
+}
+
 .text-heading {
     font-size: var(--font_heading);
     font-weight: bold;
@@ -305,7 +310,8 @@
 }
 
 .frame-notice {
-    background: var(--bg_preview);
+    background: var(--grey8);
+    border: 1px solid var(--grey6);
     border-radius: var(--border_radius);
     padding: var(--padding_xlarge) var(--padding_large);
 }
@@ -314,6 +320,67 @@
     padding: var(--padding_large) 0px;
 }
 
+.dialog-container {
+    padding: var(--padding_large) var(--padding_xlarge);
+}
+
+.dialog-frame {
+    background-color: var(--grey6);
+    border-radius: var(--border_radius);
+    border: 1px solid var(--border_color);
+    margin: var(--spacing_base);
+}
+
+.dialog-frame > QWidget {
+    margin: var(--spacing_base) 0;
+}
+
+.button-primary {
+    background-color: var(--primary_dark);
+    border-color: var(--primary);
+    outline: none;
+}
+
+.button-primary:hover,
+.button-primary:focus {
+    background-color: var(--primary);
+    border-color: var(--white3);
+}
+
+.button-primary:hover {
+    border-color: var(--primary_light);
+}
+
+.margin {
+    margin: var(--spacing_base);
+}
+
+.margin-x {
+    margin-left: var(--spacing_base);
+    margin-right: var(--spacing_base);
+}
+
+.margin-left {
+    margin-left: var(--spacing_base);
+}
+
+.margin-right {
+    margin-right: var(--spacing_base);
+}
+
+.margin-y {
+    margin-top: var(--spacing_base);
+    margin-bottom: var(--spacing_base);
+}
+
+.margin-top {
+    margin-top: var(--spacing_base);
+}
+
+.margin-bottom {
+    margin-bottom: var(--spacing_base);
+}
+
 /* Icon Overrides */
 
 .icon-plus {
@@ -608,17 +675,14 @@ QMenu::item:selected,
 QListView::item:selected,
 QListWidget::item:selected {
     background-color: var(--primary);
-    border-color: var(--primary);
+    border-color: var(--primary_light);
 }
 
 QMenu::item:hover,
 QListView::item:hover,
-QListWidget::item:hover,
-QMenu::item:selected:hover,
-QListView::item:selected:hover,
-QListWidget::item:selected:hover {
-    background-color: var(--primary_light);
-    border-color: var(--highlight_color);
+QListWidget::item:hover {
+    background: var(--grey4);
+    border: 1px solid var(--grey3);
 }
 
 QMenu::item:focus,
@@ -627,7 +691,15 @@ QListWidget::item:focus,
 QMenu::item:selected:focus,
 QListView::item:selected:focus,
 QListWidget::item:selected:focus {
-    border: 1px solid var(--border_highlight);
+    border: 1px solid var(--white3);
+}
+
+QMenu::item:selected:hover,
+QListView::item:selected:hover,
+QListWidget::item:selected:hover {
+    background: var(--primary_light);
+    border: 1px solid var(--primary_lighter);
+    color: var(--text);
 }
 
 QListView::item:disabled,
@@ -655,7 +727,6 @@ QListWidget QLineEdit:focus {
 /* Settings QList */
 
 OBSBasicSettings QScrollBar:vertical {
-    width: var(--scrollbar_size);
     width: var(--settings_scrollbar_size);
     margin-left: 9px;
 }
@@ -882,14 +953,6 @@ QScrollBar::handle:disabled {
     border-color: transparent;
 }
 
-OBSDock QListWidget {
-    padding: 0;
-}
-
-OBSDock QListWidget::item {
-    margin: 0 var(--spacing_base);
-}
-
 OBSDock QScrollBar {
     border-radius: 0;
 }

+ 0 - 5
frontend/data/themes/Yami_Classic.ovt

@@ -110,11 +110,6 @@ QDockWidget > QWidget {
     padding: var(--padding_xlarge);
 }
 
-SceneTree::item,
-SourceTreeItem {
-    border-width: 0px;
-}
-
 QMenu::item {
     padding: var(--padding_menu_y) var(--padding_menu);
 }

+ 337 - 22
frontend/forms/PluginManagerWindow.ui

@@ -6,7 +6,7 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>850</width>
+    <width>861</width>
     <height>400</height>
    </rect>
   </property>
@@ -16,31 +16,346 @@
   <property name="sizeGripEnabled">
    <bool>true</bool>
   </property>
-  <layout class="QGridLayout" name="gridLayout">
-   <item row="2" column="0">
-    <layout class="QHBoxLayout" name="horizontalLayout_4">
-     <property name="spacing">
-      <number>6</number>
+  <layout class="QVBoxLayout" name="verticalLayout_3">
+   <property name="leftMargin">
+    <number>0</number>
+   </property>
+   <property name="topMargin">
+    <number>0</number>
+   </property>
+   <property name="rightMargin">
+    <number>0</number>
+   </property>
+   <property name="bottomMargin">
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="QFrame" name="dialogInner">
+     <property name="frameShape">
+      <enum>QFrame::NoFrame</enum>
      </property>
-     <item>
-      <widget class="QDialogButtonBox" name="buttonBox">
-       <property name="standardButtons">
-        <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
-       </property>
-      </widget>
-     </item>
-    </layout>
-   </item>
-   <item row="0" column="0">
-    <widget class="QLabel" name="label">
-     <property name="text">
-      <string>PluginManager.HelpText</string>
+     <property name="frameShadow">
+      <enum>QFrame::Plain</enum>
+     </property>
+     <property name="lineWidth">
+      <number>0</number>
      </property>
+     <property name="class" stdset="0">
+      <string>dialog-container</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_2">
+      <property name="spacing">
+       <number>0</number>
+      </property>
+      <property name="leftMargin">
+       <number>0</number>
+      </property>
+      <property name="topMargin">
+       <number>0</number>
+      </property>
+      <property name="rightMargin">
+       <number>0</number>
+      </property>
+      <property name="bottomMargin">
+       <number>0</number>
+      </property>
+      <item>
+       <widget class="QFrame" name="frame">
+        <property name="frameShape">
+         <enum>QFrame::NoFrame</enum>
+        </property>
+        <property name="frameShadow">
+         <enum>QFrame::Plain</enum>
+        </property>
+        <property name="lineWidth">
+         <number>0</number>
+        </property>
+        <layout class="QHBoxLayout" name="horizontalLayout" stretch="1,4">
+         <property name="spacing">
+          <number>0</number>
+         </property>
+         <property name="leftMargin">
+          <number>0</number>
+         </property>
+         <property name="topMargin">
+          <number>0</number>
+         </property>
+         <property name="rightMargin">
+          <number>0</number>
+         </property>
+         <property name="bottomMargin">
+          <number>0</number>
+         </property>
+         <item>
+          <widget class="QFrame" name="sectionFrame">
+           <property name="frameShape">
+            <enum>QFrame::NoFrame</enum>
+           </property>
+           <property name="frameShadow">
+            <enum>QFrame::Plain</enum>
+           </property>
+           <property name="lineWidth">
+            <number>0</number>
+           </property>
+           <property name="class" stdset="0">
+            <string>dialog-frame</string>
+           </property>
+           <layout class="QVBoxLayout" name="verticalLayout">
+            <property name="spacing">
+             <number>0</number>
+            </property>
+            <property name="leftMargin">
+             <number>0</number>
+            </property>
+            <property name="topMargin">
+             <number>0</number>
+            </property>
+            <property name="rightMargin">
+             <number>0</number>
+            </property>
+            <property name="bottomMargin">
+             <number>0</number>
+            </property>
+            <item>
+             <widget class="QListWidget" name="sectionList">
+              <property name="frameShape">
+               <enum>QFrame::NoFrame</enum>
+              </property>
+              <property name="frameShadow">
+               <enum>QFrame::Plain</enum>
+              </property>
+              <property name="lineWidth">
+               <number>0</number>
+              </property>
+              <property name="editTriggers">
+               <set>QAbstractItemView::NoEditTriggers</set>
+              </property>
+              <property name="showDropIndicator" stdset="0">
+               <bool>false</bool>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </widget>
+         </item>
+         <item>
+          <widget class="QFrame" name="modulesFrame">
+           <property name="frameShape">
+            <enum>QFrame::NoFrame</enum>
+           </property>
+           <property name="frameShadow">
+            <enum>QFrame::Plain</enum>
+           </property>
+           <property name="lineWidth">
+            <number>0</number>
+           </property>
+           <property name="class" stdset="0">
+            <string>dialog-container dialog-frame</string>
+           </property>
+           <layout class="QVBoxLayout" name="verticalLayout_4">
+            <property name="spacing">
+             <number>0</number>
+            </property>
+            <property name="leftMargin">
+             <number>0</number>
+            </property>
+            <property name="topMargin">
+             <number>0</number>
+            </property>
+            <property name="rightMargin">
+             <number>0</number>
+            </property>
+            <property name="bottomMargin">
+             <number>0</number>
+            </property>
+            <item>
+             <widget class="QLabel" name="label">
+              <property name="frameShape">
+               <enum>QFrame::NoFrame</enum>
+              </property>
+              <property name="lineWidth">
+               <number>0</number>
+              </property>
+              <property name="text">
+               <string>PluginManager.Section.Manage.Title</string>
+              </property>
+              <property name="class" stdset="0">
+               <string>text-title</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QScrollArea" name="modulesListContainer">
+              <property name="frameShape">
+               <enum>QFrame::NoFrame</enum>
+              </property>
+              <property name="frameShadow">
+               <enum>QFrame::Plain</enum>
+              </property>
+              <property name="lineWidth">
+               <number>0</number>
+              </property>
+              <property name="horizontalScrollBarPolicy">
+               <enum>Qt::ScrollBarAlwaysOff</enum>
+              </property>
+              <property name="sizeAdjustPolicy">
+               <enum>QAbstractScrollArea::AdjustToContents</enum>
+              </property>
+              <property name="widgetResizable">
+               <bool>false</bool>
+              </property>
+              <property name="alignment">
+               <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+              </property>
+              <property name="class" stdset="0">
+               <string/>
+              </property>
+              <widget class="QWidget" name="modulesListContents">
+               <property name="geometry">
+                <rect>
+                 <x>0</x>
+                 <y>0</y>
+                 <width>689</width>
+                 <height>50</height>
+                </rect>
+               </property>
+               <property name="sizePolicy">
+                <sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
+                 <horstretch>0</horstretch>
+                 <verstretch>0</verstretch>
+                </sizepolicy>
+               </property>
+               <layout class="QVBoxLayout" name="verticalLayout_5">
+                <property name="spacing">
+                 <number>0</number>
+                </property>
+                <property name="leftMargin">
+                 <number>0</number>
+                </property>
+                <property name="topMargin">
+                 <number>0</number>
+                </property>
+                <property name="rightMargin">
+                 <number>0</number>
+                </property>
+                <property name="bottomMargin">
+                 <number>0</number>
+                </property>
+                <item>
+                 <widget class="QFrame" name="modulesList">
+                  <property name="minimumSize">
+                   <size>
+                    <width>0</width>
+                    <height>20</height>
+                   </size>
+                  </property>
+                  <property name="frameShape">
+                   <enum>QFrame::NoFrame</enum>
+                  </property>
+                  <property name="frameShadow">
+                   <enum>QFrame::Plain</enum>
+                  </property>
+                  <property name="lineWidth">
+                   <number>0</number>
+                  </property>
+                  <layout class="QVBoxLayout" name="verticalLayout_6">
+                   <property name="spacing">
+                    <number>0</number>
+                   </property>
+                   <property name="leftMargin">
+                    <number>0</number>
+                   </property>
+                   <property name="topMargin">
+                    <number>0</number>
+                   </property>
+                   <property name="rightMargin">
+                    <number>0</number>
+                   </property>
+                   <property name="bottomMargin">
+                    <number>0</number>
+                   </property>
+                  </layout>
+                 </widget>
+                </item>
+                <item>
+                 <spacer name="verticalSpacer">
+                  <property name="orientation">
+                   <enum>Qt::Vertical</enum>
+                  </property>
+                  <property name="sizeHint" stdset="0">
+                   <size>
+                    <width>10</width>
+                    <height>0</height>
+                   </size>
+                  </property>
+                 </spacer>
+                </item>
+               </layout>
+              </widget>
+             </widget>
+            </item>
+            <item>
+             <widget class="QLabel" name="manageRestartLabel">
+              <property name="text">
+               <string>PluginManager.Restart</string>
+              </property>
+              <property name="alignment">
+               <set>Qt::AlignCenter</set>
+              </property>
+              <property name="class" stdset="0">
+               <string>frame-notice</string>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </item>
+      <item>
+       <widget class="QFrame" name="footer">
+        <property name="frameShape">
+         <enum>QFrame::NoFrame</enum>
+        </property>
+        <property name="frameShadow">
+         <enum>QFrame::Plain</enum>
+        </property>
+        <property name="lineWidth">
+         <number>0</number>
+        </property>
+        <property name="class" stdset="0">
+         <string>dialog-container</string>
+        </property>
+        <layout class="QHBoxLayout" name="horizontalLayout_2">
+         <property name="spacing">
+          <number>0</number>
+         </property>
+         <property name="leftMargin">
+          <number>0</number>
+         </property>
+         <property name="topMargin">
+          <number>0</number>
+         </property>
+         <property name="rightMargin">
+          <number>0</number>
+         </property>
+         <property name="bottomMargin">
+          <number>0</number>
+         </property>
+         <item>
+          <widget class="QDialogButtonBox" name="buttonBox">
+           <property name="standardButtons">
+            <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </item>
+     </layout>
     </widget>
    </item>
-   <item row="1" column="0">
-    <widget class="QListWidget" name="modulesList"/>
-   </item>
   </layout>
  </widget>
  <resources/>

+ 2 - 2
frontend/plugin-manager/PluginManager.cpp

@@ -297,8 +297,8 @@ void PluginManager::open()
 		}
 
 		if (changed) {
-			QMessageBox::StandardButton button = OBSMessageBox::question(
-				main, QTStr("PluginManager.Restart"), QTStr("PluginManager.NeedsRestart"));
+			QMessageBox::StandardButton button =
+				OBSMessageBox::question(main, QTStr("Restart"), QTStr("NeedsRestart"));
 
 			if (button == QMessageBox::Yes) {
 				restart = true;

+ 81 - 10
frontend/plugin-manager/PluginManagerWindow.cpp

@@ -40,12 +40,40 @@ PluginManagerWindow::PluginManagerWindow(std::vector<ModuleInfo> const &modules,
 
 	ui->setupUi(this);
 
+	ui->modulesListContainer->viewport()->setAutoFillBackground(false);
+	ui->modulesListContents->setAutoFillBackground(false);
+
+	// Set up sidebar entries
+	ui->sectionList->clear();
+	ui->sectionList->setSelectionMode(QAbstractItemView::SingleSelection);
+
+	connect(ui->sectionList, &QListWidget::itemSelectionChanged, this,
+		&PluginManagerWindow::sectionSelectionChanged);
+
+	QListWidgetItem *browse = new QListWidgetItem(QTStr("PluginManager.Section.Discover"));
+	browse->setFlags(browse->flags() & ~Qt::ItemIsEnabled);
+	browse->setFlags(browse->flags() & ~Qt::ItemIsSelectable);
+	browse->setToolTip(QTStr("ComingSoon"));
+	ui->sectionList->addItem(browse);
+
+	QListWidgetItem *installed = new QListWidgetItem(QTStr("PluginManager.Section.Manage"));
+	ui->sectionList->addItem(installed);
+
+	QListWidgetItem *updates = new QListWidgetItem(QTStr("PluginManager.Section.Updates"));
+	updates->setFlags(updates->flags() & ~Qt::ItemIsEnabled);
+	updates->setFlags(updates->flags() & ~Qt::ItemIsSelectable);
+	updates->setToolTip(QTStr("ComingSoon"));
+	ui->sectionList->addItem(updates);
+
+	setSection(ui->sectionList->indexFromItem(installed));
+
 	std::sort(modules_.begin(), modules_.end(), [](const ModuleInfo &a, const ModuleInfo &b) {
 		std::string aName = !a.display_name.empty() ? a.display_name : a.module_name;
 		std::string bName = !b.display_name.empty() ? b.display_name : b.module_name;
 		return aName < bName;
 	});
 
+	int row = 0;
 	for (auto &metadata : modules_) {
 		std::string id = metadata.module_name;
 		// Check if the module is missing:
@@ -56,24 +84,67 @@ PluginManagerWindow::PluginManagerWindow(std::vector<ModuleInfo> const &modules,
 		if (missing) {
 			name += " " + QTStr("PluginManager.MissingPlugin");
 		}
-		auto item = new QListWidgetItem(name);
-		item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
-		item->setCheckState(metadata.enabled ? Qt::Checked : Qt::Unchecked);
+
+		auto item = new QCheckBox(name);
+		item->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
+		item->setChecked(metadata.enabled);
+
+		if (!metadata.enabledAtLaunch) {
+			item->setProperty("class", "text-muted");
+		}
 
 		if (missing) {
-			item->setFlags(item->flags() & ~Qt::ItemIsEnabled);
+			item->setEnabled(false);
 		}
-		ui->modulesList->addItem(item);
+		ui->modulesList->layout()->addWidget(item);
+
+		connect(item, &QCheckBox::toggled, this, [this, row](bool checked) {
+			modules_[row].enabled = checked;
+			ui->manageRestartLabel->setVisible(isEnabledPluginsChanged());
+		});
+
+		row++;
 	}
 
-	connect(ui->modulesList, &QListWidget::itemChanged, this, [this](QListWidgetItem *item) {
-		auto row = ui->modulesList->row(item);
-		bool checked = item->checkState() == Qt::Checked;
-		modules_[row].enabled = checked;
-	});
+	ui->modulesList->adjustSize();
+	ui->modulesListContents->adjustSize();
+
+	ui->manageRestartLabel->setVisible(isEnabledPluginsChanged());
 
 	connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
 	connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
 }
 
+void PluginManagerWindow::sectionSelectionChanged()
+{
+	auto selected = ui->sectionList->selectedItems();
+	if (selected.count() != 1) {
+		setSection(activeSectionIndex);
+	} else {
+		auto selectionIndex = ui->sectionList->indexFromItem(selected.first());
+		setSection(selectionIndex);
+	}
+}
+
+void PluginManagerWindow::setSection(QPersistentModelIndex index)
+{
+	if (ui->sectionList->itemFromIndex(index)) {
+		activeSectionIndex = index;
+		ui->sectionList->setCurrentIndex(index);
+	}
+}
+
+bool PluginManagerWindow::isEnabledPluginsChanged()
+{
+	bool result = false;
+	for (auto &metadata : modules_) {
+		if (metadata.enabledAtLaunch != metadata.enabled) {
+			result = true;
+			break;
+		}
+	}
+
+	return result;
+}
+
 }; // namespace OBS

+ 6 - 0
frontend/plugin-manager/PluginManagerWindow.hpp

@@ -35,6 +35,12 @@ public:
 
 private:
 	std::vector<ModuleInfo> modules_;
+
+	void sectionSelectionChanged();
+	QPersistentModelIndex activeSectionIndex;
+	void setSection(QPersistentModelIndex index);
+
+	bool isEnabledPluginsChanged();
 };
 
 }; // namespace OBS