mirror of
https://github.com/an-anime-team/an-anime-game-launcher.git
synced 2025-02-03 14:30:50 +03:00
Synced project structure with krypt0nn/gtk-example-app
This commit is contained in:
parent
9d5c0cc9ee
commit
e2754a4eec
3 changed files with 147 additions and 67 deletions
10
src/main.rs
10
src/main.rs
|
@ -19,15 +19,9 @@ fn main() {
|
|||
|
||||
// Init app window and show it
|
||||
application.connect_activate(|app| {
|
||||
let app = MainApp::new(app).unwrap();
|
||||
let app = MainApp::new(app).expect("Failed to init MainApp");
|
||||
|
||||
let app_copy = app.clone();
|
||||
|
||||
app.open_preferences.connect_clicked(move |_| {
|
||||
app_copy.open_preferences_page();
|
||||
});
|
||||
|
||||
app.window.show();
|
||||
app.show();
|
||||
});
|
||||
|
||||
// Run app
|
||||
|
|
202
src/ui/main.rs
202
src/ui/main.rs
|
@ -1,28 +1,31 @@
|
|||
use gtk4::{self as gtk, prelude::*};
|
||||
use libadwaita::{self as adw, prelude::*};
|
||||
|
||||
use super::get_object;
|
||||
use std::rc::Rc;
|
||||
use std::cell::Cell;
|
||||
|
||||
use crate::ui::*;
|
||||
|
||||
use super::preferences::PreferencesStack;
|
||||
use super::ToastError;
|
||||
|
||||
use crate::lib::game;
|
||||
|
||||
pub enum AppState {
|
||||
Launch,
|
||||
Progress {
|
||||
title: String,
|
||||
progress: f64
|
||||
}
|
||||
}
|
||||
|
||||
/// This structure is used to describe widgets used in application
|
||||
///
|
||||
/// `AppWidgets::try_get` function loads UI file from `.assets/ui/.dist` folder and returns structure with references to its widgets
|
||||
///
|
||||
/// This function does not implement events
|
||||
#[derive(Clone)]
|
||||
pub struct App {
|
||||
pub struct AppWidgets {
|
||||
pub window: adw::ApplicationWindow,
|
||||
pub toast_overlay: adw::ToastOverlay,
|
||||
|
||||
pub leaflet: adw::Leaflet,
|
||||
|
||||
pub launch_game: adw::SplitButton,
|
||||
pub launch_game_debug: gtk::Button,
|
||||
pub open_preferences: gtk::Button,
|
||||
pub toast_overlay: adw::ToastOverlay,
|
||||
|
||||
pub launch_game_group: adw::PreferencesGroup,
|
||||
pub progress_bar_group: adw::PreferencesGroup,
|
||||
|
@ -31,22 +34,22 @@ pub struct App {
|
|||
pub preferences_stack: PreferencesStack
|
||||
}
|
||||
|
||||
impl App {
|
||||
pub fn new(app: >k::Application) -> Result<Self, String> {
|
||||
// Create builder from UI file
|
||||
impl AppWidgets {
|
||||
fn try_get() -> Result<Self, String> {
|
||||
let builder = gtk::Builder::from_string(include_str!("../../assets/ui/.dist/main.ui"));
|
||||
|
||||
let window = get_object::<adw::ApplicationWindow>(&builder, "window")?;
|
||||
let toast_overlay = get_object::<adw::ToastOverlay>(&builder, "toast_overlay")?;
|
||||
|
||||
// Parse objects from builder
|
||||
let result = Self {
|
||||
window: window.clone(),
|
||||
toast_overlay: toast_overlay.clone(),
|
||||
|
||||
leaflet: get_object(&builder, "leaflet")?,
|
||||
|
||||
launch_game: get_object(&builder, "launch_game")?,
|
||||
launch_game_debug: get_object(&builder, "launch_game_debug")?,
|
||||
open_preferences: get_object(&builder, "open_preferences")?,
|
||||
toast_overlay: toast_overlay.clone(),
|
||||
|
||||
launch_game_group: get_object(&builder, "launch_game_group")?,
|
||||
progress_bar_group: get_object(&builder, "progress_bar_group")?,
|
||||
|
@ -56,68 +59,151 @@ impl App {
|
|||
};
|
||||
|
||||
// Add preferences page to the leaflet
|
||||
let leaflet = result.leaflet.clone();
|
||||
|
||||
result.leaflet.append(&result.preferences_stack.preferences).set_name(Some("preferences_page"));
|
||||
|
||||
// Go back button for preferences page
|
||||
result.preferences_stack.preferences_go_back.connect_clicked(move |_| {
|
||||
leaflet.navigate(adw::NavigationDirection::Back);
|
||||
});
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
// Launch game
|
||||
let app_copy = result.clone();
|
||||
|
||||
result.launch_game.connect_clicked(move |_| {
|
||||
// Display toast message if the game is failed to run
|
||||
if let Err(err) = game::run(false) {
|
||||
app_copy.toast_error("Failed to run game", err);
|
||||
}
|
||||
});
|
||||
/// This enum is used to describe an action inside of this application
|
||||
///
|
||||
/// It may be helpful if you want to add the same event for several widgets, or call an action inside of another action
|
||||
#[derive(Debug)]
|
||||
pub enum Actions {
|
||||
OpenPreferencesPage,
|
||||
PreferencesGoBack,
|
||||
LaunchGame
|
||||
}
|
||||
|
||||
// Launch game in debug mode
|
||||
/*let app_copy = result.clone();
|
||||
|
||||
result.launch_game_debug.connect_clicked(move |_| {
|
||||
// Display toast message if the game is failed to run
|
||||
if let Err(err) = game::run(true) {
|
||||
app_copy.toast_error("Failed to run game", err);
|
||||
}
|
||||
});*/
|
||||
/// This enum is used to store some of this application data
|
||||
///
|
||||
/// In this example we store a counter here to know what should we increment or decrement
|
||||
///
|
||||
/// This must implement `Default` trait
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Values;
|
||||
|
||||
/// The main application structure
|
||||
///
|
||||
/// `Default` macro automatically calls `AppWidgets::default`, i.e. loads UI file and reference its widgets
|
||||
///
|
||||
/// `Rc<Cell<Values>>` means this:
|
||||
/// - `Rc` addeds ability to reference the same value from various clones of the structure.
|
||||
/// This will guarantee us that inner `Cell<Values>` is the same for all the `App::clone()` values
|
||||
/// - `Cell` addeds inner mutability to its value, so we can mutate it even without mutable reference.
|
||||
///
|
||||
/// So we have a shared reference to some value that can be changed without mutable reference.
|
||||
/// That's what we need and what we use in `App::update` method
|
||||
#[derive(Clone)]
|
||||
pub struct App {
|
||||
widgets: AppWidgets,
|
||||
values: Rc<Cell<Values>>
|
||||
}
|
||||
|
||||
impl App {
|
||||
/// Create new application
|
||||
pub fn new(app: >k::Application) -> Result<Self, String> {
|
||||
let result = Self {
|
||||
widgets: AppWidgets::try_get()?,
|
||||
values: Default::default()
|
||||
}.init_events();
|
||||
|
||||
// Bind app to the window
|
||||
result.window.set_application(Some(app));
|
||||
result.widgets.window.set_application(Some(app));
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub fn open_preferences_page(&self) {
|
||||
self.leaflet.set_visible_child_name("preferences_page");
|
||||
/// Add default events and values to the widgets
|
||||
fn init_events(self) -> Self {
|
||||
// Open preferences page
|
||||
let self_copy = self.clone();
|
||||
|
||||
if let Err(err) = self.preferences_stack.update() {
|
||||
self.toast_error("Failed to update preferences", err);
|
||||
}
|
||||
self.widgets.open_preferences.connect_clicked(move |_| {
|
||||
self_copy.update(Actions::OpenPreferencesPage);
|
||||
});
|
||||
|
||||
// Go back button for preferences page
|
||||
let self_copy = self.clone();
|
||||
|
||||
self.widgets.preferences_stack.preferences_go_back.connect_clicked(move |_| {
|
||||
self_copy.update(Actions::PreferencesGoBack);
|
||||
});
|
||||
|
||||
// Launch game
|
||||
let self_copy = self.clone();
|
||||
|
||||
self.widgets.launch_game.connect_clicked(move |_| {
|
||||
self_copy.update(Actions::LaunchGame);
|
||||
});
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn update_state(&self, state: AppState) {
|
||||
match state {
|
||||
AppState::Launch => {
|
||||
self.launch_game_group.set_visible(true);
|
||||
self.progress_bar_group.set_visible(false);
|
||||
},
|
||||
AppState::Progress { title, progress } => {
|
||||
self.launch_game_group.set_visible(false);
|
||||
self.progress_bar_group.set_visible(true);
|
||||
/// Update widgets state by calling some action
|
||||
pub fn update(&self, action: Actions) {
|
||||
let values = self.values.take();
|
||||
|
||||
self.progress_bar.set_text(Some(&title));
|
||||
self.progress_bar.set_fraction(progress);
|
||||
println!("[update] action: {:?}, counter: {:?}", &action, &values);
|
||||
|
||||
match action {
|
||||
Actions::OpenPreferencesPage => {
|
||||
self.widgets.leaflet.set_visible_child_name("preferences_page");
|
||||
|
||||
if let Err(err) = self.widgets.preferences_stack.update() {
|
||||
self.toast_error("Failed to update preferences", err);
|
||||
}
|
||||
}
|
||||
|
||||
Actions::PreferencesGoBack => {
|
||||
self.widgets.leaflet.navigate(adw::NavigationDirection::Back);
|
||||
}
|
||||
|
||||
Actions::LaunchGame => {
|
||||
// Display toast message if the game is failed to run
|
||||
if let Err(err) = game::run(false) {
|
||||
self.toast_error("Failed to run game", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.values.set(values);
|
||||
}
|
||||
|
||||
/// Show application window
|
||||
pub fn show(&self) {
|
||||
self.widgets.window.show();
|
||||
}
|
||||
}
|
||||
|
||||
impl ToastError for App {
|
||||
fn get_toast_widgets(&self) -> (adw::ApplicationWindow, adw::ToastOverlay) {
|
||||
(self.window.clone(), self.toast_overlay.clone())
|
||||
(self.widgets.window.clone(), self.widgets.toast_overlay.clone())
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
pub enum AppState {
|
||||
Launch,
|
||||
Progress {
|
||||
title: String,
|
||||
progress: f64
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_state(&self, state: AppState) {
|
||||
match state {
|
||||
AppState::Launch => {
|
||||
self.launch_game_group.set_visible(true);
|
||||
self.progress_bar_group.set_visible(false);
|
||||
},
|
||||
AppState::Progress { title, progress } => {
|
||||
self.launch_game_group.set_visible(false);
|
||||
self.progress_bar_group.set_visible(true);
|
||||
|
||||
self.progress_bar.set_text(Some(&title));
|
||||
self.progress_bar.set_fraction(progress);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -7,7 +7,7 @@ mod toast_error;
|
|||
|
||||
pub use main::{
|
||||
App as MainApp,
|
||||
AppState as MainAppState,
|
||||
// AppState as MainAppState,
|
||||
};
|
||||
|
||||
pub use toast_error::ToastError;
|
||||
|
|
Loading…
Add table
Reference in a new issue