mirror of
https://gitlab.freedesktop.org/dabrain34/GstPipelineStudio.git
synced 2024-11-22 09:00:59 +00:00
pluginlist: can now select and double click element
Treeview row actions: - A selection will display element information. - A double click add a new element in the app.graph structure. The plugin list dialog is an item from gps.ui
This commit is contained in:
parent
0851f0545b
commit
b36fd0aebe
7 changed files with 305 additions and 146 deletions
11
TODO.md
11
TODO.md
|
@ -1,16 +1,15 @@
|
||||||
TODO:
|
TODO:
|
||||||
|
|
||||||
- [X] Fix c.fill issue
|
- [x] Fix c.fill issue
|
||||||
- [] Create Element structure with pads and connections
|
- [x] Create Element structure with pads and connections
|
||||||
- [] Get a list of GStreamer elements in dialog add plugin
|
- [x] Get a list of GStreamer elements in dialog add plugin
|
||||||
|
- [x] Add plugin details in the element dialog
|
||||||
- [] Draw element with its pad
|
- [] Draw element with its pad
|
||||||
- [] Be able to move the element on Screen
|
- [] Be able to move the element on Screen
|
||||||
- [] Create connection between element
|
- [] Create connection between element
|
||||||
- [] Run a pipeline with GStreamer
|
- [] Run a pipeline with GStreamer
|
||||||
- [] Run the pipeline with GStreamer
|
- [] Run the pipeline with GStreamer
|
||||||
- [] Control the pipeline with GStreamer
|
- [] Control the pipeline with GStreamer
|
||||||
- [X] Define the license
|
- [x] Define the license
|
||||||
- [] Connect the logs to the window
|
- [] Connect the logs to the window
|
||||||
- [] Create a window for the video output
|
- [] Create a window for the video output
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ use std::{error, ops};
|
||||||
|
|
||||||
use crate::graph::{Element, Graph};
|
use crate::graph::{Element, Graph};
|
||||||
use crate::pipeline::Pipeline;
|
use crate::pipeline::Pipeline;
|
||||||
use crate::pluginlistwindow;
|
use crate::pluginlist;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct GPSAppInner {
|
pub struct GPSAppInner {
|
||||||
|
@ -186,7 +186,7 @@ impl GPSApp {
|
||||||
add_button.connect_clicked(glib::clone!(@weak window => move |_| {
|
add_button.connect_clicked(glib::clone!(@weak window => move |_| {
|
||||||
let app = upgrade_weak!(app_weak);
|
let app = upgrade_weak!(app_weak);
|
||||||
let elements = Pipeline::elements_list().expect("Unable to obtain element's list");
|
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
|
// Create a dialog to open a file
|
||||||
let open_button: Button = self
|
let open_button: Button = self
|
||||||
|
|
87
src/gps.ui
87
src/gps.ui
|
@ -67,6 +67,90 @@
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
<object class="GtkDialog" id="dialog-plugin-list">
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<property name="default-width">320</property>
|
||||||
|
<property name="default-height">260</property>
|
||||||
|
<property name="type-hint">dialog</property>
|
||||||
|
<child internal-child="vbox">
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="spacing">2</property>
|
||||||
|
<child internal-child="action_area">
|
||||||
|
<object class="GtkButtonBox">
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<property name="layout-style">end</property>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<property name="vexpand">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkScrolledWindow">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">True</property>
|
||||||
|
<property name="hexpand">True</property>
|
||||||
|
<property name="shadow-type">in</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkTreeView" id="treeview-plugin-list">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">True</property>
|
||||||
|
<child internal-child="selection">
|
||||||
|
<object class="GtkTreeSelection"/>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkScrolledWindow">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">True</property>
|
||||||
|
<property name="hexpand">True</property>
|
||||||
|
<property name="shadow-type">in</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkTextView" id="textview-plugin-list">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">True</property>
|
||||||
|
<property name="editable">False</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
<object class="GtkApplicationWindow" id="mainwindow">
|
<object class="GtkApplicationWindow" id="mainwindow">
|
||||||
<property name="can-focus">False</property>
|
<property name="can-focus">False</property>
|
||||||
<property name="border-width">6</property>
|
<property name="border-width">6</property>
|
||||||
|
@ -374,7 +458,7 @@
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkButton" id="button-clear">
|
<object class="GtkButton">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can-focus">True</property>
|
<property name="can-focus">True</property>
|
||||||
<property name="receives-default">True</property>
|
<property name="receives-default">True</property>
|
||||||
|
@ -423,7 +507,6 @@
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can-focus">False</property>
|
<property name="can-focus">False</property>
|
||||||
<property name="vexpand">True</property>
|
<property name="vexpand">True</property>
|
||||||
<property name="homogeneous">True</property>
|
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkScrolledWindow">
|
<object class="GtkScrolledWindow">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
|
|
@ -22,7 +22,7 @@ mod macros;
|
||||||
mod app;
|
mod app;
|
||||||
mod graph;
|
mod graph;
|
||||||
mod pipeline;
|
mod pipeline;
|
||||||
mod pluginlistwindow;
|
mod pluginlist;
|
||||||
|
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
|
|
||||||
|
|
|
@ -73,6 +73,74 @@ impl Pipeline {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
elements.sort();
|
||||||
Ok(elements)
|
Ok(elements)
|
||||||
}
|
}
|
||||||
|
pub fn element_description(
|
||||||
|
element_name: &str,
|
||||||
|
) -> anyhow::Result<String, Box<dyn error::Error>> {
|
||||||
|
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::<gst::ElementFactory>() {
|
||||||
|
desc.push_str("<b>Factory details:</b>\n");
|
||||||
|
desc.push_str("<b>Name:</b>");
|
||||||
|
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("<b>");
|
||||||
|
desc.push_str(&key);
|
||||||
|
desc.push_str("</b>:");
|
||||||
|
desc.push_str(>k::glib::markup_escape_text(&val).to_string());
|
||||||
|
desc.push('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let feature = factory.upcast::<gst::PluginFeature>();
|
||||||
|
let plugin = gst::PluginFeature::get_plugin(&feature);
|
||||||
|
if let Some(plugin) = plugin {
|
||||||
|
desc.push('\n');
|
||||||
|
desc.push_str("<b>Plugin details:</b>");
|
||||||
|
desc.push('\n');
|
||||||
|
desc.push_str("<b>Name:");
|
||||||
|
desc.push_str("</b>");
|
||||||
|
desc.push_str(gst::Plugin::get_plugin_name(&plugin).as_str());
|
||||||
|
desc.push('\n');
|
||||||
|
desc.push_str("<b>Description:");
|
||||||
|
desc.push_str("</b>");
|
||||||
|
desc.push_str(
|
||||||
|
>k::glib::markup_escape_text(&plugin.get_description()).to_string(),
|
||||||
|
);
|
||||||
|
desc.push('\n');
|
||||||
|
desc.push_str("<b>Filename:");
|
||||||
|
desc.push_str("</b>");
|
||||||
|
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("<b>Version:");
|
||||||
|
desc.push_str("</b>");
|
||||||
|
desc.push_str(>k::glib::markup_escape_text(&plugin.get_version()).to_string());
|
||||||
|
desc.push('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(desc)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
136
src/pluginlist.rs
Normal file
136
src/pluginlist.rs
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
// pluginlist.rs
|
||||||
|
//
|
||||||
|
// Copyright 2021 Stéphane Cerveau <scerveau@collabora.com>
|
||||||
|
//
|
||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
// 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::<String>()
|
||||||
|
.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::<String>()
|
||||||
|
.expect("Treeview selection, column 1"),
|
||||||
|
position: (100.0,100.0),
|
||||||
|
size: (100.0,100.0),
|
||||||
|
};
|
||||||
|
|
||||||
|
let element_name = model
|
||||||
|
.value(&iter, 1)
|
||||||
|
.get::<String>()
|
||||||
|
.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();
|
||||||
|
}
|
|
@ -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<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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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<ElementInfo>) {
|
|
||||||
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::<String>()
|
|
||||||
.expect("Treeview selection, column 1"),
|
|
||||||
model
|
|
||||||
.value(&iter, 0)
|
|
||||||
.get::<u32>()
|
|
||||||
.expect("Treeview selection, column 0"),
|
|
||||||
));
|
|
||||||
let element = Element {
|
|
||||||
name: model
|
|
||||||
.value(&iter, 1)
|
|
||||||
.get::<String>()
|
|
||||||
.expect("Treeview selection, column 1"),
|
|
||||||
position: (100.0,100.0),
|
|
||||||
size: (100.0,100.0),
|
|
||||||
};
|
|
||||||
|
|
||||||
let element_name = model
|
|
||||||
.value(&iter, 1)
|
|
||||||
.get::<String>()
|
|
||||||
.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();
|
|
||||||
}
|
|
Loading…
Reference in a new issue