Commit 9302dbe4 authored by Christopher Davis's avatar Christopher Davis

Port to GTK4 + libadwaita + gtk4-rs

This commit upgrades our rust dependencies and ports Tour to libadwaita+GTK4. As part of porting we now use GtkPicture instead of GtkImage, and AdwClamps to hold pages in place. This port is part of https://gitlab.gnome.org/GNOME/Initiatives/-/issues/26 and handles https://gitlab.gnome.org/GNOME/Initiatives/-/issues/32 Fixes https://gitlab.gnome.org/GNOME/gnome-tour/-/issues/36
parent 4ac7296b
...@@ -8,22 +8,19 @@ edition = "2018" ...@@ -8,22 +8,19 @@ edition = "2018"
video = ["gst_player", "gst"] video = ["gst_player", "gst"]
[dependencies] [dependencies]
glib = { version = "0.10", features = ["v2_64"] } gtk = { package = "gtk4", version = "0.3", features= ["v4_2"]}
gdk = "0.13"
gtk = { version = "0.9", features= ["v3_16"] }
gio = "0.9"
log = "0.4" log = "0.4"
gettext-rs = { version = "0.6", features = ["gettext-system"] } gettext-rs = { version = "0.6", features = ["gettext-system"] }
libhandy = "0.7" libadwaita = "0.1.0-alpha-6"
pretty_env_logger = "0.4" pretty_env_logger = "0.4"
[dependencies.gst_player] [dependencies.gst_player]
version = "0.16" version = "0.17"
package = "gstreamer-player" package = "gstreamer-player"
optional = true optional = true
[dependencies.gst] [dependencies.gst]
version = "0.16" version = "0.17"
package = "gstreamer" package = "gstreamer"
optional = true optional = true
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
<gresources> <gresources>
<gresource prefix="/org/gnome/Tour/"> <gresource prefix="/org/gnome/Tour/">
<file compressed="true" alias="style.css">resources/style.css</file> <file compressed="true" alias="style.css">resources/style.css</file>
<file compressed="true" alias="style-dark.css">resources/style-dark.css</file>
<file compressed="true" alias="welcome.svg">resources/assets/welcome.svg</file> <file compressed="true" alias="welcome.svg">resources/assets/welcome.svg</file>
<file compressed="true" alias="overview.svg">resources/assets/overview.svg</file> <file compressed="true" alias="overview.svg">resources/assets/overview.svg</file>
<file compressed="true" alias="search.svg">resources/assets/search.svg</file> <file compressed="true" alias="search.svg">resources/assets/search.svg</file>
......
.page { color: #fff; }
...@@ -11,8 +11,8 @@ base_id = 'org.gnome.Tour' ...@@ -11,8 +11,8 @@ base_id = 'org.gnome.Tour'
dependency('glib-2.0', version: '>= 2.64') dependency('glib-2.0', version: '>= 2.64')
dependency('gio-2.0', version: '>= 2.56') dependency('gio-2.0', version: '>= 2.56')
dependency('gdk-pixbuf-2.0') dependency('gdk-pixbuf-2.0')
dependency('gtk+-3.0', version: '>= 3.16') dependency('gtk4', version: '>= 4.4')
dependency('libhandy-1', version: '>= 1') dependency('libadwaita-1', version: '>= 1')
if get_option('video_path') != '' if get_option('video_path') != ''
dependency('gstreamer-1.0', version: '>= 1.12') dependency('gstreamer-1.0', version: '>= 1.12')
......
use crate::config; use crate::config;
use crate::utils; use crate::utils;
use crate::widgets::Window; use crate::widgets::Window;
use gio::prelude::*; use gtk::gdk;
use glib::clone; use gtk::gio::{self, prelude::*};
use gtk::glib::{self, clone};
use gtk::prelude::*; use gtk::prelude::*;
use log::info; use log::info;
use std::env;
use std::{cell::RefCell, rc::Rc}; use std::{cell::RefCell, rc::Rc};
pub struct Application { pub struct Application {
app: gtk::Application, app: libadwaita::Application,
window: RefCell<Rc<Option<Window>>>, window: RefCell<Rc<Option<Window>>>,
} }
impl Application { impl Application {
pub fn new() -> Rc<Self> { pub fn new() -> Rc<Self> {
let app = let app =
gtk::Application::new(Some(config::APP_ID), gio::ApplicationFlags::FLAGS_NONE).unwrap(); libadwaita::Application::new(Some(config::APP_ID), gio::ApplicationFlags::FLAGS_NONE);
app.set_resource_base_path(Some("/org/gnome/Tour"));
let application = Rc::new(Self { let application = Rc::new(Self {
app, app,
...@@ -86,8 +87,6 @@ impl Application { ...@@ -86,8 +87,6 @@ impl Application {
fn setup_signals(&self, app: Rc<Self>) { fn setup_signals(&self, app: Rc<Self>) {
self.app.connect_startup(clone!(@weak app => move |_| { self.app.connect_startup(clone!(@weak app => move |_| {
libhandy::init();
app.setup_css();
app.setup_gactions(app.clone()); app.setup_gactions(app.clone());
})); }));
self.app self.app
...@@ -100,20 +99,11 @@ impl Application { ...@@ -100,20 +99,11 @@ impl Application {
})); }));
} }
fn setup_css(&self) {
let p = gtk::CssProvider::new();
gtk::CssProvider::load_from_resource(&p, "/org/gnome/Tour/style.css");
if let Some(screen) = gdk::Screen::get_default() {
gtk::StyleContext::add_provider_for_screen(&screen, &p, 500);
}
}
pub fn run(&self) { pub fn run(&self) {
info!("GNOME Tour ({})", config::APP_ID); info!("GNOME Tour ({})", config::APP_ID);
info!("Version: {} ({})", config::VERSION, config::PROFILE); info!("Version: {} ({})", config::VERSION, config::PROFILE);
info!("Datadir: {}", config::PKGDATADIR); info!("Datadir: {}", config::PKGDATADIR);
let args: Vec<String> = env::args().collect(); self.app.run();
self.app.run(&args);
} }
} }
use gettextrs::*; use gettextrs::*;
use gtk::glib;
mod application; mod application;
mod config; mod config;
......
// Source: https://gitlab.gnome.org/World/podcasts/blob/master/podcasts-gtk/src/static_resource.rs // Source: https://gitlab.gnome.org/World/podcasts/blob/master/podcasts-gtk/src/static_resource.rs
use gio::{resources_register, Resource}; use gtk::gio::{resources_register, Resource};
use glib::{Bytes, Error}; use gtk::glib::{Bytes, Error};
pub(crate) fn init() -> Result<(), Error> { pub(crate) fn init() -> Result<(), Error> {
// load the gresource binary at build time and include/link it into the final // load the gresource binary at build time and include/link it into the final
......
// based on https://gitlab.gnome.org/World/podcasts/-/blob/master/podcasts-gtk/src/i18n|utils.rs // based on https://gitlab.gnome.org/World/podcasts/-/blob/master/podcasts-gtk/src/i18n|utils.rs
use gettextrs::gettext; use gettextrs::gettext;
use gtk::{gio, glib};
pub fn action<T, F>(thing: &T, name: &str, action: F) pub fn action<T, F>(thing: &T, name: &str, action: F)
where where
T: gio::ActionMapExt, T: gio::traits::ActionMapExt,
for<'r, 's> F: Fn(&'r gio::SimpleAction, Option<&glib::Variant>) + 'static, for<'r, 's> F: Fn(&'r gio::SimpleAction, Option<&glib::Variant>) + 'static,
{ {
// Create a stateless, parameterless action // Create a stateless, parameterless action
......
...@@ -15,8 +15,9 @@ impl ImagePageWidget { ...@@ -15,8 +15,9 @@ impl ImagePageWidget {
} }
fn init(&self, resource_uri: &str, head: String, body: String) { fn init(&self, resource_uri: &str, head: String, body: String) {
self.widget.set_property_expand(true); self.widget.set_hexpand(true);
self.widget.get_style_context().add_class("page"); self.widget.set_vexpand(true);
self.widget.add_css_class("page");
self.widget.set_halign(gtk::Align::Fill); self.widget.set_halign(gtk::Align::Fill);
self.widget.set_valign(gtk::Align::Fill); self.widget.set_valign(gtk::Align::Fill);
...@@ -31,11 +32,15 @@ impl ImagePageWidget { ...@@ -31,11 +32,15 @@ impl ImagePageWidget {
.margin_start(12) .margin_start(12)
.margin_end(12) .margin_end(12)
.build(); .build();
let clamp = libadwaita::Clamp::new();
clamp.set_child(Some(&container));
let image = gtk::Image::from_resource(&resource_uri); let picture = gtk::PictureBuilder::new()
image.set_valign(gtk::Align::Start); .can_shrink(false)
image.show(); .keep_aspect_ratio(true)
container.add(&image); .build();
picture.set_resource(Some(resource_uri));
container.append(&picture);
let head_label = gtk::LabelBuilder::new() let head_label = gtk::LabelBuilder::new()
.label(&head) .label(&head)
...@@ -43,9 +48,8 @@ impl ImagePageWidget { ...@@ -43,9 +48,8 @@ impl ImagePageWidget {
.valign(gtk::Align::Center) .valign(gtk::Align::Center)
.margin_top(36) .margin_top(36)
.build(); .build();
head_label.get_style_context().add_class("page-title"); head_label.add_css_class("page-title");
head_label.show(); container.append(&head_label);
container.add(&head_label);
let body_label = gtk::LabelBuilder::new() let body_label = gtk::LabelBuilder::new()
.label(&body) .label(&body)
...@@ -55,12 +59,9 @@ impl ImagePageWidget { ...@@ -55,12 +59,9 @@ impl ImagePageWidget {
.valign(gtk::Align::Center) .valign(gtk::Align::Center)
.margin_top(12) .margin_top(12)
.build(); .build();
body_label.get_style_context().add_class("page-body"); body_label.add_css_class("page-body");
body_label.show(); container.append(&body_label);
container.add(&body_label);
container.show(); self.widget.append(&clamp);
self.widget.add(&container);
self.widget.show();
} }
} }
...@@ -4,10 +4,11 @@ use crate::utils::i18n_f; ...@@ -4,10 +4,11 @@ use crate::utils::i18n_f;
use gettextrs::gettext; use gettextrs::gettext;
#[cfg(feature = "video")] #[cfg(feature = "video")]
use gio::FileExt; use gio::FileExt;
use gtk::glib;
#[cfg(feature = "video")] #[cfg(feature = "video")]
use glib::clone; use gtk::glib::clone;
#[cfg(feature = "video")] #[cfg(feature = "video")]
use glib::{Receiver, Sender}; use gtk::glib::{Receiver, Sender};
use gtk::prelude::*; use gtk::prelude::*;
#[cfg(feature = "video")] #[cfg(feature = "video")]
use std::cell::RefCell; use std::cell::RefCell;
...@@ -67,19 +68,26 @@ impl WelcomePageWidget { ...@@ -67,19 +68,26 @@ impl WelcomePageWidget {
let container = gtk::BoxBuilder::new() let container = gtk::BoxBuilder::new()
.orientation(gtk::Orientation::Vertical) .orientation(gtk::Orientation::Vertical)
.spacing(0) .spacing(0)
.expand(true) .hexpand(true)
.vexpand(true)
.valign(gtk::Align::Center) .valign(gtk::Align::Center)
.halign(gtk::Align::Center) .halign(gtk::Align::Center)
.margin_top(24) .margin_top(24)
.margin_bottom(24) .margin_bottom(24)
.build(); .build();
self.widget.get_style_context().add_class("page"); self.widget.add_css_class("page");
self.widget.get_style_context().add_class("welcome-page"); self.widget.add_css_class("welcome-page");
let clamp = libadwaita::Clamp::new();
clamp.set_child(Some(&container));
#[cfg(not(feature = "video"))] #[cfg(not(feature = "video"))]
let header = { let header = {
let logo = gtk::Image::from_resource("/org/gnome/Tour/welcome.svg"); let logo = gtk::PictureBuilder::new()
logo.show(); .can_shrink(false)
.keep_aspect_ratio(true)
.build();
logo.set_resource(Some("/org/gnome/Tour/welcome.svg"));
logo.upcast::<gtk::Widget>() logo.upcast::<gtk::Widget>()
}; };
...@@ -103,11 +111,11 @@ impl WelcomePageWidget { ...@@ -103,11 +111,11 @@ impl WelcomePageWidget {
video_widget.set_size_request(-1, 360); video_widget.set_size_request(-1, 360);
video_widget.set_property("ignore-alpha", &false).unwrap(); video_widget.set_property("ignore-alpha", &false).unwrap();
video_widget.show(); video_widget.show();
video_widget.get_style_context().add_class("video"); video_widget.add_css_class("video");
video_widget video_widget
}; };
container.add(&header); container.append(&header);
#[cfg(feature = "video")] #[cfg(feature = "video")]
{ {
...@@ -117,7 +125,7 @@ impl WelcomePageWidget { ...@@ -117,7 +125,7 @@ impl WelcomePageWidget {
clone!(@strong self.player as player => move |action| { clone!(@strong self.player as player => move |action| {
match action { match action {
Action::VideoReady => player.play(), Action::VideoReady => player.play(),
Action::VideoUp => header.get_style_context().add_class("playing"), Action::VideoUp => header.add_css_class("playing"),
}; };
glib::Continue(true) glib::Continue(true)
}), }),
...@@ -150,24 +158,20 @@ impl WelcomePageWidget { ...@@ -150,24 +158,20 @@ impl WelcomePageWidget {
let title = gtk::Label::new(Some(&gettext("Start the Tour"))); let title = gtk::Label::new(Some(&gettext("Start the Tour")));
title.set_margin_top(36); title.set_margin_top(36);
title.get_style_context().add_class("page-title"); title.add_css_class("page-title");
title.show(); container.append(&title);
container.add(&title);
let name = glib::get_os_info("NAME").unwrap_or_else(|| "GNOME".into()); let name = glib::os_info("NAME").unwrap_or_else(|| "GNOME".into());
let version = glib::get_os_info("VERSION").unwrap_or_else(|| "".into()); let version = glib::os_info("VERSION").unwrap_or_else(|| "".into());
// Translators: The following string is formated as "Learn about new and essential features in GNOME 3.36" for example // Translators: The following string is formated as "Learn about new and essential features in GNOME 3.36" for example
let text = gtk::Label::new(Some(&i18n_f( let text = gtk::Label::new(Some(&i18n_f(
"Learn about the key features in {} {}.", "Learn about the key features in {} {}.",
&[&name, &version], &[&name, &version],
))); )));
text.get_style_context().add_class("body"); text.add_css_class("body");
text.set_margin_top(12); text.set_margin_top(12);
text.show(); container.append(&text);
container.add(&text);
container.show(); self.widget.append(&clamp);
self.widget.add(&container);
self.widget.show();
} }
} }
use gettextrs::gettext; use gettextrs::gettext;
use glib::clone; use gtk::glib::{self, clone};
use gtk::prelude::*; use gtk::prelude::*;
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
use libhandy::prelude::{CarouselExt, CarouselIndicatorDotsExt, HeaderBarExt};
pub struct PaginatorWidget { pub struct PaginatorWidget {
pub widget: gtk::Box, pub widget: gtk::Box,
carousel: libhandy::Carousel, carousel: libadwaita::Carousel,
carousel_dots: libhandy::CarouselIndicatorDots, carousel_dots: libadwaita::CarouselIndicatorDots,
headerbar: libhandy::HeaderBar, headerbar: gtk::HeaderBar,
pages: RefCell<Vec<gtk::Widget>>, pages: RefCell<Vec<gtk::Widget>>,
current_page: RefCell<u32>, current_page: RefCell<u32>,
next_overlay: gtk::Overlay,
next_btn: gtk::Button, next_btn: gtk::Button,
start_btn: gtk::Button, start_btn: gtk::Button,
finish_btn: gtk::Button, finish_btn: gtk::Button,
...@@ -26,10 +25,13 @@ impl PaginatorWidget { ...@@ -26,10 +25,13 @@ impl PaginatorWidget {
let paginator = Rc::new(Self { let paginator = Rc::new(Self {
widget, widget,
carousel: libhandy::Carousel::new(), carousel: libadwaita::Carousel::new(),
carousel_dots: libhandy::CarouselIndicatorDots::new(), carousel_dots: libadwaita::CarouselIndicatorDots::new(),
headerbar: libhandy::HeaderBar::new(), headerbar: gtk::HeaderBarBuilder::new()
.show_title_buttons(false)
.build(),
start_btn: gtk::Button::with_label(&gettext("_Start")), start_btn: gtk::Button::with_label(&gettext("_Start")),
next_overlay: gtk::Overlay::new(),
next_btn: gtk::Button::with_label(&gettext("_Next")), next_btn: gtk::Button::with_label(&gettext("_Next")),
finish_btn: gtk::Button::with_label(&gettext("_Close")), finish_btn: gtk::Button::with_label(&gettext("_Close")),
close_btn: gtk::Button::with_label(&gettext("_Close")), close_btn: gtk::Button::with_label(&gettext("_Close")),
...@@ -43,7 +45,7 @@ impl PaginatorWidget { ...@@ -43,7 +45,7 @@ impl PaginatorWidget {
pub fn try_next(&self) -> Option<()> { pub fn try_next(&self) -> Option<()> {
let p = *self.current_page.borrow() + 1; let p = *self.current_page.borrow() + 1;
if p == self.carousel.get_n_pages() { if p == self.carousel.n_pages() {
return None; return None;
} }
self.set_page(p); self.set_page(p);
...@@ -68,20 +70,24 @@ impl PaginatorWidget { ...@@ -68,20 +70,24 @@ impl PaginatorWidget {
} }
fn update_position(&self) { fn update_position(&self) {
let position = self.carousel.get_position(); let position = self.carousel.position();
let page_nr = position.round() as u32; let page_nr = position.round() as u32;
let n_pages = self.carousel.get_n_pages() as f64; let n_pages = self.carousel.n_pages() as f64;
let forelast_page = n_pages - 2.0; let forelast_page = n_pages - 2.0;
let last_page = n_pages - 1.0; let last_page = n_pages - 1.0;
let (opacity_finish, opacity_previous, opacity_start, opacity_next) = let (opacity_finish, opacity_previous, opacity_start, opacity_next, opacity_close) =
if (0.0..1.0).contains(&position) { if (0.0..1.0).contains(&position) {
(0.0, position, 1.0, position) if position == 0.0 {
(0.0, position, 1.0, position, 1.0)
} else {
(0.0, position, 1.0, position, 1f64 - position)
}
} else if (0.0 <= position) && (position <= forelast_page) { } else if (0.0 <= position) && (position <= forelast_page) {
(0.0, 1.0, 1f64 - position, 1.0) (0.0, 1.0, 1f64 - position, 1.0, 0.0)
} else if (forelast_page < position) && (position <= last_page) { } else if (forelast_page < position) && (position <= last_page) {
(position - forelast_page, 1.0, 0.0, 1.0) (position - forelast_page, 1.0, 0.0, 1.0, 0.0)
} else { } else {
panic!("Position of the carousel is outside the allowed range"); panic!("Position of the carousel is outside the allowed range");
}; };
...@@ -91,6 +97,7 @@ impl PaginatorWidget { ...@@ -91,6 +97,7 @@ impl PaginatorWidget {
self.next_btn.set_opacity(opacity_next); self.next_btn.set_opacity(opacity_next);
self.next_btn.set_visible(opacity_next > 0_f64); self.next_btn.set_visible(opacity_next > 0_f64);
self.next_overlay.set_can_target(opacity_next > 0_f64);
self.finish_btn.set_opacity(opacity_finish); self.finish_btn.set_opacity(opacity_finish);
self.finish_btn.set_visible(opacity_finish > 0_f64); self.finish_btn.set_visible(opacity_finish > 0_f64);
...@@ -98,82 +105,69 @@ impl PaginatorWidget { ...@@ -98,82 +105,69 @@ impl PaginatorWidget {
self.previous_btn.set_opacity(opacity_previous); self.previous_btn.set_opacity(opacity_previous);
self.previous_btn.set_visible(opacity_previous > 0_f64); self.previous_btn.set_visible(opacity_previous > 0_f64);
self.close_btn.set_opacity(opacity_close);
self.start_btn.set_visible(opacity_close > 0_f64);
self.current_page.replace(page_nr); self.current_page.replace(page_nr);
} }
fn init(&self, p: Rc<Self>) { fn init(&self, p: Rc<Self>) {
self.carousel_dots.show();
self.carousel_dots.set_carousel(Some(&self.carousel)); self.carousel_dots.set_carousel(Some(&self.carousel));
self.carousel.set_property_expand(true); self.carousel.set_hexpand(true);
self.carousel.set_vexpand(true);
self.carousel.set_animation_duration(300); self.carousel.set_animation_duration(300);
self.carousel.show();
self.carousel self.carousel
.connect_property_position_notify(clone!(@weak p => move |_| { .connect_position_notify(clone!(@weak p => move |_| {
p.update_position(); p.update_position();
})); }));
self.start_btn self.start_btn.add_css_class("suggested-action");
.get_style_context()
.add_class("suggested-action");
self.start_btn.set_use_underline(true); self.start_btn.set_use_underline(true);
self.start_btn.set_action_name(Some("app.start-tour")); self.start_btn.set_action_name(Some("app.start-tour"));
self.start_btn.show();
self.next_btn self.next_btn.add_css_class("suggested-action");
.get_style_context()
.add_class("suggested-action");
self.next_btn.set_use_underline(true); self.next_btn.set_use_underline(true);
self.next_btn.set_action_name(Some("app.next-page")); self.next_btn.set_action_name(Some("app.next-page"));
self.close_btn.set_use_underline(true); self.close_btn.set_use_underline(true);
self.close_btn.set_action_name(Some("app.quit")); self.close_btn.set_action_name(Some("app.quit"));
self.close_btn.show();
self.finish_btn self.finish_btn.add_css_class("suggested-action");
.get_style_context()
.add_class("suggested-action");
self.finish_btn.set_use_underline(true); self.finish_btn.set_use_underline(true);
self.finish_btn.set_action_name(Some("app.quit")); self.finish_btn.set_action_name(Some("app.quit"));
self.previous_btn.set_use_underline(true); self.previous_btn.set_use_underline(true);
self.previous_btn.set_action_name(Some("app.previous-page")); self.previous_btn.set_action_name(Some("app.previous-page"));
self.next_overlay.set_child(Some(&self.next_btn));
self.next_overlay.add_overlay(&self.finish_btn);
self.next_overlay.set_can_target(false);
let previous_overlay = gtk::Overlay::new(); let previous_overlay = gtk::Overlay::new();
previous_overlay.add(&self.close_btn); previous_overlay.set_child(Some(&self.close_btn));
previous_overlay.add_overlay(&self.previous_btn); previous_overlay.add_overlay(&self.previous_btn);
previous_overlay.show();
let next_overlay = gtk::Overlay::new();
next_overlay.add(&self.next_btn);
next_overlay.add_overlay(&self.finish_btn);
next_overlay.show();
let start_overlay = gtk::Overlay::new(); let start_overlay = gtk::Overlay::new();
start_overlay.add(&self.start_btn); start_overlay.set_child(Some(&self.start_btn));
start_overlay.add_overlay(&next_overlay); start_overlay.add_overlay(&self.next_overlay);
start_overlay.set_overlay_pass_through(&next_overlay, true);
start_overlay.show();
let btn_size_group = gtk::SizeGroup::new(gtk::SizeGroupMode::Horizontal); let btn_size_group = gtk::SizeGroup::new(gtk::SizeGroupMode::Horizontal);
btn_size_group.add_widget(&self.previous_btn); btn_size_group.add_widget(&self.previous_btn);
btn_size_group.add_widget(&self.close_btn); btn_size_group.add_widget(&self.close_btn);
btn_size_group.add_widget(&next_overlay); btn_size_group.add_widget(&self.next_overlay);
btn_size_group.add_widget(&start_overlay); btn_size_group.add_widget(&start_overlay);
btn_size_group.add_widget(&self.finish_btn); btn_size_group.add_widget(&self.finish_btn);
self.headerbar.set_custom_title(Some(&self.carousel_dots)); self.headerbar.set_title_widget(Some(&self.carousel_dots));
self.headerbar.pack_start(&previous_overlay); self.headerbar.pack_start(&previous_overlay);
self.headerbar.pack_end(&start_overlay); self.headerbar.pack_end(&start_overlay);
self.headerbar.set_show_close_button(false);
self.headerbar.show();
self.widget.add(&self.headerbar); self.widget.append(&self.headerbar);
self.widget.add(&self.carousel); self.widget.append(&self.carousel);
self.widget.show();
} }
pub fn set_page(&self, page_nr: u32) { pub fn set_page(&self, page_nr: u32) {
if page_nr < self.carousel.get_n_pages() { if page_nr < self.carousel.n_pages() {
let pages = &self.pages.borrow(); let pages = &self.pages.borrow();
let page = pages.get(page_nr as usize).unwrap(); let page = pages.get(page_nr as usize).unwrap();
self.carousel.scroll_to(page); self.carousel.scroll_to(page);
......
use crate::utils::i18n_f; use crate::utils::i18n_f;
use gettextrs::gettext; use gettextrs::gettext;
use gtk::glib;
use gtk::prelude::*; use gtk::prelude::*;
use libadwaita::traits::ApplicationWindowExt;
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
...@@ -9,14 +11,13 @@ use super::paginator::PaginatorWidget; ...@@ -9,14 +11,13 @@ use super::paginator::PaginatorWidget;
use crate::config::{APP_ID, PROFILE}; use crate::config::{APP_ID, PROFILE};
pub struct Window { pub struct Window {
pub widget: libhandy::ApplicationWindow, pub widget: libadwaita::ApplicationWindow,
pub paginator: RefCell<Rc<PaginatorWidget>>, pub paginator: RefCell<Rc<PaginatorWidget>>,
} }
impl Window { impl Window {
pub fn new(app: &gtk::Application) -> Self { pub fn new(app: &libadwaita::Application) -> Self {
let widget = libhandy::ApplicationWindow::new(); let widget = libadwaita::ApplicationWindow::new(app);
widget.set_application(Some(app));
let paginator = RefCell::new(PaginatorWidget::new()); let paginator = RefCell::new(PaginatorWidget::new());
...@@ -40,7 +41,7 @@ impl Window { ...@@ -40,7 +41,7 @@ impl Window {
// Devel Profile // Devel Profile
if PROFILE == "Devel" { if PROFILE == "Devel" {
self.widget.get_style_context().add_class("devel"); self.widget.add_css_class("devel");
} }
self.paginator self.paginator
.borrow_mut() .borrow_mut()
...@@ -95,18 +96,19 @@ impl Window { ...@@ -95,18 +96,19 @@ impl Window {
.upcast::<gtk::Widget>(), .upcast::<gtk::Widget>(),
); );
let name = glib::get_os_info("NAME").unwrap_or_else(|| "GNOME".into()); let name = glib::os_info("NAME").unwrap_or_else(|| "GNOME".into());
let version = glib::get_os_info("VERSION").unwrap_or_else(|| "".into()); let version = glib::os_info("VERSION").unwrap_or_else(|| "".into());
let last_page = ImagePageWidget::new( let last_page = ImagePageWidget::new(
"/org/gnome/Tour/ready-to-go.svg", "/org/gnome/Tour/ready-to-go.svg",
gettext("That's it. Have a nice day!"), gettext("That's it. Have a nice day!"),
gettext("To get more advice and tips, see the Help app."), gettext("To get more advice and tips, see the Help app."),
); );
last_page.widget.get_style_context().add_class("last-page"); last_page.widget.add_css_class("last-page");
self.paginator self.paginator
.borrow_mut() .borrow_mut()
.add_page(last_page.widget.upcast::<gtk::Widget>()); .add_page(last_page.widget.upcast::<gtk::Widget>());
self.widget.add(&self.paginator.borrow().widget); self.widget
.set_content(Some(&self.paginator.borrow().widget));
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment