diff --git a/.gitignore b/.gitignore index a9d37c5..965ad77 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ target Cargo.lock +.vscode/settings.json diff --git a/.travis.yml b/.travis.yml index bcfd1da..4ba17a6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ language: rust rust: - nightly - beta -- 1.39.0 # stable +- 1.41.0 # stable - stable env: - GTK=3.14 diff --git a/Cargo.toml b/Cargo.toml index e1f5f0c..dc8d6c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,6 +69,10 @@ name = "clock" [[bin]] name = "clone_macro" +[[bin]] +name = "communication_thread" +edition = "2018" + [[bin]] name = "css" @@ -91,6 +95,9 @@ name = "grid" [[bin]] name = "gtktest" +[[bin]] +name = "iconview_example" + [[bin]] name = "listbox_model" required-features = ["gtk/v3_16", "gio/v2_44"] diff --git a/build_travis.sh b/build_travis.sh index a070af6..f47003f 100755 --- a/build_travis.sh +++ b/build_travis.sh @@ -38,5 +38,5 @@ fi if [ -n "$OTHER_TARGET" ]; then PKG_CONFIG_ALLOW_CROSS=1 cargo check $OTHER_TARGET --features "$FEATURES" --jobs 1 "$@" else - RUSTFLAGS="-C link-dead-code" cargo build --features "$FEATURES" --jobs 1 "$@" + RUSTFLAGS="-C link-dead-code" cargo build -v --features "$FEATURES" --jobs 1 "$@" fi diff --git a/src/bin/accessibility.rs b/src/bin/accessibility.rs index c42addd..316f53e 100644 --- a/src/bin/accessibility.rs +++ b/src/bin/accessibility.rs @@ -20,7 +20,7 @@ fn build_ui(application: >k::Application) { window.set_title("Accessibility"); window.set_position(gtk::WindowPosition::Center); - let button = gtk::Button::new_with_label("Click me!"); + let button = gtk::Button::with_label("Click me!"); let label = gtk::Label::new(Some("0")); let vbox = gtk::Box::new(gtk::Orientation::Vertical, 0); @@ -43,11 +43,7 @@ fn build_ui(application: >k::Application) { window.add(&vbox); button.connect_clicked(move |_| { - let value = label - .get_text() - .and_then(|s| u32::from_str_radix(&s, 10).ok()) - .unwrap_or(0) - + 1; + let value = label.get_text().parse().unwrap_or(0) + 1; label.set_text(&value.to_string()); }); diff --git a/src/bin/basic.rs b/src/bin/basic.rs index deaaf3d..755fd49 100644 --- a/src/bin/basic.rs +++ b/src/bin/basic.rs @@ -20,7 +20,7 @@ fn build_ui(application: >k::Application) { window.set_position(gtk::WindowPosition::Center); window.set_default_size(350, 70); - let button = gtk::Button::new_with_label("Click me!"); + let button = gtk::Button::with_label("Click me!"); window.add(&button); diff --git a/src/bin/basic_subclass.rs b/src/bin/basic_subclass.rs index 27f31a5..63f0902 100644 --- a/src/bin/basic_subclass.rs +++ b/src/bin/basic_subclass.rs @@ -15,7 +15,7 @@ extern crate once_cell; use gio::prelude::*; use gtk::prelude::*; -use gio::subclass::application::ApplicationImplExt; +use gio::subclass::prelude::*; use gio::ApplicationFlags; use glib::subclass; use glib::subclass::prelude::*; @@ -69,7 +69,7 @@ impl ObjectImpl for SimpleWindowPrivate { let self_ = obj.downcast_ref::().unwrap(); let headerbar = gtk::HeaderBar::new(); - let increment = gtk::Button::new_with_label("Increment!"); + let increment = gtk::Button::with_label("Increment!"); let label = gtk::Label::new(Some("Press the Increment Button!")); headerbar.set_title(Some("Hello World!")); diff --git a/src/bin/builder_basics.rs b/src/bin/builder_basics.rs index 902645f..1414092 100644 --- a/src/bin/builder_basics.rs +++ b/src/bin/builder_basics.rs @@ -3,9 +3,11 @@ //! This sample demonstrates how to use the builder with an imported glade file extern crate gio; +extern crate glib; extern crate gtk; use gio::prelude::*; +use glib::clone; use gtk::prelude::*; use gtk::{ApplicationWindow, Builder, Button, MessageDialog}; @@ -14,7 +16,7 @@ use std::env::args; fn build_ui(application: >k::Application) { let glade_src = include_str!("builder_basics.glade"); - let builder = Builder::new_from_string(glade_src); + let builder = Builder::from_string(glade_src); let window: ApplicationWindow = builder.get_object("window1").expect("Couldn't get window1"); window.set_application(Some(application)); @@ -23,11 +25,12 @@ fn build_ui(application: >k::Application) { .get_object("messagedialog1") .expect("Couldn't get messagedialog1"); - bigbutton.connect_clicked(move |_| { - dialog.run(); + dialog.connect_delete_event(|dialog, _| { dialog.hide(); + gtk::Inhibit(true) }); + bigbutton.connect_clicked(clone!(@weak dialog => move |_| dialog.show_all())); window.show_all(); } diff --git a/src/bin/builder_signal.rs b/src/bin/builder_signal.rs index d7a2196..4b6de95 100644 --- a/src/bin/builder_signal.rs +++ b/src/bin/builder_signal.rs @@ -3,9 +3,11 @@ //! This sample demonstrates how to handle signals in builder extern crate gio; +extern crate glib; extern crate gtk; use gio::prelude::*; +use glib::clone; use gtk::prelude::*; use gtk::{ApplicationWindow, Builder, MessageDialog}; @@ -14,27 +16,28 @@ use std::env::args; fn build_ui(application: >k::Application) { let glade_src = include_str!("builder_signal.glade"); - let builder = Builder::new_from_string(glade_src); + let builder = Builder::from_string(glade_src); let window: ApplicationWindow = builder.get_object("window1").expect("Couldn't get window1"); window.set_application(Some(application)); let dialog: MessageDialog = builder .get_object("messagedialog1") .expect("Couldn't get messagedialog1"); + dialog.connect_delete_event(|dialog, _| { + dialog.hide(); + gtk::Inhibit(true) + }); builder.connect_signals(move |_, handler_name| { // This is the one-time callback to register signals. // Here we map each handler name to its handler. if handler_name == "button1_clicked" { - let dialog = dialog.clone(); - // Return the signal handler. - Box::new(move |_| { - dialog.run(); - dialog.hide(); + Box::new(clone!(@weak dialog => @default-return None, move |_| { + dialog.show_all(); None - }) + })) } else { panic!("Unknown handler name {}", handler_name) } diff --git a/src/bin/child-properties.rs b/src/bin/child-properties.rs index cc92025..2d4c2d1 100644 --- a/src/bin/child-properties.rs +++ b/src/bin/child-properties.rs @@ -15,12 +15,11 @@ use gtk::Orientation::Vertical; use gtk::{ApplicationWindow, Button, Label, PackType}; use std::env::args; -use std::str::FromStr; fn build_ui(application: >k::Application) { let vbox = gtk::Box::new(Vertical, 0); - let plus_button = Button::new_with_label("+"); + let plus_button = Button::with_label("+"); vbox.add(&plus_button); // Set some child properties. // These calls need to be added after the Widget is added to the Box. @@ -32,12 +31,12 @@ fn build_ui(application: >k::Application) { let counter_label = Label::new(Some("0")); vbox.add(&counter_label); - let minus_button = Button::new_with_label("-"); + let minus_button = Button::with_label("-"); vbox.add(&minus_button); minus_button.connect_clicked(clone!(@weak counter_label => move |_| { let nb = counter_label.get_text() - .and_then(|s| u32::from_str(&s).ok()) + .parse() .unwrap_or(0); if nb > 0 { counter_label.set_text(&format!("{}", nb - 1)); @@ -45,7 +44,7 @@ fn build_ui(application: >k::Application) { })); plus_button.connect_clicked(clone!(@weak counter_label => move |_| { let nb = counter_label.get_text() - .and_then(|s| u32::from_str(&s).ok()) + .parse() .unwrap_or(0); counter_label.set_text(&format!("{}", nb + 1)); })); diff --git a/src/bin/clipboard_simple.rs b/src/bin/clipboard_simple.rs index f7c05cf..1f5ea09 100644 --- a/src/bin/clipboard_simple.rs +++ b/src/bin/clipboard_simple.rs @@ -29,7 +29,7 @@ fn build_ui(application: >k::Application) { // Create the whole window window.set_title("gtk::Clipboard Simple Example"); window.connect_delete_event(|window, _| { - window.destroy(); + window.close(); Inhibit(false) }); @@ -37,18 +37,18 @@ fn build_ui(application: >k::Application) { let grid = gtk::Grid::new(); grid.set_row_homogeneous(true); grid.set_column_homogeneous(true); - let button_a1 = gtk::ToggleButton::new_with_label("A1"); + let button_a1 = gtk::ToggleButton::with_label("A1"); grid.attach(&button_a1, 0, 0, 1, 1); - let button_a2 = gtk::ToggleButton::new_with_label("A2"); + let button_a2 = gtk::ToggleButton::with_label("A2"); grid.attach(&button_a2, 1, 0, 1, 1); - let button_b1 = gtk::ToggleButton::new_with_label("B1"); + let button_b1 = gtk::ToggleButton::with_label("B1"); grid.attach(&button_b1, 0, 1, 1, 1); - let button_b2 = gtk::ToggleButton::new_with_label("B2"); + let button_b2 = gtk::ToggleButton::with_label("B2"); grid.attach(&button_b2, 1, 1, 1, 1); // Add in the action buttons - let copy_button = gtk::Button::new_with_mnemonic("_Copy"); - let paste_button = gtk::Button::new_with_mnemonic("_Paste"); + let copy_button = gtk::Button::with_mnemonic("_Copy"); + let paste_button = gtk::Button::with_mnemonic("_Paste"); let button_box = gtk::ButtonBox::new(gtk::Orientation::Horizontal); button_box.set_layout(gtk::ButtonBoxStyle::End); button_box.pack_start(©_button, false, false, 0); diff --git a/src/bin/clone_macro.rs b/src/bin/clone_macro.rs index e58f93e..263a865 100644 --- a/src/bin/clone_macro.rs +++ b/src/bin/clone_macro.rs @@ -41,7 +41,7 @@ fn main() { window.set_title("First GTK+ Program"); window.set_default_size(350, 70); - let button = Button::new_with_label("Click me!"); + let button = Button::with_label("Click me!"); button.connect_clicked(clone!(@weak state, @weak state2 => move |_| { let mut state = state.borrow_mut(); let mut state2 = state2.borrow_mut(); diff --git a/src/bin/communication_thread.rs b/src/bin/communication_thread.rs new file mode 100644 index 0000000..c7b0fb3 --- /dev/null +++ b/src/bin/communication_thread.rs @@ -0,0 +1,78 @@ +//! Example on how to use a communication thread alongside with the GUI thread. +//! +//! Tricks used here: +//! - Use a channel to show data on the GUI. +//! - Run an async function on the GUI event loop. +//! - Use a separate thread to handle incoming data and put it into a channel. + +use futures::{channel::mpsc, StreamExt}; +use gio::prelude::*; +use gtk::prelude::*; +use gtk::{ApplicationWindow, Label}; +use std::env::args; +use std::thread; + +fn main() { + let application = gtk::Application::new( + Some("com.github.gtk-rs.examples.communication_thread"), + Default::default(), + ) + .expect("Initialization failed..."); + application.connect_activate(build_ui); + application.run(&args().collect::>()); +} + +fn build_ui(application: >k::Application) { + let window = ApplicationWindow::new(application); + let label = Label::new(None); + window.add(&label); + + // Create a channel between communication thread and main event loop: + let (sender, receiver) = mpsc::channel(1000); + + spawn_local_handler(label, receiver); + start_communication_thread(sender); + window.show_all(); +} + +/// Spawn channel receive task on the main event loop. +fn spawn_local_handler(label: gtk::Label, mut receiver: mpsc::Receiver) { + let main_context = glib::MainContext::default(); + let future = async move { + while let Some(item) = receiver.next().await { + label.set_text(&item); + } + }; + main_context.spawn_local(future); +} + +/// Spawn separate thread to handle communication. +fn start_communication_thread(mut sender: mpsc::Sender) { + // Note that blocking I/O with threads can be prevented + // by using asynchronous code, which is often a better + // choice. For the sake of this example, we showcase the + // way to use a thread when there is no other option. + + thread::spawn(move || { + let mut counter = 0; + loop { + // Instead of a counter, your application code will + // block here on TCP or serial communications. + let data = format!("Counter = {}!", counter); + println!("Thread received data: {}", data); + match sender.try_send(data) { + Ok(_) => {} + Err(err) => { + if err.is_full() { + println!("Data is produced too fast for GUI"); + } else if err.is_disconnected() { + println!("GUI stopped, stopping thread."); + break; + } + } + } + counter += 1; + thread::sleep(std::time::Duration::from_millis(100)); + } + }); +} diff --git a/src/bin/css.rs b/src/bin/css.rs index efa4d05..b14c4a9 100644 --- a/src/bin/css.rs +++ b/src/bin/css.rs @@ -52,7 +52,7 @@ fn build_ui(application: >k::Application) { // The container container. let vbox = gtk::Box::new(gtk::Orientation::Vertical, 0); - let label = gtk::Button::new_with_label("hover me!"); + let label = gtk::Button::with_label("hover me!"); // We need to name it in order to be able to use its name as a CSS label to // apply CSS on it. gtk::WidgetExt::set_widget_name(&label, "label1"); diff --git a/src/bin/drag_and_drop.rs b/src/bin/drag_and_drop.rs index 764e946..df4d3d0 100644 --- a/src/bin/drag_and_drop.rs +++ b/src/bin/drag_and_drop.rs @@ -14,7 +14,7 @@ use std::env::args; fn build_ui(application: >k::Application) { // Configure button as drag source for text - let button = gtk::Button::new_with_label("Drag here"); + let button = gtk::Button::with_label("Drag here"); let targets = vec![ gtk::TargetEntry::new("STRING", gtk::TargetFlags::SAME_APP, 0), gtk::TargetEntry::new("text/plain", gtk::TargetFlags::SAME_APP, 0), diff --git a/src/bin/grid.rs b/src/bin/grid.rs index 540aa4b..d37d7cd 100644 --- a/src/bin/grid.rs +++ b/src/bin/grid.rs @@ -13,7 +13,7 @@ use std::env::args; fn build_ui(application: >k::Application) { let glade_src = include_str!("grid.glade"); - let builder = Builder::new_from_string(glade_src); + let builder = Builder::from_string(glade_src); let window: ApplicationWindow = builder.get_object("window").expect("Couldn't get window"); window.set_application(Some(application)); diff --git a/src/bin/gtktest.rs b/src/bin/gtktest.rs index 5310e58..0014cbd 100644 --- a/src/bin/gtktest.rs +++ b/src/bin/gtktest.rs @@ -24,14 +24,18 @@ fn about_clicked(button: &Button, dialog: &AboutDialog) { dialog.set_transient_for(Some(&window)); } + // We only want to hide the dialog when it's closed and not completely destroy it + // as otherwise we can't show it again a second time. + dialog.connect_delete_event(|dialog, _| { + dialog.hide(); + gtk::Inhibit(true) + }); + println!("Authors: {:?}", dialog.get_authors()); println!("Artists: {:?}", dialog.get_artists()); println!("Documenters: {:?}", dialog.get_documenters()); - // Since we only have once instance of this object with Glade, we only show/hide it. - dialog.show(); - dialog.run(); - dialog.hide(); + dialog.show_all(); } fn build_ui(application: >k::Application) { @@ -41,7 +45,7 @@ fn build_ui(application: >k::Application) { gtk::get_minor_version() ); let glade_src = include_str!("gtktest.glade"); - let builder = Builder::new_from_string(glade_src); + let builder = Builder::from_string(glade_src); let spinner: Spinner = builder.get_object("spinner").expect("Couldn't get spinner"); spinner.start(); @@ -56,9 +60,7 @@ fn build_ui(application: >k::Application) { .get_object("spin_button") .expect("Couldn't get spin_button"); spin_button.connect_input(|spin_button| { - let text = spin_button - .get_text() - .expect("Couldn't get text from spin_button"); + let text = spin_button.get_text(); println!("spin_button_input: \"{}\"", text); match text.parse::() { Ok(value) if value >= 90. => { @@ -81,18 +83,18 @@ fn build_ui(application: >k::Application) { let entry: Entry = builder.get_object("entry").expect("Couldn't get entry"); button.connect_clicked(clone!(@weak window, @weak entry => move |_| { - let dialog = Dialog::new_with_buttons(Some("Hello!"), + let dialog = Dialog::with_buttons(Some("Hello!"), Some(&window), gtk::DialogFlags::MODAL, &[("No", ResponseType::No), ("Yes", ResponseType::Yes), ("Custom", ResponseType::Other(0))]); - let ret = dialog.run(); - - dialog.destroy(); - - entry.set_text(&format!("Clicked {}", ret)); + dialog.connect_response(clone!(@weak entry => move |dialog, response| { + entry.set_text(&format!("Clicked {}", response)); + dialog.close(); + })); + dialog.show_all(); })); let button_font: Button = builder @@ -101,8 +103,8 @@ fn build_ui(application: >k::Application) { button_font.connect_clicked(clone!(@weak window => move |_| { let dialog = FontChooserDialog::new(Some("Font chooser test"), Some(&window)); - dialog.run(); - dialog.destroy(); + dialog.connect_response(|dialog, _| dialog.close()); + dialog.show_all(); })); let button_recent: Button = builder @@ -115,8 +117,8 @@ fn build_ui(application: >k::Application) { ("Cancel", ResponseType::Cancel) ]); - dialog.run(); - dialog.destroy(); + dialog.connect_response(|dialog, _| dialog.close()); + dialog.show_all(); })); let file_button: Button = builder @@ -132,11 +134,15 @@ fn build_ui(application: >k::Application) { ]); dialog.set_select_multiple(true); - dialog.run(); - let files = dialog.get_filenames(); - dialog.destroy(); - println!("Files: {:?}", files); + dialog.connect_response(|dialog, response| { + if response == ResponseType::Ok { + let files = dialog.get_filenames(); + println!("Files: {:?}", files); + } + dialog.close(); + }); + dialog.show_all(); })); let app_button: Button = builder @@ -148,8 +154,8 @@ fn build_ui(application: >k::Application) { gtk::DialogFlags::MODAL, "sh"); - dialog.run(); - dialog.destroy(); + dialog.connect_response(|dialog, _| dialog.close()); + dialog.show_all(); })); let switch: Switch = builder.get_object("switch").expect("Couldn't get switch"); @@ -173,7 +179,7 @@ fn build_ui(application: >k::Application) { let keystate = key.get_state(); println!("key pressed: {} / {:?}", keyval, keystate); - println!("text: {}", entry.get_text().expect("Couldn't get text from entry")); + println!("text: {}", entry.get_text()); if keystate.intersects(gdk::ModifierType::CONTROL_MASK) { println!("You pressed Ctrl!"); diff --git a/src/bin/iconview_example.rs b/src/bin/iconview_example.rs new file mode 100644 index 0000000..044586f --- /dev/null +++ b/src/bin/iconview_example.rs @@ -0,0 +1,116 @@ +//! # IconView Sample +//! +//! This sample demonstrates how to create a toplevel `window`, set its title, size and +//! position, how to add a `IconView` to this `window` and how to set `model` of the `IconView` +//! +//! A Gtk.IconView is a widget that displays a collection of icons in a grid view. +//! It supports features such as drag and drop, multiple selections and item reordering. +//! Similarly to Gtk.TreeView, Gtk.IconView uses a Gtk.ListStore for its model. +//! +//! Instead of using cell renderers, Gtk.IconView requires that one of the columns in its +//! Gtk.ListStore contains GdkPixbuf.Pixbuf objects. +//! +//! The example is using icons from the current icon theme. To view all icons and their names please +//! install gtk3-icon-browser: https://developer.gnome.org/gtk3/stable/gtk3-icon-browser.html + +extern crate gio; +extern crate gtk; + +use gio::prelude::*; +use gtk::prelude::*; + +use std::env::args; +use std::process; + +// Convenience Enum for IconView column types +enum IconViewColumnType { + TextColumn = 0, + PixbufColumn = 1, +} + +fn create_list_store_model() -> gtk::ListStore { + // Initialize array of icon names, these can be found using gtk3-icon-browser app + let icons: [&'static str; 3] = ["edit-cut", "edit-paste", "edit-copy"]; + + // Initialize an array of column types for ListStore object. Here we say that the first item + // must always be of glib::Type String and the second item is of glib::Type Pixbuf. + let col_types: [glib::Type; 2] = [glib::Type::String, gdk_pixbuf::Pixbuf::static_type()]; + let icon_view_model = gtk::ListStore::new(&col_types); + + // IconTheme provides a facility for looking up icons by name and size. + // + // Get default icon theme + let icon_theme: Option = gtk::IconTheme::get_default(); + if let Some(it) = icon_theme { + for x in &icons { + // Looks up an icon in an icon theme, scales it to the given size and renders it into + // a pixbuf. + let result = it.load_icon(x, 64, gtk::IconLookupFlags::empty()); + match result { + Ok(r) => { + // Notice how we specified the first column to be Text and second to be Pixbuf + // just like in col_types var. + // + // The values also follow the same order, &[&String::from("Label"), &r]. + // First item is text, second is pixbuf + icon_view_model.insert_with_values( + None, + &[ + IconViewColumnType::TextColumn as u32, + IconViewColumnType::PixbufColumn as u32, + ], + &[&String::from("Label"), &r], + ); + } + Err(err) => { + println!("Error: {}", err); + process::exit(1); + } + } + } + } + + return icon_view_model; +} + +fn build_ui(application: >k::Application) { + let window = gtk::ApplicationWindow::new(application); + + window.set_title("IconView Example"); + window.set_border_width(10); + window.set_position(gtk::WindowPosition::Center); + window.set_default_size(350, 70); + + let icon_view = gtk::IconView::new(); + icon_view.set_item_padding(0); + icon_view.set_columns(3); + icon_view.set_column_spacing(0); + // User can select only one item at a time + icon_view.set_selection_mode(gtk::SelectionMode::Single); + + // Create a model for our IconView + let icon_view_model = create_list_store_model(); + // Set IconView model + icon_view.set_model(Some(&icon_view_model)); + + // And finally set text column and pixbuf column using enum + icon_view.set_text_column(IconViewColumnType::TextColumn as i32); + icon_view.set_pixbuf_column(IconViewColumnType::PixbufColumn as i32); + + window.add(&icon_view); + window.show_all(); +} + +fn main() { + let application = gtk::Application::new( + Some("com.github.gtk-rs.examples.iconview_example"), + Default::default(), + ) + .expect("Initialization failed..."); + + application.connect_activate(|app| { + build_ui(app); + }); + + application.run(&args().collect::>()); +} diff --git a/src/bin/list_store.rs b/src/bin/list_store.rs index 509f077..3fdb3f7 100644 --- a/src/bin/list_store.rs +++ b/src/bin/list_store.rs @@ -43,7 +43,7 @@ fn build_ui(application: >k::Application) { vbox.add(&sw); let model = Rc::new(create_model()); - let treeview = gtk::TreeView::new_with_model(&*model); + let treeview = gtk::TreeView::with_model(&*model); treeview.set_vexpand(true); treeview.set_search_column(Columns::Description as i32); diff --git a/src/bin/listbox_model.rs b/src/bin/listbox_model.rs index 7410471..c4669ee 100644 --- a/src/bin/listbox_model.rs +++ b/src/bin/listbox_model.rs @@ -68,7 +68,7 @@ fn build_ui(application: >k::Application) { .build(); hbox.pack_start(&label, true, true, 0); - let spin_button = gtk::SpinButton::new_with_range(0.0, 100.0, 1.0); + let spin_button = gtk::SpinButton::with_range(0.0, 100.0, 1.0); item.bind_property("count", &spin_button, "value") .flags(glib::BindingFlags::DEFAULT | glib::BindingFlags::SYNC_CREATE | glib::BindingFlags::BIDIRECTIONAL) .build(); @@ -76,12 +76,12 @@ fn build_ui(application: >k::Application) { // When the edit button is clicked, a new modal dialog is created for editing // the corresponding row - let edit_button = gtk::Button::new_with_label("Edit"); + let edit_button = gtk::Button::with_label("Edit"); edit_button.connect_clicked(clone!(@weak window, @strong item => move |_| { - let dialog = gtk::Dialog::new_with_buttons(Some("Edit Item"), Some(&window), gtk::DialogFlags::MODAL, + let dialog = gtk::Dialog::with_buttons(Some("Edit Item"), Some(&window), gtk::DialogFlags::MODAL, &[("Close", ResponseType::Close)]); dialog.set_default_response(ResponseType::Close); - dialog.connect_response(|dialog, _| dialog.destroy()); + dialog.connect_response(|dialog, _| dialog.close()); let content_area = dialog.get_content_area(); @@ -100,7 +100,7 @@ fn build_ui(application: >k::Application) { })); content_area.add(&entry); - let spin_button = gtk::SpinButton::new_with_range(0.0, 100.0, 1.0); + let spin_button = gtk::SpinButton::with_range(0.0, 100.0, 1.0); item.bind_property("count", &spin_button, "value") .flags(glib::BindingFlags::DEFAULT | glib::BindingFlags::SYNC_CREATE | glib::BindingFlags::BIDIRECTIONAL) .build(); @@ -133,9 +133,9 @@ fn build_ui(application: >k::Application) { // and only create it once the Ok button in the dialog is clicked, and only // then add it to the model. Once added to the model, it will immediately // appear in the listbox UI - let add_button = gtk::Button::new_with_label("Add"); + let add_button = gtk::Button::with_label("Add"); add_button.connect_clicked(clone!(@weak window, @weak model => move |_| { - let dialog = gtk::Dialog::new_with_buttons(Some("Add Item"), Some(&window), gtk::DialogFlags::MODAL, + let dialog = gtk::Dialog::with_buttons(Some("Add Item"), Some(&window), gtk::DialogFlags::MODAL, &[("Ok", ResponseType::Ok), ("Cancel", ResponseType::Cancel)]); dialog.set_default_response(ResponseType::Ok); @@ -147,16 +147,15 @@ fn build_ui(application: >k::Application) { })); content_area.add(&entry); - let spin_button = gtk::SpinButton::new_with_range(0.0, 100.0, 1.0); + let spin_button = gtk::SpinButton::with_range(0.0, 100.0, 1.0); content_area.add(&spin_button); dialog.connect_response(clone!(@weak model, @weak entry, @weak spin_button => move |dialog, resp| { - if let Some(text) = entry.get_text() { - if !text.is_empty() && resp == ResponseType::Ok { - model.append(&RowData::new(&text, spin_button.get_value() as u32)); - } + let text = entry.get_text(); + if !text.is_empty() && resp == ResponseType::Ok { + model.append(&RowData::new(&text, spin_button.get_value() as u32)); } - dialog.destroy(); + dialog.close(); })); dialog.show_all(); @@ -167,7 +166,7 @@ fn build_ui(application: >k::Application) { // Via the delete button we delete the item from the model that // is at the index of the selected row. Also deleting from the // model is immediately reflected in the listbox. - let delete_button = gtk::Button::new_with_label("Delete"); + let delete_button = gtk::Button::with_label("Delete"); delete_button.connect_clicked(clone!(@weak model, @weak listbox => move |_| { let selected = listbox.get_selected_row(); diff --git a/src/bin/menu_bar.rs b/src/bin/menu_bar.rs index 01c589d..55c34f4 100644 --- a/src/bin/menu_bar.rs +++ b/src/bin/menu_bar.rs @@ -31,18 +31,18 @@ fn build_ui(application: >k::Application) { let accel_group = AccelGroup::new(); window.add_accel_group(&accel_group); let menu_bar = MenuBar::new(); - let file = MenuItem::new_with_label("File"); - let about = MenuItem::new_with_label("About"); - let quit = MenuItem::new_with_label("Quit"); + let file = MenuItem::with_label("File"); + let about = MenuItem::with_label("About"); + let quit = MenuItem::with_label("Quit"); let file_item = MenuItem::new(); let file_box = gtk::Box::new(gtk::Orientation::Horizontal, 0); - let file_image = Image::new_from_file("resources/file.png"); + let file_image = Image::from_file("resources/file.png"); let file_label = Label::new(Some("File")); let folder_item = MenuItem::new(); let folder_box = gtk::Box::new(gtk::Orientation::Horizontal, 0); - let folder_image = Image::new_from_icon_name(Some("folder-music-symbolic"), IconSize::Menu); + let folder_image = Image::from_icon_name(Some("folder-music-symbolic"), IconSize::Menu); let folder_label = Label::new(Some("Folder")); - let check_item = CheckMenuItem::new_with_label("Click me!"); + let check_item = CheckMenuItem::with_label("Click me!"); file_box.pack_start(&file_image, false, false, 0); file_box.pack_start(&file_label, true, true, 0); @@ -60,11 +60,11 @@ fn build_ui(application: >k::Application) { let other_menu = Menu::new(); let sub_other_menu = Menu::new(); - let other = MenuItem::new_with_label("Another"); - let sub_other = MenuItem::new_with_label("Sub another"); - let sub_other2 = MenuItem::new_with_label("Sub another 2"); - let sub_sub_other2 = MenuItem::new_with_label("Sub sub another 2"); - let sub_sub_other2_2 = MenuItem::new_with_label("Sub sub another2 2"); + let other = MenuItem::with_label("Another"); + let sub_other = MenuItem::with_label("Sub another"); + let sub_other2 = MenuItem::with_label("Sub another 2"); + let sub_sub_other2 = MenuItem::with_label("Sub sub another 2"); + let sub_sub_other2_2 = MenuItem::with_label("Sub sub another2 2"); sub_other_menu.append(&sub_sub_other2); sub_other_menu.append(&sub_sub_other2_2); @@ -75,7 +75,7 @@ fn build_ui(application: >k::Application) { menu_bar.append(&other); quit.connect_activate(clone!(@weak window => move |_| { - window.destroy(); + window.close(); })); // `Primary` is `Ctrl` on Windows and Linux, and `command` on macOS @@ -99,8 +99,7 @@ fn build_ui(application: >k::Application) { p.set_authors(&["Gtk-rs developers"]); p.set_title("About!"); p.set_transient_for(Some(&window)); - p.run(); - p.destroy(); + p.show_all(); }); check_item.connect_toggled(|w| { w.set_label(if w.get_active() { diff --git a/src/bin/menu_bar_system.rs b/src/bin/menu_bar_system.rs index 8b7b9c8..20f06f0 100644 --- a/src/bin/menu_bar_system.rs +++ b/src/bin/menu_bar_system.rs @@ -83,7 +83,7 @@ fn add_actions( let quit = gio::SimpleAction::new("quit", None); quit.connect_activate(clone!(@weak window => move |_, _| { - window.destroy(); + window.close(); })); let about = gio::SimpleAction::new("about", None); @@ -94,8 +94,7 @@ fn add_actions( p.set_authors(&["Gtk-rs developers"]); p.set_title("About!"); p.set_transient_for(Some(&window)); - p.run(); - p.destroy(); + p.show_all(); })); // We need to add all the actions to the application so they can be taken into account. diff --git a/src/bin/multi_windows.rs b/src/bin/multi_windows.rs index 0348707..fc5b593 100644 --- a/src/bin/multi_windows.rs +++ b/src/bin/multi_windows.rs @@ -32,7 +32,7 @@ fn create_sub_window( }), ); - let button = gtk::Button::new_with_label(&format!("Notify main window with id {}!", id)); + let button = gtk::Button::with_label(&format!("Notify main window with id {}!", id)); button.connect_clicked(clone!(@weak main_window_entry => move |_| { // When the button is clicked, let's write it on the main window's entry! main_window_entry.get_buffer().set_text(&format!("sub window {} clicked", id)); @@ -88,7 +88,7 @@ fn build_ui(application: >k::Application) { entry.set_placeholder_text(Some("Events notification will be sent here")); // Now let's create a button to create a looooot of new windows! - let button = gtk::Button::new_with_label("Create new window"); + let button = gtk::Button::with_label("Create new window"); button.connect_clicked( clone!(@weak windows_title_entry, @weak entry, @weak application => move |_| { let new_id = generate_new_id(&windows.borrow()); diff --git a/src/bin/notebook.rs b/src/bin/notebook.rs index bea114a..6180af3 100644 --- a/src/bin/notebook.rs +++ b/src/bin/notebook.rs @@ -23,7 +23,7 @@ impl Notebook { } fn create_tab(&mut self, title: &str, widget: Widget) -> u32 { - let close_image = gtk::Image::new_from_icon_name(Some("window-close"), IconSize::Button); + let close_image = gtk::Image::from_icon_name(Some("window-close"), IconSize::Button); let button = gtk::Button::new(); let label = gtk::Label::new(Some(title)); let tab = gtk::Box::new(Orientation::Horizontal, 0); diff --git a/src/bin/overlay.rs b/src/bin/overlay.rs index 47a8aa7..6e1cd4c 100644 --- a/src/bin/overlay.rs +++ b/src/bin/overlay.rs @@ -61,9 +61,9 @@ fn build_ui(application: >k::Application) { let hbox = gtk::Box::new(gtk::Orientation::Horizontal, 0); - let but1 = gtk::Button::new_with_label("Click me!"); - let but2 = gtk::Button::new_with_label("Or me!"); - let but3 = gtk::Button::new_with_label("Why not me?"); + let but1 = gtk::Button::with_label("Click me!"); + let but2 = gtk::Button::with_label("Or me!"); + let but3 = gtk::Button::with_label("Why not me?"); // When a button is clicked on, we set its label to the overlay label. let overlay_text_weak = overlay_text.downgrade(); diff --git a/src/bin/printing.rs b/src/bin/printing.rs index a8d9e39..8577380 100644 --- a/src/bin/printing.rs +++ b/src/bin/printing.rs @@ -58,7 +58,15 @@ fn print(window: >k::Window, value1: String, value2: String) { pangocairo::functions::show_layout(&cairo, &pango_layout); }); - //Open Print dialog setting up main window as its parent + // Handle printing asynchronously: run() will immediately return below on + // platforms where this is supported and once the dialog is finished the + // "done" signal will be emitted. + print_operation.set_allow_async(true); + print_operation.connect_done(|_, res| { + println!("printing done: {:?}", res); + }); + + // Open Print dialog setting up main window as its parent print_operation .run(gtk::PrintOperationAction::PrintDialog, Option::from(window)) .expect("Couldn't print"); @@ -66,7 +74,7 @@ fn print(window: >k::Window, value1: String, value2: String) { fn build_ui(application: >k::Application) { let glade_src = include_str!("printing.glade"); - let builder = gtk::Builder::new_from_string(glade_src); + let builder = gtk::Builder::from_string(glade_src); let window: gtk::Window = builder.get_object("window").expect("Couldn't get window"); window.set_application(Some(application)); @@ -77,8 +85,8 @@ fn build_ui(application: >k::Application) { .expect("Couldn't get buttonprint"); button_print.connect_clicked(clone!(@weak window => move |_| { - let text1 = entry1.get_text().expect("Couldn't get text1").to_string(); - let text2 = entry2.get_text().expect("Couldn't get text2").to_string(); + let text1 = entry1.get_text().to_string(); + let text2 = entry2.get_text().to_string(); print(&window, text1, text2); })); diff --git a/src/bin/progress_tracker.rs b/src/bin/progress_tracker.rs index 1d719d0..0357b61 100644 --- a/src/bin/progress_tracker.rs +++ b/src/bin/progress_tracker.rs @@ -141,7 +141,7 @@ impl Widgets { window.show_all(); window.set_default_size(500, 250); window.connect_delete_event(move |window, _| { - window.destroy(); + window.close(); Inhibit(false) }); diff --git a/src/bin/text_viewer.rs b/src/bin/text_viewer.rs index 930b8c7..9564ce5 100644 --- a/src/bin/text_viewer.rs +++ b/src/bin/text_viewer.rs @@ -43,21 +43,24 @@ pub fn build_ui(application: >k::Application) { ("Open", gtk::ResponseType::Ok), ("Cancel", gtk::ResponseType::Cancel), ]); - if file_chooser.run() == gtk::ResponseType::Ok { - let filename = file_chooser.get_filename().expect("Couldn't get filename"); - let file = File::open(&filename).expect("Couldn't open file"); + file_chooser.connect_response(clone!(@weak text_view => move |file_chooser, response| { + if response == gtk::ResponseType::Ok { + let filename = file_chooser.get_filename().expect("Couldn't get filename"); + let file = File::open(&filename).expect("Couldn't open file"); - let mut reader = BufReader::new(file); - let mut contents = String::new(); - let _ = reader.read_to_string(&mut contents); + let mut reader = BufReader::new(file); + let mut contents = String::new(); + let _ = reader.read_to_string(&mut contents); - text_view - .get_buffer() - .expect("Couldn't get window") - .set_text(&contents); - } + text_view + .get_buffer() + .expect("Couldn't get window") + .set_text(&contents); + } + file_chooser.close(); + })); - file_chooser.destroy(); + file_chooser.show_all(); })); window.show_all(); diff --git a/src/bin/transparent_main_window.rs b/src/bin/transparent_main_window.rs index eca0636..79970be 100644 --- a/src/bin/transparent_main_window.rs +++ b/src/bin/transparent_main_window.rs @@ -26,7 +26,7 @@ fn build_ui(application: >k::Application) { let fixed = Fixed::new(); window.add(&fixed); - let button = Button::new_with_label("Dummy"); + let button = Button::with_label("Dummy"); button.set_size_request(100, 30); fixed.add(&button); diff --git a/src/bin/tree_model_sort.rs b/src/bin/tree_model_sort.rs index 6ea47b4..4206121 100644 --- a/src/bin/tree_model_sort.rs +++ b/src/bin/tree_model_sort.rs @@ -29,7 +29,7 @@ fn build_ui(application: >k::Application) { let sortable_store = gtk::TreeModelSort::new(&store); // Then we create the `TreeView` from the `TreeModelSort`. - let treeview = gtk::TreeView::new_with_model(&sortable_store); + let treeview = gtk::TreeView::with_model(&sortable_store); let column = gtk::TreeViewColumn::new(); column.set_title("Value"); diff --git a/src/bin/treeview.rs b/src/bin/treeview.rs index 0a95a76..6751a12 100644 --- a/src/bin/treeview.rs +++ b/src/bin/treeview.rs @@ -67,7 +67,7 @@ fn build_ui(application: >k::Application) { let renderer2 = CellRendererText::new(); col.pack_start(&renderer2, true); col.add_attribute(&renderer2, "text", 1); - let image = Pixbuf::new_from_file("./resources/eye.png") + let image = Pixbuf::from_file("./resources/eye.png") .or_else(|err| { let mut msg = err.to_string(); if err.kind() == Some(glib::FileError::Noent) { @@ -81,8 +81,8 @@ fn build_ui(application: >k::Application) { clone!(@weak window => @default-return glib::Continue(false), move || { let dialog = MessageDialog::new(Some(&window), DialogFlags::MODAL, MessageType::Error, ButtonsType::Ok, &msg); - dialog.run(); - dialog.destroy(); + dialog.connect_response(|dialog, _| dialog.close()); + dialog.show_all(); Continue(false) }), );