monorepo/kifu/gtk/src/app_window.rs

176 lines
5.7 KiB
Rust

/*
Copyright 2024, Savanni D'Gerinel <savanni@luminescent-dreams.com>
This file is part of Kifu.
Kifu 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.
Kifu 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 Kifu. If not, see <https://www.gnu.org/licenses/>.
*/
use adw::prelude::*;
/*
use gio::resources_lookup_data;
use glib::IsA;
use gtk::STYLE_PROVIDER_PRIORITY_USER;
*/
use kifu_core::{Config, Core};
use std::sync::{Arc, RwLock};
use crate::{view_models::HomeViewModel, view_models::SettingsViewModel};
#[derive(Clone)]
enum AppView {
Settings(SettingsViewModel),
Home(HomeViewModel),
}
// An application window should generally contain
// - an overlay widget
// - the main content in a stack on the bottom panel of the overlay
// - the settings and the about page in bins atop the overlay
#[derive(Clone)]
pub struct AppWindow {
pub window: adw::ApplicationWindow,
header: adw::HeaderBar,
// content is a stack which contains the view models for the application. These are the main
// elements that users want to interact with: the home page, the game library, a review, a game
// itself, perhaps also chat rooms and player lists on other networks. stack contains the
// widgets that need to be rendered. The two of these work together in order to ensure that
// we can maintain the state of previous views. Since the two of these work together, they are
// a candidate for extraction into a new widget or a new struct.
stack: adw::NavigationView,
content: Vec<AppView>,
// Overlays are for transient content, such as about and settings, which can be accessed from
// anywhere but shouldn't be part of the main application flow.
panel_overlay: gtk::Overlay,
core: Core,
// Not liking this, but I have to keep track of the settings view model separately from
// anything else. I'll have to look into this later.
settings_view_model: Arc<RwLock<Option<SettingsViewModel>>>,
}
impl AppWindow {
pub fn new(app: &adw::Application, core: Core) -> Self {
let window = Self::setup_window(app);
let header = Self::setup_header();
let panel_overlay = Self::setup_panel_overlay();
let (stack, content) = Self::setup_content(core.clone());
let layout = gtk::Box::builder()
.orientation(gtk::Orientation::Vertical)
.build();
layout.append(&header);
layout.append(&panel_overlay);
panel_overlay.set_child(Some(&stack));
window.set_content(Some(&layout));
Self {
window,
header,
stack,
content,
panel_overlay,
core,
settings_view_model: Default::default(),
}
}
pub fn open_settings(&self) {
let view_model = SettingsViewModel::new(&self.window, self.core.clone(), {
let s = self.clone();
move || {
s.close_overlay();
}
});
self.panel_overlay.add_overlay(&view_model.widget);
*self.settings_view_model.write().unwrap() = Some(view_model);
}
pub fn close_overlay(&self) {
let mut vm = self.settings_view_model.write().unwrap();
match *vm {
Some(ref mut view_model) => {
self.panel_overlay.remove_overlay(&view_model.widget);
*vm = None;
}
None => {}
}
}
fn setup_window(app: &adw::Application) -> adw::ApplicationWindow {
let window = adw::ApplicationWindow::builder()
.application(app)
.width_request(800)
.height_request(500)
.build();
window
}
fn setup_header() -> adw::HeaderBar {
let header = adw::HeaderBar::builder()
.title_widget(&gtk::Label::new(Some("Kifu")))
.build();
let app_menu = gio::Menu::new();
let menu_item = gio::MenuItem::new(Some("Configuration"), Some("app.show_settings"));
app_menu.append_item(&menu_item);
let hamburger = gtk::MenuButton::builder()
.icon_name("open-menu-symbolic")
.build();
hamburger.set_menu_model(Some(&app_menu));
header.pack_end(&hamburger);
header
}
fn setup_panel_overlay() -> gtk::Overlay {
gtk::Overlay::new()
}
fn setup_content(core: Core) -> (adw::NavigationView, Vec<AppView>) {
let stack = adw::NavigationView::new();
let mut content = Vec::new();
let nothing_page = adw::StatusPage::builder().title("Nothing here").build();
let _ = stack.push(
&adw::NavigationPage::builder()
.can_pop(false)
.title("Kifu")
.child(&nothing_page)
.build(),
);
content.push(AppView::Home(HomeViewModel::new(core.clone())));
/*
match *core.library() {
Some(_) => {
}
None => {
let settings_vm = SettingsViewModel::new(core.clone());
let _ = stack.push(&adw::NavigationPage::new(&settings_vm.widget, "Settings"));
content.push(AppView::Settings(settings_vm));
}
}
*/
(stack, content)
}
// pub fn set_content(content: &impl IsA<gtk::Widget>) -> adw::ViewStack {
// self.content.set_child(Some(content));
// }
}