graphbook: introduce element_factory_exists

This method helps to tell if a factory exists
when loading a graph.
If the factory does not exists, use light mode
to display it and prevent some menu item
and change its description.
This commit is contained in:
Stéphane Cerveau 2023-09-18 12:30:39 +02:00
parent 111750a33b
commit f4be2299b9
5 changed files with 155 additions and 117 deletions

View file

@ -100,3 +100,7 @@
### app
- [x] Add multiple graphviews with tabs.
- [x] handle the caps setter element
## 0.3.2
### app
- [x] check that element exists before creating it on file load.

View file

@ -15,7 +15,6 @@
- [ ] unable to connect element with incompatible caps.
- [ ] Implement graph dot render/load
- [ ] Add probes on each pad to monitor the pipeline
- [ ] Render a media file
- [ ] Offer compatible element to a pad (autorender)
@ -32,7 +31,6 @@
## bugs
- [ ] check that element exists before creating it on file load.
- [ ] Combo box is not well selected if the value is not linear such as flags. See flags in playbin
- [ ] opening a graph file can lead a different behavior in the pipeline. See videomixer graph where the zorder
on pads is not correctly set to right one.

View file

@ -46,6 +46,19 @@ impl ElementInfo {
Ok(elements)
}
pub fn element_factory_exists(element_name: &str) -> bool {
match ElementInfo::element_feature(element_name) {
Some(_feature) => {
GPS_DEBUG!("Found element factory name {}", element_name);
true
}
None => {
GPS_ERROR!("Unable to find element factory name {}", element_name);
false
}
}
}
pub fn element_feature(element_name: &str) -> Option<gst::PluginFeature> {
let registry = gst::Registry::get();
gst::Registry::find_feature(&registry, element_name, gst::ElementFactory::static_type())
@ -60,6 +73,14 @@ impl ElementInfo {
pub fn element_description(element_name: &str) -> anyhow::Result<String> {
let mut desc = String::from("");
if !ElementInfo::element_factory_exists(element_name) {
desc.push_str("<b>Factory details:</b>\n");
desc.push_str("<b>Name:</b>");
desc.push_str(element_name);
desc.push('\n');
desc.push('\n');
desc.push_str("Factory unavailable.");
} else {
let feature = ElementInfo::element_feature(element_name)
.ok_or_else(|| glib::bool_error!("Failed get element feature"))?;
let rank = feature.rank();
@ -114,6 +135,7 @@ impl ElementInfo {
desc.push('\n');
}
}
}
Ok(desc)
}

View file

@ -51,10 +51,9 @@ impl PadInfo {
}
pub fn pads(element_name: &str, include_on_request: bool) -> (Vec<PadInfo>, Vec<PadInfo>) {
let feature = ElementInfo::element_feature(element_name).expect("Unable to get feature");
let mut input = vec![];
let mut output = vec![];
if let Some(feature) = ElementInfo::element_feature(element_name) {
if let Ok(factory) = feature.downcast::<gst::ElementFactory>() {
if factory.num_pad_templates() > 0 {
let pads = factory.static_pad_templates();
@ -87,5 +86,8 @@ impl PadInfo {
}
}
(input, output)
} else {
(input, output)
}
}
}

View file

@ -242,6 +242,10 @@ pub fn create_graphtab(app: &GPSApp, id: u32, name: Option<&str>) {
if let Some(node) = current_graphtab(&app).graphview().node(node_id) {
let description = GPS::ElementInfo::element_description(&node.name()).ok();
node.set_tooltip_markup(description.as_deref());
if !GPS::ElementInfo::element_factory_exists(&node.name()) {
node.set_light(true);
node.set_tooltip_markup(description.as_deref());
}
for port in node.all_ports(GM::PortDirection::All) {
let caps = PropertyExt::property(&port,"_caps");
GPS_DEBUG!("caps={} for port id {}", caps.clone().unwrap_or_else(|| "caps unknown".to_string()), port.id());
@ -382,6 +386,8 @@ pub fn create_graphtab(app: &GPSApp, id: u32, name: Option<&str>) {
glib::clone!(@weak graphbook => @default-return None, move |values: &[Value]| {
let app = upgrade_weak!(app_weak, None);
let node_id = values[1].get::<u32>().expect("node id args[1]");
let node = current_graphtab(&app).graphview().node(node_id).unwrap();
let element_exists = GPS::ElementInfo::element_factory_exists(&node.name());
let point = values[2].get::<graphene::Point>().expect("point in args[2]");
let pop_menu = app.app_pop_menu_at_position(&*current_graphtab(&app).graphview(), point.to_vec2().x() as f64, point.to_vec2().y() as f64);
let menu: gio::MenuModel = app
@ -390,6 +396,16 @@ pub fn create_graphtab(app: &GPSApp, id: u32, name: Option<&str>) {
.expect("Couldn't get menu model for node");
pop_menu.set_menu_model(Some(&menu));
let app_weak = app.downgrade();
app.connect_app_menu_action("node.delete",
move |_,_| {
let app = upgrade_weak!(app_weak);
GPS_DEBUG!("node.delete id: {}", node_id);
current_graphtab(&app).graphview().remove_node(node_id);
}
);
if element_exists {
let app_weak = app.downgrade();
app.connect_app_menu_action("node.add-to-favorite",
move |_,_| {
@ -401,14 +417,7 @@ pub fn create_graphtab(app: &GPSApp, id: u32, name: Option<&str>) {
}
);
let app_weak = app.downgrade();
app.connect_app_menu_action("node.delete",
move |_,_| {
let app = upgrade_weak!(app_weak);
GPS_DEBUG!("node.delete id: {}", node_id);
current_graphtab(&app).graphview().remove_node(node_id);
}
);
let node = app.node(node_id);
if let Some(input) = GPS::ElementInfo::element_supports_new_pad_request(&node.name(), GM::PortDirection::Input) {
let app_weak = app.downgrade();
@ -445,6 +454,7 @@ pub fn create_graphtab(app: &GPSApp, id: u32, name: Option<&str>) {
GPSUI::properties::display_plugin_properties(&app, &node.name(), node_id);
}
);
}
pop_menu.show();
None
}),
@ -459,7 +469,9 @@ pub fn create_graphtab(app: &GPSApp, id: u32, name: Option<&str>) {
let node_id = values[1].get::<u32>().expect("node id args[1]");
GPS_TRACE!("Node double clicked id={}", node_id);
let node = current_graphtab(&app).graphview().node(node_id).unwrap();
if GPS::ElementInfo::element_factory_exists(&node.name()) {
GPSUI::properties::display_plugin_properties(&app, &node.name(), node_id);
}
None
}),
);