diff --git a/TODO.md b/TODO.md
index 21917f9..a70b13b 100644
--- a/TODO.md
+++ b/TODO.md
@@ -1,16 +1,15 @@
TODO:
- - [X] Fix c.fill issue
- - [] Create Element structure with pads and connections
- - [] Get a list of GStreamer elements in dialog add plugin
- - [] Draw element with its pad
- - [] Be able to move the element on Screen
- - [] Create connection between element
- - [] Run a pipeline with GStreamer
- - [] Run the pipeline with GStreamer
- - [] Control the pipeline with GStreamer
- - [X] Define the license
- - [] Connect the logs to the window
- - [] Create a window for the video output
-
-
+- [x] Fix c.fill issue
+- [x] Create Element structure with pads and connections
+- [x] Get a list of GStreamer elements in dialog add plugin
+- [x] Add plugin details in the element dialog
+- [] Draw element with its pad
+- [] Be able to move the element on Screen
+- [] Create connection between element
+- [] Run a pipeline with GStreamer
+- [] Run the pipeline with GStreamer
+- [] Control the pipeline with GStreamer
+- [x] Define the license
+- [] Connect the logs to the window
+- [] Create a window for the video output
diff --git a/src/app.rs b/src/app.rs
index 662a6af..dc077f3 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -29,7 +29,7 @@ use std::{error, ops};
use crate::graph::{Element, Graph};
use crate::pipeline::Pipeline;
-use crate::pluginlistwindow;
+use crate::pluginlist;
#[derive(Debug)]
pub struct GPSAppInner {
@@ -186,7 +186,7 @@ impl GPSApp {
add_button.connect_clicked(glib::clone!(@weak window => move |_| {
let app = upgrade_weak!(app_weak);
let elements = Pipeline::elements_list().expect("Unable to obtain element's list");
- pluginlistwindow::build_plugin_list(&app, &elements);
+ pluginlist::display_plugin_list(&app, &elements);
}));
// Create a dialog to open a file
let open_button: Button = self
diff --git a/src/gps.ui b/src/gps.ui
index 8c8647f..571a838 100644
--- a/src/gps.ui
+++ b/src/gps.ui
@@ -67,6 +67,90 @@
+
False6
@@ -374,7 +458,7 @@
-
+ TrueTrueTrue
@@ -423,7 +507,6 @@
TrueFalseTrue
- TrueTrue
diff --git a/src/main.rs b/src/main.rs
index ec989e6..c6301bd 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -22,7 +22,7 @@ mod macros;
mod app;
mod graph;
mod pipeline;
-mod pluginlistwindow;
+mod pluginlist;
use gtk::prelude::*;
diff --git a/src/pipeline.rs b/src/pipeline.rs
index c23bfcd..9e42d82 100644
--- a/src/pipeline.rs
+++ b/src/pipeline.rs
@@ -73,6 +73,74 @@ impl Pipeline {
}
}
}
+ elements.sort();
Ok(elements)
}
+ pub fn element_description(
+ element_name: &str,
+ ) -> anyhow::Result> {
+ let mut desc = String::from("");
+ let registry = gst::Registry::get();
+ let feature = gst::Registry::find_feature(
+ ®istry,
+ element_name,
+ gst::ElementFactory::static_type(),
+ )
+ .expect("Unable to find the element name");
+
+ if let Ok(factory) = feature.downcast::() {
+ desc.push_str("Factory details:\n");
+ desc.push_str("Name:");
+ desc.push_str(&factory.get_name());
+ desc.push('\n');
+
+ let element_keys = factory.get_metadata_keys();
+ for key in element_keys {
+ let val = factory.get_metadata(&key);
+ if let Some(val) = val {
+ desc.push_str("");
+ desc.push_str(&key);
+ desc.push_str(":");
+ desc.push_str(>k::glib::markup_escape_text(&val).to_string());
+ desc.push('\n');
+ }
+ }
+ let feature = factory.upcast::();
+ let plugin = gst::PluginFeature::get_plugin(&feature);
+ if let Some(plugin) = plugin {
+ desc.push('\n');
+ desc.push_str("Plugin details:");
+ desc.push('\n');
+ desc.push_str("Name:");
+ desc.push_str("");
+ desc.push_str(gst::Plugin::get_plugin_name(&plugin).as_str());
+ desc.push('\n');
+ desc.push_str("Description:");
+ desc.push_str("");
+ desc.push_str(
+ >k::glib::markup_escape_text(&plugin.get_description()).to_string(),
+ );
+ desc.push('\n');
+ desc.push_str("Filename:");
+ desc.push_str("");
+ desc.push_str(
+ >k::glib::markup_escape_text(
+ &plugin
+ .get_filename()
+ .unwrap()
+ .as_path()
+ .display()
+ .to_string(),
+ )
+ .to_string(),
+ );
+ desc.push('\n');
+ desc.push_str("Version:");
+ desc.push_str("");
+ desc.push_str(>k::glib::markup_escape_text(&plugin.get_version()).to_string());
+ desc.push('\n');
+ }
+ }
+ Ok(desc)
+ }
}
diff --git a/src/pluginlist.rs b/src/pluginlist.rs
new file mode 100644
index 0000000..2e86dd4
--- /dev/null
+++ b/src/pluginlist.rs
@@ -0,0 +1,136 @@
+// pluginlist.rs
+//
+// Copyright 2021 Stéphane Cerveau
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+//
+// SPDX-License-Identifier: GPL-3.0-only
+use crate::app::GPSApp;
+use crate::graph::Element;
+use crate::pipeline::ElementInfo;
+use crate::pipeline::Pipeline;
+use gtk::TextBuffer;
+use gtk::{
+ glib::{self, clone},
+ prelude::*,
+};
+
+use gtk::{
+ CellRendererText, Dialog, ListStore, TextView, TreeView, TreeViewColumn, WindowPosition,
+};
+
+fn create_and_fill_model(elements: &[ElementInfo]) -> ListStore {
+ // Creation of a model with two rows.
+ let model = ListStore::new(&[u32::static_type(), String::static_type()]);
+
+ // Filling up the tree view.
+ for (i, entry) in elements.iter().enumerate() {
+ model.insert_with_values(
+ None,
+ &[(0, &(i as u32 + 1)), (1, &entry.name.as_ref().unwrap())],
+ );
+ }
+ model
+}
+
+fn append_column(tree: &TreeView, id: i32) {
+ let column = TreeViewColumn::new();
+ let cell = CellRendererText::new();
+
+ column.pack_start(&cell, true);
+ // Association of the view's column with the model's `id` column.
+ column.add_attribute(&cell, "text", id);
+ tree.append_column(&column);
+}
+
+pub fn display_plugin_list(app: &GPSApp, elements: &[ElementInfo]) {
+ let dialog: Dialog = app
+ .builder
+ .object("dialog-plugin-list")
+ .expect("Couldn't get window");
+
+ dialog.set_title("Plugin list");
+ dialog.set_position(WindowPosition::Center);
+ dialog.set_default_size(640, 480);
+
+ let tree: TreeView = app
+ .builder
+ .object("treeview-plugin-list")
+ .expect("Couldn't get window");
+
+ let text_view: TextView = app
+ .builder
+ .object("textview-plugin-list")
+ .expect("Couldn't get window");
+ let text_buffer: TextBuffer = text_view
+ .buffer()
+ .expect("Couldn't get buffer from text_view");
+ if tree.n_columns() < 2 {
+ append_column(&tree, 0);
+ append_column(&tree, 1);
+ }
+ let model = create_and_fill_model(elements);
+ // Setting the model into the view.
+ tree.set_model(Some(&model));
+
+ // The closure responds to selection changes by connection to "::cursor-changed" signal,
+ // that gets emitted when the cursor moves (focus changes).
+ tree.connect_cursor_changed(clone!(@weak dialog, @weak text_buffer => move |tree_view| {
+ let selection = tree_view.selection();
+ if let Some((model, iter)) = selection.selected() {
+ let element_name = model
+ .value(&iter, 1)
+ .get::()
+ .expect("Treeview selection, column 1");
+ let description = Pipeline::element_description(&element_name).expect("Unable to get element list from GStreamer");
+ text_buffer.set_text("");
+ text_buffer.insert_markup(&mut text_buffer.end_iter(), &description);
+ }
+
+ }));
+ let app_weak = app.downgrade();
+ tree.connect_row_activated(
+ clone!(@weak dialog => move |tree_view, _tree_path, _tree_column| {
+ let app = upgrade_weak!(app_weak);
+ let selection = tree_view.selection();
+ if let Some((model, iter)) = selection.selected() {
+ // Now getting back the values from the row corresponding to the
+ // iterator `iter`.
+ //
+ let element = Element {
+ name: model
+ .value(&iter, 1)
+ .get::()
+ .expect("Treeview selection, column 1"),
+ position: (100.0,100.0),
+ size: (100.0,100.0),
+ };
+
+ let element_name = model
+ .value(&iter, 1)
+ .get::()
+ .expect("Treeview selection, column 1");
+ app.add_new_element(element);
+
+ println!("{}", element_name);
+ }
+ }),
+ );
+
+ dialog.connect_delete_event(|dialog, _| {
+ dialog.hide();
+ gtk::Inhibit(true)
+ });
+ dialog.show_all();
+}
diff --git a/src/pluginlistwindow.rs b/src/pluginlistwindow.rs
deleted file mode 100644
index 1178b7a..0000000
--- a/src/pluginlistwindow.rs
+++ /dev/null
@@ -1,127 +0,0 @@
-use crate::app::GPSApp;
-use crate::graph::Element;
-use crate::pipeline::ElementInfo;
-use gtk::{
- glib::{self, clone},
- prelude::*,
- ResponseType,
-};
-
-use gtk::{
- CellRendererText, Label, ListStore, Orientation, TreeView, TreeViewColumn, WindowPosition,
-};
-
-fn create_and_fill_model(elements: &Vec) -> ListStore {
- // Creation of a model with two rows.
- let model = ListStore::new(&[u32::static_type(), String::static_type()]);
-
- // Filling up the tree view.
- for (i, entry) in elements.iter().enumerate() {
- model.insert_with_values(
- None,
- &[(0, &(i as u32 + 1)), (1, &entry.name.as_ref().unwrap())],
- );
- }
- model
-}
-
-fn append_column(tree: &TreeView, id: i32) {
- let column = TreeViewColumn::new();
- let cell = CellRendererText::new();
-
- column.pack_start(&cell, true);
- // Association of the view's column with the model's `id` column.
- column.add_attribute(&cell, "text", id);
- tree.append_column(&column);
-}
-
-fn create_and_setup_view() -> TreeView {
- // Creating the tree view.
- let tree = TreeView::new();
-
- tree.set_headers_visible(false);
- // Creating the two columns inside the view.
- append_column(&tree, 0);
- append_column(&tree, 1);
- tree
-}
-
-pub fn build_plugin_list(app: &GPSApp, elements: &Vec) {
- let dialog = gtk::Dialog::with_buttons(
- Some("Edit Item"),
- Some(&app.window),
- gtk::DialogFlags::MODAL,
- &[("Close", ResponseType::Close)],
- );
- dialog.set_title("Plugin list");
- dialog.set_position(WindowPosition::Center);
- dialog.set_default_size(640, 480);
-
- // Creating a vertical layout to place both tree view and label in the window.
- let vertical_layout = gtk::Box::new(Orientation::Vertical, 0);
-
- // Creation of the label.
- let label = Label::new(Some(""));
-
- let tree = create_and_setup_view();
-
- let model = create_and_fill_model(elements);
- // Setting the model into the view.
- tree.set_model(Some(&model));
-
- // Adding the view to the layout.
- vertical_layout.add(&tree);
- // Same goes for the label.
- vertical_layout.add(&label);
-
- // The closure responds to selection changes by connection to "::cursor-changed" signal,
- // that gets emitted when the cursor moves (focus changes).
- let app_weak = app.downgrade();
- tree.connect_cursor_changed(clone!(@weak dialog => move |tree_view| {
- let app = upgrade_weak!(app_weak);
- let selection = tree_view.selection();
- if let Some((model, iter)) = selection.selected() {
- // Now getting back the values from the row corresponding to the
- // iterator `iter`.
- //
- // The `get_value` method do the conversion between the gtk type and Rust.
- label.set_text(&format!(
- "Hello '{}' from row {}",
- model
- .value(&iter, 1)
- .get::()
- .expect("Treeview selection, column 1"),
- model
- .value(&iter, 0)
- .get::()
- .expect("Treeview selection, column 0"),
- ));
- let element = Element {
- name: model
- .value(&iter, 1)
- .get::()
- .expect("Treeview selection, column 1"),
- position: (100.0,100.0),
- size: (100.0,100.0),
- };
-
- let element_name = model
- .value(&iter, 1)
- .get::()
- .expect("Treeview selection, column 1");
- app.add_new_element(element);
-
- //dialog.close();
- println!("{}", element_name);
- }
- }));
-
- // Adding the layout to the window.
- let content_area = dialog.content_area();
- let scrolled_window = gtk::ScrolledWindow::new(gtk::NONE_ADJUSTMENT, gtk::NONE_ADJUSTMENT);
- scrolled_window.add(&vertical_layout);
- content_area.add(&scrolled_window);
-
- dialog.connect_response(|dialog, _| dialog.close());
- dialog.show_all();
-}