gplugin/gplugin

Split plugin details into a separate page

19 months ago, Elliott Sales de Andrade
fcd52dc4273e
Parents 2ab8afb6e8be
Children 7ccf3db483d1
Split plugin details into a separate page

This modifies the `GPluginGtkView` into a stack, showing the list of plugins by default (called the 'overview'), or a page for a specific plugin. Going back and forth is automated, but an application can request the page for a plugin directly if needed.

The plugin row no longer expands to show details or shows a config button, but its activation goes to its own page now. This also makes each row a bit more balanced vertically, since there's no `GtkRevealer` taking up invisible space underneath.

The new plugin page is _mostly_ a copy of the previous plugin row, except:

* It's always expanded (or rather, it cannot be collapsed.)
* The main details are re-arranged a bit to fit nicely on a page.
* All information is found via `GtkExpression`s.
* Instead of separate labels for each author/dependency, these are now a single newline-separated label, which is easier to generate.
* Booleans display a check mark instead of text, like in the inspector.
* Information labels are selectable and have a `labelled-by` relation.
* The error message is allowed to wrap.

Settings, once implemented, can go at the end of this page.

I debated splitting the plugin info into a stack with 'important' vs 'developer-oriented' entries (somewhat how `GtkAboutDialog` splits its information), but that can go in a separate review if it's done.

NOTE: This deletes the `expanded` property from `GPluginGtkPluginRow`; that's probably an ABI break, though /r/1834 means it was never registered in a released version.

Testing Done:
Opened the separate page of a few plugins, and saw that details were available. Also, the switch was in sync with the switch in the overview.

Reviewed at https://reviews.imfreedom.org/r/1840/
--- a/gplugin-gtk4/data/gplugin-gtk.gresource.xml Mon Sep 26 00:03:15 2022 -0500
+++ b/gplugin-gtk4/data/gplugin-gtk.gresource.xml Mon Sep 26 00:42:07 2022 -0500
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/imfreedom/keep/gplugin/gplugin-gtk/">
+ <file compressed="true">plugin-page.ui</file>
<file compressed="true">plugin-row.ui</file>
<file compressed="true">view.ui</file>
</gresource>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gplugin-gtk4/data/plugin-page.ui Mon Sep 26 00:42:07 2022 -0500
@@ -0,0 +1,451 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk" version="4.0"/>
+ <template class="GPluginGtkPluginPage" parent="GtkBox">
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkBox">
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkBox">
+ <property name="orientation">horizontal</property>
+ <property name="valign">center</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="css-classes">title-1</property>
+ <property name="hexpand">1</property>
+ <binding name="label">
+ <closure type="gchararray" function="gplugin_gtk_lookup_plugin_name">
+ <lookup name="info" type="GPluginPlugin">
+ <lookup name="plugin">GPluginGtkPluginPage</lookup>
+ </lookup>
+ <lookup name="filename" type="GPluginPlugin">
+ <lookup name="plugin">GPluginGtkPluginPage</lookup>
+ </lookup>
+ </closure>
+ </binding>
+ <property name="wrap">1</property>
+ <property name="wrap-mode">word-char</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkSwitch">
+ <property name="halign">end</property>
+ <property name="valign">center</property>
+ <binding name="sensitive">
+ <closure type="gboolean" function="gplugin_gtk_lookup_plugin_state_sensitivity">
+ <lookup name="state" type="GPluginPlugin">
+ <lookup name="plugin">GPluginGtkPluginPage</lookup>
+ </lookup>
+ </closure>
+ </binding>
+ <binding name="state">
+ <closure type="gboolean" function="gplugin_gtk_lookup_plugin_state">
+ <lookup name="state" type="GPluginPlugin">
+ <lookup name="plugin">GPluginGtkPluginPage</lookup>
+ </lookup>
+ </closure>
+ </binding>
+ <signal name="state-set" handler="gplugin_gtk_plugin_page_enable_state_set_cb"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="orientation">horizontal</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="css-classes">dim-label</property>
+ <property name="halign">start</property>
+ <property name="hexpand">1</property>
+ <binding name="label">
+ <lookup name="summary" type="GPluginPluginInfo">
+ <lookup name="info" type="GPluginPlugin">
+ <lookup name="plugin">GPluginGtkPluginPage</lookup>
+ </lookup>
+ </lookup>
+ </binding>
+ <property name="wrap">1</property>
+ <property name="wrap-mode">word-char</property>
+ <property name="ellipsize">end</property>
+ <property name="xalign">0</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="css-classes">dim-label</property>
+ <property name="halign">end</property>
+ <binding name="label">
+ <lookup name="version" type="GPluginPluginInfo">
+ <lookup name="info" type="GPluginPlugin">
+ <lookup name="plugin">GPluginGtkPluginPage</lookup>
+ </lookup>
+ </lookup>
+ </binding>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="description">
+ <binding name="label">
+ <lookup name="description" type="GPluginPluginInfo">
+ <lookup name="info" type="GPluginPlugin">
+ <lookup name="plugin">GPluginGtkPluginPage</lookup>
+ </lookup>
+ </lookup>
+ </binding>
+ <property name="wrap">1</property>
+ <property name="xalign">0</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkFrame">
+ <property name="child">
+ <object class="GtkListBox">
+ <property name="css-classes">rich-list</property>
+ <property name="selection-mode">none</property>
+ <property name="show-separators">1</property>
+ <child>
+ <object class="GtkListBoxRow">
+ <property name="activatable">0</property>
+ <property name="child">
+ <object class="GtkBox">
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="authors-label">
+ <property name="label" translatable="1">Authors</property>
+ <property name="xalign">0</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="selectable">1</property>
+ <binding name="label">
+ <closure type="gchararray" function="gplugin_gtk_plugin_page_newline_strjoinv_cb">
+ <lookup name="authors" type="GPluginPluginInfo">
+ <lookup name="info" type="GPluginPlugin">
+ <lookup name="plugin">GPluginGtkPluginPage</lookup>
+ </lookup>
+ </lookup>
+ </closure>
+ </binding>
+ <accessibility>
+ <relation name="labelled-by">authors-label</relation>
+ </accessibility>
+ </object>
+ </child>
+ </object>
+ </property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkListBoxRow">
+ <property name="activatable">0</property>
+ <property name="child">
+ <object class="GtkBox">
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="website-label">
+ <property name="label" translatable="1">Website</property>
+ <property name="xalign">0</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="use-markup">1</property>
+ <binding name="label">
+ <closure type="gchararray" function="gplugin_gtk_plugin_page_lookup_website_cb">
+ <lookup name="website" type="GPluginPluginInfo">
+ <lookup name="info" type="GPluginPlugin">
+ <lookup name="plugin">GPluginGtkPluginPage</lookup>
+ </lookup>
+ </lookup>
+ </closure>
+ </binding>
+ <accessibility>
+ <relation name="labelled-by">website-label</relation>
+ </accessibility>
+ </object>
+ </child>
+ </object>
+ </property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkListBoxRow">
+ <property name="activatable">0</property>
+ <property name="child">
+ <object class="GtkBox">
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="dependencies-label">
+ <property name="label" translatable="1">Dependencies</property>
+ <property name="xalign">0</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="selectable">1</property>
+ <binding name="label">
+ <closure type="gchararray" function="gplugin_gtk_plugin_page_newline_strjoinv_cb">
+ <lookup name="dependencies" type="GPluginPluginInfo">
+ <lookup name="info" type="GPluginPlugin">
+ <lookup name="plugin">GPluginGtkPluginPage</lookup>
+ </lookup>
+ </lookup>
+ </closure>
+ </binding>
+ <accessibility>
+ <relation name="labelled-by">dependencies-label</relation>
+ </accessibility>
+ </object>
+ </child>
+ </object>
+ </property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkListBoxRow">
+ <property name="activatable">0</property>
+ <property name="child">
+ <object class="GtkBox">
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="error-label">
+ <property name="label" translatable="1">Error</property>
+ <property name="xalign">0</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="selectable">1</property>
+ <property name="wrap">1</property>
+ <binding name="label">
+ <closure type="gchararray" function="gplugin_gtk_plugin_page_lookup_error_cb">
+ <lookup name="error" type="GPluginPlugin">
+ <lookup name="plugin">GPluginGtkPluginPage</lookup>
+ </lookup>
+ </closure>
+ </binding>
+ <accessibility>
+ <relation name="labelled-by">error-label</relation>
+ </accessibility>
+ </object>
+ </child>
+ </object>
+ </property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkListBoxRow">
+ <property name="activatable">0</property>
+ <property name="child">
+ <object class="GtkBox">
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="id-label">
+ <property name="label" translatable="1">ID</property>
+ <property name="xalign">0</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="selectable">1</property>
+ <binding name="label">
+ <lookup name="id" type="GPluginPluginInfo">
+ <lookup name="info" type="GPluginPlugin">
+ <lookup name="plugin">GPluginGtkPluginPage</lookup>
+ </lookup>
+ </lookup>
+ </binding>
+ <accessibility>
+ <relation name="labelled-by">id-label</relation>
+ </accessibility>
+ </object>
+ </child>
+ </object>
+ </property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkListBoxRow">
+ <property name="activatable">0</property>
+ <property name="child">
+ <object class="GtkBox">
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="filename-label">
+ <property name="label" translatable="1">Filename</property>
+ <property name="xalign">0</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="selectable">1</property>
+ <property name="ellipsize">start</property>
+ <binding name="label">
+ <lookup name="filename" type="GPluginPlugin">
+ <lookup name="plugin">GPluginGtkPluginPage</lookup>
+ </lookup>
+ </binding>
+ <accessibility>
+ <relation name="labelled-by">filename-label</relation>
+ </accessibility>
+ </object>
+ </child>
+ </object>
+ </property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkListBoxRow">
+ <property name="activatable">0</property>
+ <property name="child">
+ <object class="GtkBox">
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="abi-version-label">
+ <property name="label" translatable="1">ABI Version</property>
+ <property name="xalign">0</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="selectable">1</property>
+ <binding name="label">
+ <closure type="gchararray" function="gplugin_gtk_plugin_page_lookup_abi_version_cb">
+ <lookup name="abi-version" type="GPluginPluginInfo">
+ <lookup name="info" type="GPluginPlugin">
+ <lookup name="plugin">GPluginGtkPluginPage</lookup>
+ </lookup>
+ </lookup>
+ </closure>
+ </binding>
+ <accessibility>
+ <relation name="labelled-by">abi-version-label</relation>
+ </accessibility>
+ </object>
+ </child>
+ </object>
+ </property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkListBoxRow">
+ <property name="activatable">0</property>
+ <property name="child">
+ <object class="GtkBox">
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="loader-label">
+ <property name="label" translatable="1">Loader</property>
+ <property name="xalign">0</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="selectable">1</property>
+ <binding name="label">
+ <closure type="gchararray" function="gplugin_gtk_plugin_page_lookup_loader_cb">
+ <lookup name="plugin">GPluginGtkPluginPage</lookup>
+ </closure>
+ </binding>
+ <accessibility>
+ <relation name="labelled-by">loader-label</relation>
+ </accessibility>
+ </object>
+ </child>
+ </object>
+ </property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkListBoxRow">
+ <property name="activatable">0</property>
+ <property name="child">
+ <object class="GtkBox">
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="internal-label">
+ <property name="label" translatable="1">Internal</property>
+ <property name="xalign">0</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkImage">
+ <property name="icon-name">object-select-symbolic</property>
+ <binding name="visible">
+ <lookup name="internal" type="GPluginPluginInfo">
+ <lookup name="info" type="GPluginPlugin">
+ <lookup name="plugin">GPluginGtkPluginPage</lookup>
+ </lookup>
+ </lookup>
+ </binding>
+ <accessibility>
+ <relation name="labelled-by">internal-label</relation>
+ </accessibility>
+ </object>
+ </child>
+ </object>
+ </property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkListBoxRow">
+ <property name="activatable">0</property>
+ <property name="child">
+ <object class="GtkBox">
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="load-on-query-label">
+ <property name="label" translatable="1">Load on Query</property>
+ <property name="xalign">0</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkImage">
+ <property name="icon-name">object-select-symbolic</property>
+ <binding name="visible">
+ <lookup name="load-on-query" type="GPluginPluginInfo">
+ <lookup name="info" type="GPluginPlugin">
+ <lookup name="plugin">GPluginGtkPluginPage</lookup>
+ </lookup>
+ </lookup>
+ </binding>
+ <accessibility>
+ <relation name="labelled-by">load-on-query-label</relation>
+ </accessibility>
+ </object>
+ </child>
+ </object>
+ </property>
+ </object>
+ </child>
+ </object>
+ </property>
+ </object>
+ </child>
+ </template>
+ <object class="GtkSizeGroup">
+ <property name="mode">horizontal</property>
+ <widgets>
+ <widget name="authors-label"/>
+ <widget name="website-label"/>
+ <widget name="dependencies-label"/>
+ <widget name="error-label"/>
+ <widget name="id-label"/>
+ <widget name="filename-label"/>
+ <widget name="abi-version-label"/>
+ <widget name="loader-label"/>
+ <widget name="internal-label"/>
+ <widget name="load-on-query-label"/>
+ </widgets>
+ </object>
+</interface>
--- a/gplugin-gtk4/data/plugin-row.ui Mon Sep 26 00:03:15 2022 -0500
+++ b/gplugin-gtk4/data/plugin-row.ui Mon Sep 26 00:42:07 2022 -0500
@@ -94,333 +94,12 @@
</object>
</child>
<child>
- <object class="GtkButton" id="config">
- <property name="css-classes">circular</property>
- <property name="receives-default">1</property>
- <property name="valign">center</property>
- <property name="child">
- <object class="GtkImage">
- <property name="margin-start">6</property>
- <property name="margin-end">6</property>
- <property name="margin-top">6</property>
- <property name="margin-bottom">6</property>
- <property name="icon-name">preferences-system-symbolic</property>
- </object>
- </property>
- </object>
- </child>
- <child>
- <object class="GtkSeparator">
- <property name="orientation">vertical</property>
- </object>
- </child>
- <child>
- <object class="GtkExpander" id="expander">
- <property name="halign">center</property>
- <property name="valign">center</property>
+ <object class="GtkImage">
+ <property name="icon-name">go-next-symbolic</property>
</object>
</child>
</object>
</child>
- <child>
- <object class="GtkRevealer" id="revealer">
- <property name="reveal-child" bind-source="expander" bind-property="expanded" bind-flags="bidirectional|sync-create"/>
- <property name="child">
- <object class="GtkBox">
- <property name="orientation">vertical</property>
- <property name="spacing">12</property>
- <child>
- <object class="GtkLabel" id="description">
- <property name="margin-start">12</property>
- <property name="margin-end">12</property>
- <property name="margin-top">12</property>
- <property name="margin-bottom">12</property>
- <property name="label">A longer description of what this plugin does.</property>
- <property name="wrap">1</property>
- <property name="xalign">0</property>
- </object>
- </child>
- <child>
- <object class="GtkListBox">
- <property name="css-classes">nested</property>
- <child>
- <object class="GtkListBoxRow">
- <property name="activatable">0</property>
- <property name="selectable">0</property>
- <property name="child">
- <object class="GtkBox">
- <property name="margin-start">12</property>
- <property name="margin-end">12</property>
- <property name="margin-top">12</property>
- <property name="margin-bottom">12</property>
- <property name="spacing">12</property>
- <child>
- <object class="GtkLabel" id="authors_label">
- <property name="label" translatable="1">Authors</property>
- <property name="xalign">0</property>
- </object>
- </child>
- <child>
- <object class="GtkBox" id="authors_box">
- <property name="orientation">vertical</property>
- <child>
- <object class="GtkLabel">
- <property name="label">An Author &lt;author@example.com&gt;</property>
- </object>
- </child>
- </object>
- </child>
- </object>
- </property>
- </object>
- </child>
- <child>
- <object class="GtkListBoxRow">
- <property name="activatable">0</property>
- <property name="selectable">0</property>
- <property name="child">
- <object class="GtkBox">
- <property name="margin-start">12</property>
- <property name="margin-end">12</property>
- <property name="margin-top">12</property>
- <property name="margin-bottom">12</property>
- <property name="spacing">12</property>
- <child>
- <object class="GtkLabel" id="website_label">
- <property name="label" translatable="1">Website</property>
- <property name="xalign">0</property>
- </object>
- </child>
- <child>
- <object class="GtkLabel" id="website">
- <property name="label">&lt;a href=&quot;https://pidgin.im&quot;&gt;https://pidgin.im&lt;/a&gt;</property>
- <property name="use-markup">1</property>
- </object>
- </child>
- </object>
- </property>
- </object>
- </child>
- <child>
- <object class="GtkListBoxRow">
- <property name="activatable">0</property>
- <property name="selectable">0</property>
- <property name="child">
- <object class="GtkBox">
- <property name="margin-start">12</property>
- <property name="margin-end">12</property>
- <property name="margin-top">12</property>
- <property name="margin-bottom">12</property>
- <property name="spacing">12</property>
- <child>
- <object class="GtkLabel" id="dependencies_label">
- <property name="label" translatable="1">Dependencies</property>
- <property name="xalign">0</property>
- </object>
- </child>
- <child>
- <object class="GtkBox" id="dependencies_box">
- <property name="orientation">vertical</property>
- <child>
- <object class="GtkLabel">
- <property name="label">(none)</property>
- </object>
- </child>
- </object>
- </child>
- </object>
- </property>
- </object>
- </child>
- <child>
- <object class="GtkListBoxRow">
- <property name="activatable">0</property>
- <property name="selectable">0</property>
- <property name="child">
- <object class="GtkBox">
- <property name="margin-start">12</property>
- <property name="margin-end">12</property>
- <property name="margin-top">12</property>
- <property name="margin-bottom">12</property>
- <property name="spacing">12</property>
- <child>
- <object class="GtkLabel" id="error_label">
- <property name="label" translatable="1">Error</property>
- <property name="xalign">0</property>
- </object>
- </child>
- <child>
- <object class="GtkLabel" id="error">
- <property name="label">(none)</property>
- </object>
- </child>
- </object>
- </property>
- </object>
- </child>
- <child>
- <object class="GtkListBoxRow">
- <property name="activatable">0</property>
- <property name="selectable">0</property>
- <property name="child">
- <object class="GtkBox">
- <property name="margin-start">12</property>
- <property name="margin-end">12</property>
- <property name="margin-top">12</property>
- <property name="margin-bottom">12</property>
- <property name="spacing">12</property>
- <child>
- <object class="GtkLabel" id="id_label">
- <property name="label" translatable="1">ID</property>
- <property name="xalign">0</property>
- </object>
- </child>
- <child>
- <object class="GtkLabel" id="id">
- <property name="label">gplugin/example-plugin</property>
- </object>
- </child>
- </object>
- </property>
- </object>
- </child>
- <child>
- <object class="GtkListBoxRow">
- <property name="activatable">0</property>
- <property name="selectable">0</property>
- <property name="child">
- <object class="GtkBox">
- <property name="margin-start">12</property>
- <property name="margin-end">12</property>
- <property name="margin-top">12</property>
- <property name="margin-bottom">12</property>
- <property name="spacing">12</property>
- <child>
- <object class="GtkLabel" id="filename_label">
- <property name="label" translatable="1">Filename</property>
- <property name="xalign">0</property>
- </object>
- </child>
- <child>
- <object class="GtkLabel" id="filename">
- <property name="label">/the/full/path/to/plugin.so</property>
- <property name="ellipsize">start</property>
- </object>
- </child>
- </object>
- </property>
- </object>
- </child>
- <child>
- <object class="GtkListBoxRow">
- <property name="activatable">0</property>
- <property name="selectable">0</property>
- <property name="child">
- <object class="GtkBox">
- <property name="margin-start">12</property>
- <property name="margin-end">12</property>
- <property name="margin-top">12</property>
- <property name="margin-bottom">12</property>
- <property name="spacing">12</property>
- <child>
- <object class="GtkLabel" id="abi_version_label">
- <property name="label" translatable="1">ABI Version</property>
- <property name="xalign">0</property>
- </object>
- </child>
- <child>
- <object class="GtkLabel" id="abi_version">
- <property name="label">DEADC0DE</property>
- </object>
- </child>
- </object>
- </property>
- </object>
- </child>
- <child>
- <object class="GtkListBoxRow">
- <property name="activatable">0</property>
- <property name="selectable">0</property>
- <property name="child">
- <object class="GtkBox">
- <property name="margin-start">12</property>
- <property name="margin-end">12</property>
- <property name="margin-top">12</property>
- <property name="margin-bottom">12</property>
- <property name="spacing">12</property>
- <child>
- <object class="GtkLabel" id="loader_label">
- <property name="label" translatable="1">Loader</property>
- <property name="xalign">0</property>
- </object>
- </child>
- <child>
- <object class="GtkLabel" id="loader">
- <property name="label">GPluginExampleLoader</property>
- </object>
- </child>
- </object>
- </property>
- </object>
- </child>
- <child>
- <object class="GtkListBoxRow">
- <property name="activatable">0</property>
- <property name="selectable">0</property>
- <property name="child">
- <object class="GtkBox">
- <property name="margin-start">12</property>
- <property name="margin-end">12</property>
- <property name="margin-top">12</property>
- <property name="margin-bottom">12</property>
- <property name="spacing">12</property>
- <child>
- <object class="GtkLabel" id="internal_label">
- <property name="label" translatable="1">Internal</property>
- <property name="xalign">0</property>
- </object>
- </child>
- <child>
- <object class="GtkLabel" id="internal">
- <property name="label">Maybe</property>
- </object>
- </child>
- </object>
- </property>
- </object>
- </child>
- <child>
- <object class="GtkListBoxRow">
- <property name="activatable">0</property>
- <property name="selectable">0</property>
- <property name="child">
- <object class="GtkBox">
- <property name="margin-start">12</property>
- <property name="margin-end">12</property>
- <property name="margin-top">12</property>
- <property name="margin-bottom">12</property>
- <property name="spacing">12</property>
- <child>
- <object class="GtkLabel" id="load_on_query_label">
- <property name="label" translatable="1">Load on Query</property>
- <property name="xalign">0</property>
- </object>
- </child>
- <child>
- <object class="GtkLabel" id="load_on_query">
- <property name="label">Maybe</property>
- </object>
- </child>
- </object>
- </property>
- </object>
- </child>
- </object>
- </child>
- </object>
- </property>
- </object>
- </child>
</object>
</property>
<style>
@@ -428,19 +107,4 @@
<class name="expander"/>
</style>
</template>
- <object class="GtkSizeGroup">
- <property name="mode">horizontal</property>
- <widgets>
- <widget name="authors_label"/>
- <widget name="website_label"/>
- <widget name="dependencies_label"/>
- <widget name="error_label"/>
- <widget name="id_label"/>
- <widget name="filename_label"/>
- <widget name="abi_version_label"/>
- <widget name="loader_label"/>
- <widget name="internal_label"/>
- <widget name="load_on_query_label"/>
- </widgets>
- </object>
</interface>
--- a/gplugin-gtk4/data/view.ui Mon Sep 26 00:03:15 2022 -0500
+++ b/gplugin-gtk4/data/view.ui Mon Sep 26 00:42:07 2022 -0500
@@ -2,46 +2,96 @@
<interface>
<requires lib="gtk" version="4.0"/>
<template class="GPluginGtkView" parent="GtkBox">
- <property name="orientation">vertical</property>
<child>
- <object class="GtkSearchBar" id="search_bar">
- <property name="key-capture-widget">list_box</property>
- <property name="show-close-button">1</property>
+ <object class="GtkStack" id="stack">
+ <property name="transition-type">slide-left-right</property>
+ <property name="vhomogeneous">0</property>
<child>
- <object class="GtkSearchEntry" id="search_entry">
- <signal name="search-changed" handler="gplugin_gtk_view_search_changed"/>
+ <object class="GtkStackPage">
+ <property name="name">overview</property>
+ <property name="child">
+ <object class="GtkScrolledWindow">
+ <property name="hscrollbar_policy">never</property>
+ <property name="vexpand">1</property>
+ <child>
+ <object class="GtkBox">
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkSearchBar" id="search_bar">
+ <property name="key-capture-widget">list_box</property>
+ <property name="show-close-button">1</property>
+ <child>
+ <object class="GtkSearchEntry" id="search_entry">
+ <signal name="search-changed" handler="gplugin_gtk_view_search_changed"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkFrame">
+ <property name="margin-bottom">24</property>
+ <property name="margin-end">24</property>
+ <property name="margin-start">24</property>
+ <property name="margin-top">24</property>
+ <child>
+ <object class="GtkListBox" id="list_box">
+ <property name="css-classes">rich-list</property>
+ <property name="selection-mode">none</property>
+ <property name="show-separators">1</property>
+ <signal name="row-activated" handler="gplugin_gtk_view_row_activated"/>
+ <child type="placeholder">
+ <object class="GtkLabel">
+ <property name="css-classes">large-title</property>
+ <property name="label" translatable="1">No plugins found</property>
+ <property name="margin-bottom">24</property>
+ <property name="margin-end">24</property>
+ <property name="margin-start">24</property>
+ <property name="margin-top">24</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </property>
</object>
</child>
- </object>
- </child>
- <child>
- <object class="GtkScrolledWindow">
- <property name="hscrollbar_policy">never</property>
- <property name="vexpand">1</property>
<child>
- <object class="GtkFrame">
- <property name="margin-bottom">24</property>
- <property name="margin-end">24</property>
- <property name="margin-start">24</property>
- <property name="margin-top">24</property>
- <child>
- <object class="GtkListBox" id="list_box">
- <property name="css-classes">rich-list</property>
- <property name="selection-mode">none</property>
- <property name="show-separators">1</property>
- <signal name="row-activated" handler="gplugin_gtk_view_row_activated"/>
- <child type="placeholder">
- <object class="GtkLabel">
- <property name="css-classes">large-title</property>
- <property name="label" translatable="1">No plugins found</property>
+ <object class="GtkStackPage">
+ <property name="name">plugin-page</property>
+ <property name="child">
+ <object class="GtkScrolledWindow">
+ <property name="hscrollbar_policy">never</property>
+ <property name="vexpand">1</property>
+ <child>
+ <object class="GtkBox">
<property name="margin-bottom">24</property>
<property name="margin-end">24</property>
<property name="margin-start">24</property>
<property name="margin-top">24</property>
+ <property name="orientation">horizontal</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkButton">
+ <property name="css-classes">flat</property>
+ <property name="halign">start</property>
+ <property name="valign">start</property>
+ <property name="icon-name">go-previous-symbolic</property>
+ <signal name="clicked" handler="gplugin_gtk_view_back_clicked_cb" object="GPluginGtkView" swapped="no"/>
+ </object>
+ </child>
+ <child>
+ <object class="GPluginGtkPluginPage" id="plugin_page">
+ <signal name="plugin-state-set" handler="gplugin_gtk_view_plugin_state_set_cb" object="GPluginGtkView" swapped="no"/>
+ </object>
+ </child>
</object>
</child>
</object>
- </child>
+ </property>
</object>
</child>
</object>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gplugin-gtk4/gplugin-gtk-plugin-page.c Mon Sep 26 00:42:07 2022 -0500
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2022 Elliott Sales de Andrade <quantum.analyst@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <glib/gi18n-lib.h>
+
+#include <gplugin.h>
+
+#include <gplugin-gtk-plugin-closures.h>
+#include <gplugin-gtk-plugin-page.h>
+
+/**
+ * GPluginGtkPluginPage:
+ *
+ * A widget that displays a single [iface@GPlugin.Plugin] in a user friendly
+ * way, intended to be placed in a [class@GPluginGtk4.View].
+ *
+ * Since: 0.39.0
+ */
+
+/******************************************************************************
+ * Structs
+ *****************************************************************************/
+struct _GPluginGtkPluginPage {
+ GtkBox parent;
+
+ GPluginPlugin *plugin;
+};
+
+/******************************************************************************
+ * Enums
+ *****************************************************************************/
+enum {
+ PROP_ZERO,
+ PROP_PLUGIN,
+ N_PROPERTIES,
+};
+static GParamSpec *properties[N_PROPERTIES] = {
+ NULL,
+};
+
+enum {
+ SIG_PLUGIN_STATE_SET,
+ N_SIGNALS,
+};
+static guint signals[N_SIGNALS] = {
+ 0,
+};
+
+/******************************************************************************
+ * Callbacks
+ *****************************************************************************/
+static gboolean
+gplugin_gtk_plugin_page_enable_state_set_cb(
+ G_GNUC_UNUSED GtkSwitch *widget,
+ gboolean state,
+ gpointer data)
+{
+ GPluginGtkPluginPage *page = GPLUGIN_GTK_PLUGIN_PAGE(data);
+
+ g_signal_emit(G_OBJECT(page), signals[SIG_PLUGIN_STATE_SET], 0, state);
+
+ return TRUE;
+}
+
+static gchar *
+gplugin_gtk_plugin_page_newline_strjoinv_cb(
+ G_GNUC_UNUSED GtkClosureExpression *expression,
+ gchar **str_array,
+ G_GNUC_UNUSED gpointer data)
+{
+ if(str_array == NULL) {
+ return g_strdup(_("(none)"));
+ }
+
+ return g_strjoinv("\n", str_array);
+}
+
+static gchar *
+gplugin_gtk_plugin_page_lookup_website_cb(
+ G_GNUC_UNUSED GtkClosureExpression *expression,
+ const gchar *website,
+ G_GNUC_UNUSED gpointer data)
+{
+ if(website == NULL) {
+ return NULL;
+ }
+
+ return g_markup_printf_escaped("<a href=\"%s\">%s</a>", website, website);
+}
+
+static gchar *
+gplugin_gtk_plugin_page_lookup_error_cb(
+ G_GNUC_UNUSED GtkClosureExpression *expression,
+ GError *error,
+ G_GNUC_UNUSED gpointer data)
+{
+ if(error == NULL) {
+ return g_strdup(_("(none)"));
+ }
+
+ return g_strdup(error->message);
+}
+
+static gchar *
+gplugin_gtk_plugin_page_lookup_abi_version_cb(
+ G_GNUC_UNUSED GtkClosureExpression *expression,
+ guint32 abi_version,
+ G_GNUC_UNUSED gpointer data)
+{
+ return g_strdup_printf("%08x", abi_version);
+}
+
+static gchar *
+gplugin_gtk_plugin_page_lookup_loader_cb(
+ G_GNUC_UNUSED GtkClosureExpression *expression,
+ GPluginPlugin *plugin,
+ G_GNUC_UNUSED gpointer data)
+{
+ if(GPLUGIN_IS_PLUGIN(plugin)) {
+ GPluginLoader *plugin_loader = gplugin_plugin_get_loader(plugin);
+
+ if(GPLUGIN_IS_LOADER(plugin_loader)) {
+ return g_strdup(G_OBJECT_TYPE_NAME(plugin_loader));
+ }
+ }
+
+ return g_strdup(_("Unknown"));
+}
+
+/******************************************************************************
+ * GObject Implementation
+ *****************************************************************************/
+G_DEFINE_TYPE(GPluginGtkPluginPage, gplugin_gtk_plugin_page, GTK_TYPE_BOX)
+
+static void
+gplugin_gtk_plugin_page_set_property(
+ GObject *obj,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GPluginGtkPluginPage *page = GPLUGIN_GTK_PLUGIN_PAGE(obj);
+
+ switch(prop_id) {
+ case PROP_PLUGIN:
+ gplugin_gtk_plugin_page_set_plugin(page, g_value_get_object(value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gplugin_gtk_plugin_page_get_property(
+ GObject *obj,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GPluginGtkPluginPage *page = GPLUGIN_GTK_PLUGIN_PAGE(obj);
+
+ switch(prop_id) {
+ case PROP_PLUGIN:
+ g_value_set_object(value, gplugin_gtk_plugin_page_get_plugin(page));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gplugin_gtk_plugin_page_dispose(GObject *obj)
+{
+ GPluginGtkPluginPage *page = GPLUGIN_GTK_PLUGIN_PAGE(obj);
+
+ g_clear_object(&page->plugin);
+
+ G_OBJECT_CLASS(gplugin_gtk_plugin_page_parent_class)->dispose(obj);
+}
+
+static void
+gplugin_gtk_plugin_page_init(GPluginGtkPluginPage *page)
+{
+ gtk_widget_init_template(GTK_WIDGET(page));
+}
+
+static void
+gplugin_gtk_plugin_page_class_init(GPluginGtkPluginPageClass *klass)
+{
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
+ GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+
+ obj_class->get_property = gplugin_gtk_plugin_page_get_property;
+ obj_class->set_property = gplugin_gtk_plugin_page_set_property;
+ obj_class->dispose = gplugin_gtk_plugin_page_dispose;
+
+ /* properties */
+
+ /**
+ * GPluginGtkPluginPage:plugin:
+ *
+ * The [iface@GPlugin.Plugin] whose info should be displayed.
+ *
+ * Since: 0.39.0
+ */
+ properties[PROP_PLUGIN] = g_param_spec_object(
+ "plugin",
+ "plugin",
+ "The GPluginPlugin whose info should be displayed",
+ G_TYPE_OBJECT,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
+
+ /* signals */
+
+ /**
+ * GPluginGtkPluginPage::plugin-state-set:
+ * @page: The [class@GPluginGtk.PluginPage] instance.
+ * @enabled: Whether the plugin was requested to be enabled or disabled.
+ *
+ * Emitted when the plugin page enable switch is toggled.
+ *
+ * Since: 0.39.0
+ */
+ signals[SIG_PLUGIN_STATE_SET] = g_signal_new_class_handler(
+ "plugin-state-set",
+ G_OBJECT_CLASS_TYPE(klass),
+ G_SIGNAL_RUN_LAST,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_BOOLEAN);
+
+ /* template stuff */
+ gtk_widget_class_set_template_from_resource(
+ widget_class,
+ "/org/imfreedom/keep/gplugin/gplugin-gtk/plugin-page.ui");
+
+ gtk_widget_class_bind_template_callback(
+ widget_class,
+ gplugin_gtk_lookup_plugin_name);
+ gtk_widget_class_bind_template_callback(
+ widget_class,
+ gplugin_gtk_lookup_plugin_state);
+ gtk_widget_class_bind_template_callback(
+ widget_class,
+ gplugin_gtk_lookup_plugin_state_sensitivity);
+ gtk_widget_class_bind_template_callback(
+ widget_class,
+ gplugin_gtk_plugin_page_enable_state_set_cb);
+ gtk_widget_class_bind_template_callback(
+ widget_class,
+ gplugin_gtk_plugin_page_newline_strjoinv_cb);
+ gtk_widget_class_bind_template_callback(
+ widget_class,
+ gplugin_gtk_plugin_page_lookup_website_cb);
+ gtk_widget_class_bind_template_callback(
+ widget_class,
+ gplugin_gtk_plugin_page_lookup_error_cb);
+ gtk_widget_class_bind_template_callback(
+ widget_class,
+ gplugin_gtk_plugin_page_lookup_abi_version_cb);
+ gtk_widget_class_bind_template_callback(
+ widget_class,
+ gplugin_gtk_plugin_page_lookup_loader_cb);
+}
+
+/******************************************************************************
+ * Public API
+ *****************************************************************************/
+
+/**
+ * gplugin_gtk_plugin_page_new:
+ *
+ * Create a new [class@GPluginGtk4.PluginPage] which can be used to display
+ * info about a [iface@GPlugin.Plugin].
+ *
+ * Returns: (transfer full): The new widget.
+ *
+ * Since: 0.39.0
+ */
+GtkWidget *
+gplugin_gtk_plugin_page_new(void)
+{
+ return g_object_new(GPLUGIN_GTK_TYPE_PLUGIN_PAGE, NULL);
+}
+
+/**
+ * gplugin_gtk_plugin_page_set_plugin:
+ * @page: The plugin page instance.
+ * @plugin: (nullable): The plugin instance.
+ *
+ * Sets the [iface@GPlugin.Plugin] that should be displayed.
+ *
+ * A @plugin value of %NULL will clear the widget.
+ *
+ * Since: 0.39.0
+ */
+void
+gplugin_gtk_plugin_page_set_plugin(
+ GPluginGtkPluginPage *page,
+ GPluginPlugin *plugin)
+{
+ g_return_if_fail(GPLUGIN_GTK_IS_PLUGIN_PAGE(page));
+
+ if(g_set_object(&page->plugin, plugin)) {
+ g_object_notify_by_pspec(G_OBJECT(page), properties[PROP_PLUGIN]);
+ }
+}
+
+/**
+ * gplugin_gtk_plugin_page_get_plugin:
+ * @page: The plugin page instance.
+ *
+ * Gets the [iface@GPlugin.Plugin] that's being displayed.
+ *
+ * Returns: (transfer none) (nullable): The plugin that's being displayed, or
+ * %NULL if the page is empty.
+ *
+ * Since: 0.39.0
+ */
+GPluginPlugin *
+gplugin_gtk_plugin_page_get_plugin(GPluginGtkPluginPage *page)
+{
+ g_return_val_if_fail(GPLUGIN_GTK_IS_PLUGIN_PAGE(page), NULL);
+
+ return page->plugin;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gplugin-gtk4/gplugin-gtk-plugin-page.h Mon Sep 26 00:42:07 2022 -0500
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 Elliott Sales de Andrade <quantum.analyst@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#if !defined(GPLUGIN_GTK_GLOBAL_HEADER_INSIDE) && \
+ !defined(GPLUGIN_GTK_COMPILATION)
+#error "only <gplugin-gtk.h> may be included directly"
+#endif
+
+#ifndef GPLUGIN_GTK_PLUGIN_PAGE_H
+#define GPLUGIN_GTK_PLUGIN_PAGE_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <gtk/gtk.h>
+
+#include <gplugin.h>
+
+G_BEGIN_DECLS
+
+#define GPLUGIN_GTK_TYPE_PLUGIN_PAGE (gplugin_gtk_plugin_page_get_type())
+G_DECLARE_FINAL_TYPE(
+ GPluginGtkPluginPage,
+ gplugin_gtk_plugin_page,
+ GPLUGIN_GTK,
+ PLUGIN_PAGE,
+ GtkBox)
+
+GtkWidget *gplugin_gtk_plugin_page_new(void);
+
+void gplugin_gtk_plugin_page_set_plugin(
+ GPluginGtkPluginPage *page,
+ GPluginPlugin *plugin);
+GPluginPlugin *gplugin_gtk_plugin_page_get_plugin(GPluginGtkPluginPage *page);
+
+G_END_DECLS
+
+#endif /* GPLUGIN_GTK_PLUGIN_PAGE_H */
--- a/gplugin-gtk4/gplugin-gtk-plugin-row.c Mon Sep 26 00:03:15 2022 -0500
+++ b/gplugin-gtk4/gplugin-gtk-plugin-row.c Mon Sep 26 00:42:07 2022 -0500
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 Elliott Sales de Andrade <quantum.analyst@gmail.com>
+ * Copyright (C) 2021-2022 Elliott Sales de Andrade <quantum.analyst@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -40,21 +40,6 @@
/* Header */
GtkWidget *title;
GtkWidget *summary;
- GtkWidget *config;
- GtkWidget *revealer;
-
- /* Details */
- GtkWidget *description;
- GtkWidget *authors_box;
- GtkWidget *website;
- GtkWidget *dependencies_box;
- GtkWidget *error;
- GtkWidget *id;
- GtkWidget *filename;
- GtkWidget *abi_version;
- GtkWidget *loader;
- GtkWidget *internal;
- GtkWidget *load_on_query;
};
/******************************************************************************
@@ -63,7 +48,6 @@
enum {
PROP_ZERO,
PROP_PLUGIN,
- PROP_EXPANDED,
N_PROPERTIES,
};
static GParamSpec *properties[N_PROPERTIES] = {
@@ -79,136 +63,6 @@
};
/******************************************************************************
- * Helpers
- *****************************************************************************/
-static void
-_gplugin_gtk_plugin_row_refresh(GPluginGtkPluginRow *row)
-{
- GtkWidget *widget = NULL;
- GError *error = NULL;
- gchar *website = NULL;
- gchar *description = NULL, *id = NULL, *abi_version = NULL;
- gchar *loader = NULL;
- gchar **authors = NULL;
- gchar **dependencies = NULL;
- guint32 abi_version_uint;
- gboolean loq = FALSE, internal = FALSE;
- const gchar *filename = NULL;
-
- /* Remove all the children from the authors box. */
- while((widget = gtk_widget_get_first_child(row->authors_box)) != NULL) {
- gtk_box_remove(GTK_BOX(row->authors_box), widget);
- }
-
- /* Remove all the children from the dependencies box. */
- while((widget = gtk_widget_get_first_child(row->dependencies_box)) !=
- NULL) {
- gtk_box_remove(GTK_BOX(row->dependencies_box), widget);
- }
-
- /* Now get the info if we can. */
- if(GPLUGIN_IS_PLUGIN(row->plugin)) {
- GPluginPluginInfo *plugin_info = gplugin_plugin_get_info(row->plugin);
- GPluginLoader *plugin_loader = gplugin_plugin_get_loader(row->plugin);
-
- filename = gplugin_plugin_get_filename(row->plugin);
- error = gplugin_plugin_get_error(row->plugin);
-
- if(GPLUGIN_IS_LOADER(plugin_loader)) {
- loader = g_strdup(G_OBJECT_TYPE_NAME(plugin_loader));
- }
-
- /* clang-format off */
- g_object_get(
- G_OBJECT(plugin_info),
- "abi_version", &abi_version_uint,
- "authors", &authors,
- "description", &description,
- "dependencies", &dependencies,
- "id", &id,
- "internal", &internal,
- "load-on-query", &loq,
- "website", &website,
- NULL);
- /* clang-format on */
-
- /* Finagle the website. */
- if(website) {
- gchar *markup = g_markup_printf_escaped(
- "<a href=\"%s\">%s</a>",
- website,
- website);
- g_free(website);
- website = markup;
- }
-
- /* Finagle the abi_version. */
- abi_version = g_strdup_printf("%08x", abi_version_uint);
-
- g_clear_object(&plugin_loader);
- g_clear_object(&plugin_info);
- }
-
- gtk_label_set_markup(GTK_LABEL(row->website), website);
- gtk_label_set_text(GTK_LABEL(row->description), description);
- gtk_widget_set_visible(row->description, description != NULL);
- gtk_label_set_text(GTK_LABEL(row->id), id);
- gtk_label_set_text(
- GTK_LABEL(row->error),
- (error != NULL) ? error->message : "(none)");
- gtk_label_set_text(GTK_LABEL(row->filename), filename);
- gtk_label_set_text(GTK_LABEL(row->abi_version), abi_version);
- gtk_label_set_text(
- GTK_LABEL(row->loader),
- (loader != NULL) ? loader : _("Unknown"));
- gtk_label_set_text(GTK_LABEL(row->internal), internal ? _("Yes") : _("No"));
- gtk_label_set_text(GTK_LABEL(row->load_on_query), loq ? _("Yes") : _("No"));
- /* FIXME: Set this correctly when plugins get proper configuration. */
- gtk_widget_set_sensitive(row->config, FALSE);
-
- /* Set the authors. */
- if(authors) {
- gint i = 0;
-
- for(i = 0; authors[i]; i++) {
- widget = gtk_label_new(authors[i]);
- gtk_widget_set_halign(widget, GTK_ALIGN_START);
- gtk_widget_set_valign(widget, GTK_ALIGN_START);
- gtk_box_append(GTK_BOX(row->authors_box), widget);
- }
- } else {
- widget = gtk_label_new(_("(none)"));
- gtk_box_append(GTK_BOX(row->authors_box), widget);
- }
-
- /* Set the dependencies. */
- if(dependencies) {
- gint i = 0;
-
- for(i = 0; dependencies[i]; i++) {
- widget = gtk_label_new(dependencies[i]);
- gtk_widget_set_halign(widget, GTK_ALIGN_START);
- gtk_widget_set_valign(widget, GTK_ALIGN_START);
- gtk_box_append(GTK_BOX(row->dependencies_box), widget);
- }
- } else {
- widget = gtk_label_new(_("(none)"));
- gtk_box_append(GTK_BOX(row->dependencies_box), widget);
- }
-
- g_clear_error(&error);
- g_free(loader);
- g_free(abi_version);
- g_strfreev(authors);
- g_free(description);
- g_strfreev(dependencies);
- g_free(id);
- g_free(website);
-
- gtk_list_box_row_changed(GTK_LIST_BOX_ROW(row));
-}
-
-/******************************************************************************
* Callbacks
*****************************************************************************/
static gboolean
@@ -245,11 +99,6 @@
case PROP_PLUGIN:
gplugin_gtk_plugin_row_set_plugin(row, g_value_get_object(value));
break;
- case PROP_EXPANDED:
- gplugin_gtk_plugin_row_set_expanded(
- row,
- g_value_get_boolean(value));
- break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec);
break;
@@ -269,11 +118,6 @@
case PROP_PLUGIN:
g_value_set_object(value, gplugin_gtk_plugin_row_get_plugin(row));
break;
- case PROP_EXPANDED:
- g_value_set_boolean(
- value,
- gplugin_gtk_plugin_row_get_expanded(row));
- break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec);
break;
@@ -322,13 +166,6 @@
G_TYPE_OBJECT,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
- properties[PROP_EXPANDED] = g_param_spec_boolean(
- "expanded",
- "expanded",
- "Whether the row has been opened to show details",
- FALSE,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
-
g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
/* signals */
@@ -368,14 +205,6 @@
widget_class,
GPluginGtkPluginRow,
summary);
- gtk_widget_class_bind_template_child(
- widget_class,
- GPluginGtkPluginRow,
- config);
- gtk_widget_class_bind_template_child(
- widget_class,
- GPluginGtkPluginRow,
- revealer);
gtk_widget_class_bind_template_callback(
widget_class,
gplugin_gtk_plugin_row_enable_state_set_cb);
@@ -388,49 +217,6 @@
gtk_widget_class_bind_template_callback(
widget_class,
gplugin_gtk_lookup_plugin_state_sensitivity);
-
- /* Details */
- gtk_widget_class_bind_template_child(
- widget_class,
- GPluginGtkPluginRow,
- description);
- gtk_widget_class_bind_template_child(
- widget_class,
- GPluginGtkPluginRow,
- authors_box);
- gtk_widget_class_bind_template_child(
- widget_class,
- GPluginGtkPluginRow,
- website);
- gtk_widget_class_bind_template_child(
- widget_class,
- GPluginGtkPluginRow,
- dependencies_box);
- gtk_widget_class_bind_template_child(
- widget_class,
- GPluginGtkPluginRow,
- error);
- gtk_widget_class_bind_template_child(widget_class, GPluginGtkPluginRow, id);
- gtk_widget_class_bind_template_child(
- widget_class,
- GPluginGtkPluginRow,
- filename);
- gtk_widget_class_bind_template_child(
- widget_class,
- GPluginGtkPluginRow,
- abi_version);
- gtk_widget_class_bind_template_child(
- widget_class,
- GPluginGtkPluginRow,
- loader);
- gtk_widget_class_bind_template_child(
- widget_class,
- GPluginGtkPluginRow,
- internal);
- gtk_widget_class_bind_template_child(
- widget_class,
- GPluginGtkPluginRow,
- load_on_query);
}
/******************************************************************************
@@ -472,8 +258,6 @@
g_return_if_fail(GPLUGIN_GTK_IS_PLUGIN_ROW(row));
if(g_set_object(&row->plugin, plugin)) {
- _gplugin_gtk_plugin_row_refresh(row);
-
g_object_notify_by_pspec(G_OBJECT(row), properties[PROP_PLUGIN]);
}
}
@@ -498,42 +282,6 @@
}
/**
- * gplugin_gtk_plugin_row_get_expanded:
- * @row: The plugin row instance.
- *
- * Returns whether the plugin row is showing detailed information.
- *
- * Returns: %TRUE if the plugin row is expanded, %FALSE otherwise.
- *
- * Since: 0.38.0
- */
-gboolean
-gplugin_gtk_plugin_row_get_expanded(GPluginGtkPluginRow *row)
-{
- g_return_val_if_fail(GPLUGIN_GTK_IS_PLUGIN_ROW(row), FALSE);
-
- return gtk_revealer_get_reveal_child(GTK_REVEALER(row->revealer));
-}
-
-/**
- * gplugin_gtk_plugin_row_set_expanded:
- * @row: The plugin row instance.
- * @expanded: Whether the plugin row is expanded.
- *
- * Sets whether the plugin row is showing detailed information.
- *
- * Since: 0.38.0
- */
-void
-gplugin_gtk_plugin_row_set_expanded(GPluginGtkPluginRow *row, gboolean expanded)
-{
- g_return_if_fail(GPLUGIN_GTK_IS_PLUGIN_ROW(row));
-
- gtk_revealer_set_reveal_child(GTK_REVEALER(row->revealer), expanded);
- g_object_notify_by_pspec(G_OBJECT(row), properties[PROP_EXPANDED]);
-}
-
-/**
* gplugin_gtk_plugin_row_get_sort_key:
* @row: The plugin row instance.
*
@@ -581,14 +329,23 @@
return TRUE;
}
- value = gtk_label_get_text(GTK_LABEL(row->description));
- if(g_strstr_len(value, -1, text)) {
- return TRUE;
- }
+ if(GPLUGIN_IS_PLUGIN(row->plugin)) {
+ GPluginPluginInfo *plugin_info = NULL;
+ gchar *filename = NULL;
- value = gtk_label_get_text(GTK_LABEL(row->filename));
- if(g_strstr_len(value, -1, text)) {
- return TRUE;
+ plugin_info = gplugin_plugin_get_info(row->plugin);
+ value = gplugin_plugin_info_get_description(plugin_info);
+ g_clear_object(&plugin_info);
+ if(value != NULL && g_strstr_len(value, -1, text)) {
+ return TRUE;
+ }
+
+ filename = gplugin_plugin_get_filename(row->plugin);
+ if(filename != NULL && g_strstr_len(filename, -1, text)) {
+ g_free(filename);
+ return TRUE;
+ }
+ g_free(filename);
}
return FALSE;
--- a/gplugin-gtk4/gplugin-gtk-plugin-row.h Mon Sep 26 00:03:15 2022 -0500
+++ b/gplugin-gtk4/gplugin-gtk-plugin-row.h Mon Sep 26 00:42:07 2022 -0500
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 Elliott Sales de Andrade <quantum.analyst@gmail.com>
+ * Copyright (C) 2021-2022 Elliott Sales de Andrade <quantum.analyst@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -46,10 +46,6 @@
GPluginGtkPluginRow *row,
GPluginPlugin *plugin);
GPluginPlugin *gplugin_gtk_plugin_row_get_plugin(GPluginGtkPluginRow *row);
-gboolean gplugin_gtk_plugin_row_get_expanded(GPluginGtkPluginRow *row);
-void gplugin_gtk_plugin_row_set_expanded(
- GPluginGtkPluginRow *row,
- gboolean expanded);
gchar *gplugin_gtk_plugin_row_get_sort_key(GPluginGtkPluginRow *row);
gboolean gplugin_gtk_plugin_row_matches_search(
GPluginGtkPluginRow *row,
--- a/gplugin-gtk4/gplugin-gtk-view.c Mon Sep 26 00:03:15 2022 -0500
+++ b/gplugin-gtk4/gplugin-gtk-view.c Mon Sep 26 00:42:07 2022 -0500
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 Elliott Sales de Andrade <quantum.analyst@gmail.com>
+ * Copyright (C) 2021-2022 Elliott Sales de Andrade <quantum.analyst@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -17,14 +17,15 @@
#include <gplugin.h>
+#include <gplugin-gtk-plugin-page.h>
#include <gplugin-gtk-plugin-row.h>
#include <gplugin-gtk-view.h>
/**
* GPluginGtkView:
*
- * A [class@Gtk.ListBox] widget that displays all the plugins and some basic
- * information about them.
+ * A widget that displays all the plugins and some basic information about
+ * them.
*/
/******************************************************************************
@@ -33,12 +34,17 @@
struct _GPluginGtkView {
GtkBox parent;
+ GPluginManager *manager;
+ gboolean show_internal;
+ GtkWidget *stack;
+
+ /* Overview */
GtkWidget *list_box;
GtkWidget *search_bar;
GtkWidget *search_entry;
- GPluginManager *manager;
- gboolean show_internal;
+ /* Plugin details */
+ GtkWidget *plugin_page;
};
/******************************************************************************
@@ -61,25 +67,27 @@
gplugin_gtk_view_row_activated(
G_GNUC_UNUSED GtkListBox *box,
GtkListBoxRow *row,
- G_GNUC_UNUSED gpointer data)
+ gpointer data)
{
+ GPluginGtkView *view = GPLUGIN_GTK_VIEW(data);
GPluginGtkPluginRow *plugin_row = GPLUGIN_GTK_PLUGIN_ROW(row);
+ GPluginPlugin *plugin = NULL;
- gplugin_gtk_plugin_row_set_expanded(
- plugin_row,
- !gplugin_gtk_plugin_row_get_expanded(plugin_row));
+ plugin = gplugin_gtk_plugin_row_get_plugin(plugin_row);
+ gplugin_gtk_view_show_plugin(view, plugin);
}
static void
gplugin_gtk_view_plugin_state_set_cb(
- GPluginGtkPluginRow *row,
+ GObject *row_or_page,
gboolean state,
gpointer data)
{
GPluginGtkView *view = GPLUGIN_GTK_VIEW(data);
- GPluginPlugin *plugin = gplugin_gtk_plugin_row_get_plugin(row);
+ GPluginPlugin *plugin = NULL;
GError *error = NULL;
+ g_object_get(row_or_page, "plugin", &plugin, NULL);
if(state) {
gplugin_manager_load_plugin(view->manager, plugin, &error);
@@ -97,6 +105,8 @@
g_error_free(error);
}
}
+
+ g_clear_object(&plugin);
}
static void
@@ -173,6 +183,14 @@
gtk_list_box_invalidate_filter(GTK_LIST_BOX(view->list_box));
}
+static void
+gplugin_gtk_view_back_clicked_cb(G_GNUC_UNUSED GtkButton *button, gpointer data)
+{
+ GPluginGtkView *view = GPLUGIN_GTK_VIEW(data);
+
+ gplugin_gtk_view_show_overview(view);
+}
+
/******************************************************************************
* GObject Implementation
*****************************************************************************/
@@ -250,6 +268,8 @@
widget_class,
"/org/imfreedom/keep/gplugin/gplugin-gtk/view.ui");
+ gtk_widget_class_bind_template_child(widget_class, GPluginGtkView, stack);
+
gtk_widget_class_bind_template_child(
widget_class,
GPluginGtkView,
@@ -263,12 +283,23 @@
GPluginGtkView,
search_entry);
+ gtk_widget_class_bind_template_child(
+ widget_class,
+ GPluginGtkView,
+ plugin_page);
+
gtk_widget_class_bind_template_callback(
widget_class,
gplugin_gtk_view_row_activated);
gtk_widget_class_bind_template_callback(
widget_class,
gplugin_gtk_view_search_changed);
+ gtk_widget_class_bind_template_callback(
+ widget_class,
+ gplugin_gtk_view_back_clicked_cb);
+ gtk_widget_class_bind_template_callback(
+ widget_class,
+ gplugin_gtk_view_plugin_state_set_cb);
/* properties */
@@ -418,3 +449,43 @@
return view->show_internal;
}
+
+/**
+ * gplugin_gtk_view_show_overview:
+ * @view: The GTK view instance.
+ *
+ * Shows the plugin list overview.
+ *
+ * Since: 0.39.0
+ */
+void
+gplugin_gtk_view_show_overview(GPluginGtkView *view)
+{
+ g_return_if_fail(GPLUGIN_GTK_IS_VIEW(view));
+
+ gplugin_gtk_plugin_page_set_plugin(
+ GPLUGIN_GTK_PLUGIN_PAGE(view->plugin_page),
+ NULL);
+ gtk_stack_set_visible_child_name(GTK_STACK(view->stack), "overview");
+}
+
+/**
+ * gplugin_gtk_view_show_plugin:
+ * @view: The GTK view instance.
+ * @plugin: (transfer none): The plugin to show.
+ *
+ * Shows a page for a single plugin.
+ *
+ * Since: 0.39.0
+ */
+void
+gplugin_gtk_view_show_plugin(GPluginGtkView *view, GPluginPlugin *plugin)
+{
+ g_return_if_fail(GPLUGIN_GTK_IS_VIEW(view));
+ g_return_if_fail(GPLUGIN_IS_PLUGIN(plugin));
+
+ gplugin_gtk_plugin_page_set_plugin(
+ GPLUGIN_GTK_PLUGIN_PAGE(view->plugin_page),
+ plugin);
+ gtk_stack_set_visible_child_name(GTK_STACK(view->stack), "plugin-page");
+}
--- a/gplugin-gtk4/gplugin-gtk-view.h Mon Sep 26 00:03:15 2022 -0500
+++ b/gplugin-gtk4/gplugin-gtk-view.h Mon Sep 26 00:42:07 2022 -0500
@@ -52,6 +52,9 @@
gboolean show_internal);
gboolean gplugin_gtk_view_get_show_internal(GPluginGtkView *view);
+void gplugin_gtk_view_show_overview(GPluginGtkView *view);
+void gplugin_gtk_view_show_plugin(GPluginGtkView *view, GPluginPlugin *plugin);
+
G_END_DECLS
#endif /* GPLUGIN_GTK_VIEW_H */
--- a/gplugin-gtk4/meson.build Mon Sep 26 00:03:15 2022 -0500
+++ b/gplugin-gtk4/meson.build Mon Sep 26 00:42:07 2022 -0500
@@ -9,11 +9,13 @@
GPLUGIN_GTK4_LIBRARY_VERSION = '0.1.0'
GPLUGIN_GTK4_SOURCES = [
+ 'gplugin-gtk-plugin-page.c',
'gplugin-gtk-plugin-row.c',
'gplugin-gtk-view.c',
]
GPLUGIN_GTK4_HEADERS = [
+ 'gplugin-gtk-plugin-page.h',
'gplugin-gtk-plugin-row.h',
'gplugin-gtk-view.h',
]
--- a/po/POTFILES Mon Sep 26 00:03:15 2022 -0500
+++ b/po/POTFILES Mon Sep 26 00:42:07 2022 -0500
@@ -1,5 +1,7 @@
+gplugin-gtk4/data/plugin-page.ui
gplugin-gtk4/data/plugin-row.ui
gplugin-gtk4/data/view.ui
+gplugin-gtk4/gplugin-gtk-plugin-page.c
gplugin-gtk4/gplugin-gtk-plugin-row.c
gplugin-gtk4/gplugin-gtk-view.c
gplugin-gtk4-viewer/data/window.ui