feat: intial work
This commit is contained in:
parent
be1d5b0fb3
commit
1bc959bd56
36 changed files with 3050 additions and 316 deletions
2024
Cargo.lock
generated
Normal file
2024
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
10
Cargo.toml
10
Cargo.toml
|
@ -9,6 +9,14 @@ lto = true
|
|||
|
||||
[dependencies]
|
||||
gettext-rs = { version = "0.7", features = ["gettext-system"] }
|
||||
gtk = { version = "0.7", package = "gtk4", features = ["v4_8"] }
|
||||
gtk = { version = "0.7", package = "gtk4", features = ["v4_10"] }
|
||||
tracing = "0.1.37"
|
||||
tracing-subscriber = "0.3"
|
||||
reqwest = { version = "0.11", features = ["json", "blocking"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
gsettings-macro = "0.1.20"
|
||||
|
||||
[dependencies.adw]
|
||||
package = "libadwaita"
|
||||
version = "0.5"
|
||||
features = ["v1_4"]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "dev.mnts.ModManager.Devel",
|
||||
"runtime": "org.gnome.Platform",
|
||||
"runtime-version": "44",
|
||||
"runtime-version": "45",
|
||||
"sdk": "org.gnome.Sdk",
|
||||
"sdk-extensions": [
|
||||
"org.freedesktop.Sdk.Extension.rust-stable",
|
||||
|
@ -19,9 +19,7 @@
|
|||
],
|
||||
"build-options": {
|
||||
"append-path": "/usr/lib/sdk/rust-stable/bin:/usr/lib/sdk/llvm16/bin",
|
||||
"build-args": [
|
||||
"--share=network"
|
||||
],
|
||||
"build-args": ["--share=network"],
|
||||
"env": {
|
||||
"CARGO_REGISTRIES_CRATES_IO_PROTOCOL": "sparse",
|
||||
"CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER": "clang",
|
||||
|
@ -29,19 +27,37 @@
|
|||
"CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER": "clang",
|
||||
"CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUSTFLAGS": "-C link-arg=-fuse-ld=/usr/lib/sdk/rust-stable/bin/mold"
|
||||
},
|
||||
"test-args": [
|
||||
"--socket=x11",
|
||||
"--share=network"
|
||||
]
|
||||
"test-args": ["--socket=x11", "--share=network"]
|
||||
},
|
||||
"cleanup": [
|
||||
"/include",
|
||||
"/lib/pkgconfig",
|
||||
"/man",
|
||||
"/share/doc",
|
||||
"/share/gtk-doc",
|
||||
"/share/man",
|
||||
"/share/pkgconfig",
|
||||
"*.la",
|
||||
"*.a"
|
||||
],
|
||||
"modules": [
|
||||
{
|
||||
"name": "blueprint-compiler",
|
||||
"buildsystem": "meson",
|
||||
"cleanup": ["*"],
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://gitlab.gnome.org/jwestman/blueprint-compiler",
|
||||
"tag": "v0.10.0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "mod-manager",
|
||||
"buildsystem": "meson",
|
||||
"run-tests": true,
|
||||
"config-opts": [
|
||||
"-Dprofile=development"
|
||||
],
|
||||
"config-opts": ["-Dprofile=development"],
|
||||
"sources": [
|
||||
{
|
||||
"type": "dir",
|
||||
|
@ -51,4 +67,3 @@
|
|||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
@ -13,5 +13,10 @@
|
|||
<default>false</default>
|
||||
<summary>Window maximized state</summary>
|
||||
</key>
|
||||
<key name="games" type="{ss}">
|
||||
<default>{}</default>
|
||||
<summary>Dictionary of games being managed. First string is game name second is path to mods
|
||||
folder.</summary>
|
||||
</key>
|
||||
</schema>
|
||||
</schemalist>
|
||||
</schemalist>
|
|
@ -1,8 +1,20 @@
|
|||
# Resources
|
||||
blueprints = custom_target('blueprints',
|
||||
input: files(
|
||||
'ui/windows/main/main.blp',
|
||||
'ui/windows/main/pages/welcome.blp',
|
||||
'ui/windows/main/pages/games_and_mods.blp',
|
||||
'ui/windows/add_new_game/add_new_game.blp',
|
||||
'ui/components/mods_list.blp',
|
||||
),
|
||||
output: '.',
|
||||
command: [find_program('blueprint-compiler'), 'batch-compile', '@OUTPUT@', '@CURRENT_SOURCE_DIR@', '@INPUT@'],
|
||||
)
|
||||
resources = gnome.compile_resources(
|
||||
'resources',
|
||||
'resources.gresource.xml',
|
||||
gresource_bundle: true,
|
||||
dependencies: blueprints,
|
||||
source_dir: meson.current_build_dir(),
|
||||
install: true,
|
||||
install_dir: pkgdatadir,
|
||||
|
|
|
@ -2,8 +2,11 @@
|
|||
<gresources>
|
||||
<gresource prefix="/dev/mnts/ModManager/">
|
||||
<!-- see https://gtk-rs.org/gtk4-rs/git/docs/gtk4/struct.Application.html#automatic-resources -->
|
||||
<file compressed="true" preprocess="xml-stripblanks" alias="gtk/help-overlay.ui">ui/shortcuts.ui</file>
|
||||
<file compressed="true" preprocess="xml-stripblanks">ui/window.ui</file>
|
||||
<file compressed="true">ui/windows/main/main.ui</file>
|
||||
<file compressed="true">ui/windows/main/pages/welcome.ui</file>
|
||||
<file compressed="true">ui/windows/main/pages/games_and_mods.ui</file>
|
||||
<file compressed="true">ui/windows/add_new_game/add_new_game.ui</file>
|
||||
<file compressed="true">ui/components/mods_list.ui</file>
|
||||
<file compressed="true">style.css</file>
|
||||
</gresource>
|
||||
</gresources>
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
.title-header{
|
||||
font-size: 36px;
|
||||
font-weight: bold;
|
||||
}
|
135
data/resources/ui/components/mods_list.blp
Normal file
135
data/resources/ui/components/mods_list.blp
Normal file
|
@ -0,0 +1,135 @@
|
|||
using Gtk 4.0;
|
||||
using Adw 1;
|
||||
|
||||
template $ModsList : Adw.NavigationPage {
|
||||
title: _("Main");
|
||||
|
||||
Adw.ToolbarView {
|
||||
[top]
|
||||
Adw.HeaderBar header_bar {
|
||||
show-back-button: true;
|
||||
}
|
||||
|
||||
content: Box {
|
||||
orientation: vertical;
|
||||
valign: center;
|
||||
halign: center;
|
||||
|
||||
Image {
|
||||
name: "logo";
|
||||
icon-name: "re.sonny.Workbench";
|
||||
pixel-size: 196;
|
||||
margin-bottom: 30;
|
||||
|
||||
styles [
|
||||
"icon-dropshadow"
|
||||
]
|
||||
}
|
||||
|
||||
Label {
|
||||
label: _("Welcome to Mod Manager");
|
||||
margin-bottom: 30;
|
||||
|
||||
styles [
|
||||
"title-1"
|
||||
]
|
||||
}
|
||||
|
||||
Box subtitle {
|
||||
orientation: vertical;
|
||||
halign: center;
|
||||
margin-bottom: 30;
|
||||
|
||||
Label {
|
||||
label: "Learn and prototype with\nGNOME technologies";
|
||||
justify: center;
|
||||
}
|
||||
}
|
||||
|
||||
Box {
|
||||
orientation: vertical;
|
||||
homogeneous: true;
|
||||
halign: center;
|
||||
|
||||
Box {
|
||||
margin-bottom: 6;
|
||||
|
||||
Image {
|
||||
icon-name: "update-symbolic";
|
||||
margin-end: 12;
|
||||
icon-size: normal;
|
||||
}
|
||||
|
||||
Label {
|
||||
label: _("Edit Style or UI to update the Preview");
|
||||
}
|
||||
}
|
||||
|
||||
Box {
|
||||
margin-bottom: 6;
|
||||
|
||||
Image {
|
||||
icon-name: "media-playback-start-symbolic";
|
||||
margin-end: 12;
|
||||
icon-size: normal;
|
||||
}
|
||||
|
||||
Label {
|
||||
label: _("Hit");
|
||||
}
|
||||
|
||||
ShortcutsShortcut {
|
||||
accelerator: "<Control>Return";
|
||||
margin-start: 12;
|
||||
}
|
||||
|
||||
Label {
|
||||
label: _("to format and run Code");
|
||||
}
|
||||
}
|
||||
|
||||
Box {
|
||||
margin-bottom: 6;
|
||||
|
||||
Image {
|
||||
icon-name: "media-floppy-symbolic";
|
||||
margin-end: 12;
|
||||
icon-size: normal;
|
||||
}
|
||||
|
||||
Label {
|
||||
label: _("Changes are automatically saved and restored");
|
||||
}
|
||||
}
|
||||
|
||||
Box {
|
||||
margin-bottom: 6;
|
||||
|
||||
Image {
|
||||
icon-name: "library-symbolic";
|
||||
margin-end: 12;
|
||||
icon-size: normal;
|
||||
}
|
||||
|
||||
Label {
|
||||
label: _("Browse the Library for demos and examples");
|
||||
}
|
||||
}
|
||||
|
||||
Box {
|
||||
margin-bottom: 6;
|
||||
|
||||
Image {
|
||||
icon-name: "user-bookmarks-symbolic";
|
||||
margin-end: 12;
|
||||
icon-size: normal;
|
||||
}
|
||||
|
||||
Label {
|
||||
label: _("Checkout the Bookmarks menu to learn and get help");
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<object class="GtkShortcutsWindow" id="help_overlay">
|
||||
<property name="modal">True</property>
|
||||
<child>
|
||||
<object class="GtkShortcutsSection">
|
||||
<property name="section-name">shortcuts</property>
|
||||
<property name="max-height">10</property>
|
||||
<child>
|
||||
<object class="GtkShortcutsGroup">
|
||||
<property name="title" translatable="yes" context="shortcut window">General</property>
|
||||
<child>
|
||||
<object class="GtkShortcutsShortcut">
|
||||
<property name="title" translatable="yes" context="shortcut window">Show Shortcuts</property>
|
||||
<property name="action-name">win.show-help-overlay</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkShortcutsShortcut">
|
||||
<property name="title" translatable="yes" context="shortcut window">Quit</property>
|
||||
<property name="action-name">app.quit</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
|
@ -1,41 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<menu id="primary_menu">
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_Preferences</attribute>
|
||||
<attribute name="action">app.preferences</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_Keyboard Shortcuts</attribute>
|
||||
<attribute name="action">win.show-help-overlay</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_About Mod Manager</attribute>
|
||||
<attribute name="action">app.about</attribute>
|
||||
</item>
|
||||
</section>
|
||||
</menu>
|
||||
<template class="ExampleApplicationWindow" parent="GtkApplicationWindow">
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar" id="headerbar">
|
||||
<child type="end">
|
||||
<object class="GtkMenuButton" id="appmenu_button">
|
||||
<property name="icon-name">open-menu-symbolic</property>
|
||||
<property name="menu-model">primary_menu</property>
|
||||
<property name="primary">True</property>
|
||||
<property name="tooltip-text" translatable="yes">Main Menu</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label">
|
||||
<property name="label" translatable="yes">Hello world!</property>
|
||||
<style>
|
||||
<class name="title-header"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
46
data/resources/ui/windows/add_new_game/add_new_game.blp
Normal file
46
data/resources/ui/windows/add_new_game/add_new_game.blp
Normal file
|
@ -0,0 +1,46 @@
|
|||
using Gtk 4.0;
|
||||
using Adw 1;
|
||||
|
||||
template $ModManagerWindowAddNewGame : Adw.ApplicationWindow {
|
||||
default-width: 600;
|
||||
default-height: 400;
|
||||
title: _("Add a new game");
|
||||
|
||||
content: Adw.ToolbarView {
|
||||
[top]
|
||||
Adw.HeaderBar header_bar {
|
||||
show-back-button: true;
|
||||
}
|
||||
|
||||
content: Box {
|
||||
orientation: vertical;
|
||||
halign: center;
|
||||
valign: center;
|
||||
|
||||
Label {
|
||||
label: _("Chose a game to manage mods for");
|
||||
margin-bottom: 30;
|
||||
justify: center;
|
||||
wrap: true;
|
||||
styles ["title-1"]
|
||||
}
|
||||
|
||||
DropDown games_dropdown {
|
||||
margin-bottom: 30;
|
||||
}
|
||||
|
||||
FileDialog mods_folder {
|
||||
title: _("Chose a location where to install the mods");
|
||||
}
|
||||
|
||||
Button chose_button {
|
||||
label: _("Chose the location");
|
||||
margin-bottom: 30;
|
||||
}
|
||||
|
||||
Button complete_button {
|
||||
label: _("Add game");
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
25
data/resources/ui/windows/main/main.blp
Normal file
25
data/resources/ui/windows/main/main.blp
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
Copyright (c) 2023 Tine Jozelj
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Gtk 4.0;
|
||||
using Adw 1;
|
||||
|
||||
template $ModManagerWindowMain : Adw.ApplicationWindow {
|
||||
default-width: 1000;
|
||||
default-height: 800;
|
||||
title: _("Mod Manager");
|
||||
}
|
45
data/resources/ui/windows/main/pages/games_and_mods.blp
Normal file
45
data/resources/ui/windows/main/pages/games_and_mods.blp
Normal file
|
@ -0,0 +1,45 @@
|
|||
using Gtk 4.0;
|
||||
using Adw 1;
|
||||
|
||||
template $GamesAndMods: Adw.Bin {
|
||||
Adw.NavigationSplitView {
|
||||
sidebar: Adw.NavigationPage {
|
||||
title: "Games";
|
||||
tag: "sidebar";
|
||||
|
||||
Adw.ToolbarView {
|
||||
[top]
|
||||
Adw.HeaderBar {
|
||||
}
|
||||
|
||||
content: Box {
|
||||
Label {
|
||||
label: "The Sims 4";
|
||||
}
|
||||
Label {
|
||||
label: "The Sims 3";
|
||||
}
|
||||
Label {
|
||||
label: "The Sims 2";
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
content: Adw.NavigationPage{
|
||||
title: "Mods";
|
||||
tag: "content";
|
||||
|
||||
Adw.ToolbarView {
|
||||
[top]
|
||||
Adw.HeaderBar {
|
||||
}
|
||||
|
||||
content: Box {
|
||||
Label {
|
||||
label: "Mods";
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
28
data/resources/ui/windows/main/pages/welcome.blp
Normal file
28
data/resources/ui/windows/main/pages/welcome.blp
Normal file
|
@ -0,0 +1,28 @@
|
|||
using Gtk 4.0;
|
||||
using Adw 1;
|
||||
|
||||
template $Welcome: Adw.Bin {
|
||||
Adw.ToolbarView {
|
||||
[top]
|
||||
Adw.HeaderBar {
|
||||
}
|
||||
|
||||
content: Box {
|
||||
orientation: vertical;
|
||||
halign: center;
|
||||
valign: center;
|
||||
|
||||
Label {
|
||||
label: "No games added yet!";
|
||||
justify: center;
|
||||
wrap: true;
|
||||
styles ["title-1"]
|
||||
margin-bottom: 30;
|
||||
}
|
||||
Button add_new_game {
|
||||
label: "Add new game";
|
||||
styles ["suggested-action", "pill"]
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
15
src/api/base.rs
Normal file
15
src/api/base.rs
Normal file
|
@ -0,0 +1,15 @@
|
|||
pub const API_URL: &str = "https://api.curseforge.com";
|
||||
|
||||
pub fn get_curse_forge_client() -> Result<reqwest::blocking::Client, reqwest::Error> {
|
||||
let mut api_key_header =
|
||||
reqwest::header::HeaderValue::from_str(crate::config::API_KEY).unwrap();
|
||||
api_key_header.set_sensitive(true);
|
||||
|
||||
let mut headers = reqwest::header::HeaderMap::new();
|
||||
headers.insert("x-api-key", api_key_header);
|
||||
|
||||
reqwest::blocking::Client::builder()
|
||||
.user_agent(format!("dev.mnts.ModManager/{}", crate::config::VERSION))
|
||||
.default_headers(headers)
|
||||
.build()
|
||||
}
|
46
src/api/games.rs
Normal file
46
src/api/games.rs
Normal file
|
@ -0,0 +1,46 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
use crate::api::*;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
struct Response {
|
||||
data: Vec<Game>,
|
||||
pagination: Pagination,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
struct Game {
|
||||
id: u32,
|
||||
name: String,
|
||||
slug: String,
|
||||
dateModified: String,
|
||||
assets: Assets,
|
||||
status: u32,
|
||||
apiStatus: u32,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
struct Assets {
|
||||
iconUrl: Option<String>,
|
||||
tileUrl: String,
|
||||
coverUrl: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
struct Pagination {
|
||||
index: u32,
|
||||
pageSize: u32,
|
||||
resultCount: u32,
|
||||
totalCount: u32,
|
||||
}
|
||||
|
||||
pub fn get_games() -> Vec<String> {
|
||||
let client = base::get_curse_forge_client().unwrap();
|
||||
let response = client
|
||||
.get(&format!("{}/v1/games", base::API_URL))
|
||||
.send()
|
||||
.unwrap();
|
||||
let json: Response = response.json().unwrap();
|
||||
|
||||
return json.data.iter().map(|game| game.name.clone()).collect();
|
||||
}
|
5
src/api/mod.rs
Normal file
5
src/api/mod.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
mod base;
|
||||
pub use base::*;
|
||||
|
||||
pub mod games;
|
||||
pub use games::*;
|
|
@ -1,50 +1,80 @@
|
|||
use gettextrs::gettext;
|
||||
/* application.rs
|
||||
*
|
||||
* Copyright 2023 Tine
|
||||
*
|
||||
* 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-or-later
|
||||
*/
|
||||
|
||||
use adw::subclass::prelude::*;
|
||||
use gtk::{gdk, prelude::*};
|
||||
use gtk::{gio, glib};
|
||||
use tracing::{debug, info};
|
||||
|
||||
use gtk::prelude::*;
|
||||
use gtk::subclass::prelude::*;
|
||||
use gtk::{gdk, gio, glib};
|
||||
|
||||
use crate::config::{APP_ID, PKGDATADIR, PROFILE, VERSION};
|
||||
use crate::window::ExampleApplicationWindow;
|
||||
use crate::config::APP_ID;
|
||||
use crate::config::VERSION;
|
||||
use crate::settings::ModManagerSettings;
|
||||
use crate::windows::main::ModManagerWindowMain;
|
||||
use crate::windows::main::Welcome;
|
||||
|
||||
mod imp {
|
||||
|
||||
use super::*;
|
||||
use glib::WeakRef;
|
||||
use std::cell::OnceCell;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ExampleApplication {
|
||||
pub window: OnceCell<WeakRef<ExampleApplicationWindow>>,
|
||||
}
|
||||
pub struct ModManagerApplication {}
|
||||
|
||||
#[glib::object_subclass]
|
||||
impl ObjectSubclass for ExampleApplication {
|
||||
const NAME: &'static str = "ExampleApplication";
|
||||
type Type = super::ExampleApplication;
|
||||
type ParentType = gtk::Application;
|
||||
impl ObjectSubclass for ModManagerApplication {
|
||||
const NAME: &'static str = "ModManagerApplication";
|
||||
type Type = super::ModManagerApplication;
|
||||
type ParentType = adw::Application;
|
||||
}
|
||||
|
||||
impl ObjectImpl for ExampleApplication {}
|
||||
impl ObjectImpl for ModManagerApplication {
|
||||
fn constructed(&self) {
|
||||
self.parent_constructed();
|
||||
let obj = self.obj();
|
||||
obj.set_accels_for_action("app.quit", &["<primary>q"]);
|
||||
}
|
||||
}
|
||||
|
||||
impl ApplicationImpl for ExampleApplication {
|
||||
impl ApplicationImpl for ModManagerApplication {
|
||||
// We connect to the activate callback to create a window when the application
|
||||
// has been launched. Additionally, this callback notifies us when the user
|
||||
// tries to launch a "second instance" of the application. When they try
|
||||
// to do that, we'll just present any existing window.
|
||||
fn activate(&self) {
|
||||
debug!("GtkApplication<ExampleApplication>::activate");
|
||||
self.parent_activate();
|
||||
let app = self.obj();
|
||||
let application = self.obj();
|
||||
// Get the current window or create one if necessary
|
||||
let window = if let Some(window) = application.active_window() {
|
||||
window
|
||||
} else {
|
||||
let settings = ModManagerSettings::default();
|
||||
|
||||
if let Some(window) = self.window.get() {
|
||||
let window = window.upgrade().unwrap();
|
||||
window.present();
|
||||
return;
|
||||
}
|
||||
let games = settings.games();
|
||||
println!("Games: {:?}", games);
|
||||
|
||||
let window = ExampleApplicationWindow::new(&app);
|
||||
self.window
|
||||
.set(window.downgrade())
|
||||
.expect("Window already set.");
|
||||
// TODO: Figure our if show welcome or games_and_mods.
|
||||
let welcome = Welcome::new();
|
||||
let window = ModManagerWindowMain::new(&*application, &welcome.upcast());
|
||||
window.upcast()
|
||||
};
|
||||
|
||||
app.main_window().present();
|
||||
// Ask the window manager/compositor to present the window
|
||||
window.present();
|
||||
}
|
||||
|
||||
fn startup(&self) {
|
||||
|
@ -57,47 +87,35 @@ mod imp {
|
|||
|
||||
app.setup_css();
|
||||
app.setup_gactions();
|
||||
app.setup_accels();
|
||||
}
|
||||
}
|
||||
|
||||
impl GtkApplicationImpl for ExampleApplication {}
|
||||
impl GtkApplicationImpl for ModManagerApplication {}
|
||||
impl AdwApplicationImpl for ModManagerApplication {}
|
||||
}
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct ExampleApplication(ObjectSubclass<imp::ExampleApplication>)
|
||||
@extends gio::Application, gtk::Application,
|
||||
@implements gio::ActionMap, gio::ActionGroup;
|
||||
pub struct ModManagerApplication(ObjectSubclass<imp::ModManagerApplication>)
|
||||
@extends gio::Application, gtk::Application, adw::Application,
|
||||
@implements gio::ActionGroup, gio::ActionMap;
|
||||
}
|
||||
|
||||
impl ExampleApplication {
|
||||
fn main_window(&self) -> ExampleApplicationWindow {
|
||||
self.imp().window.get().unwrap().upgrade().unwrap()
|
||||
impl ModManagerApplication {
|
||||
pub fn new(flags: &gio::ApplicationFlags) -> Self {
|
||||
glib::Object::builder()
|
||||
.property("application-id", APP_ID)
|
||||
.property("flags", flags)
|
||||
.build()
|
||||
}
|
||||
|
||||
fn setup_gactions(&self) {
|
||||
// Quit
|
||||
let action_quit = gio::ActionEntry::builder("quit")
|
||||
.activate(move |app: &Self, _, _| {
|
||||
// This is needed to trigger the delete event and saving the window state
|
||||
app.main_window().close();
|
||||
app.quit();
|
||||
})
|
||||
let quit_action = gio::ActionEntry::builder("quit")
|
||||
.activate(move |app: &Self, _, _| app.quit())
|
||||
.build();
|
||||
|
||||
// About
|
||||
let action_about = gio::ActionEntry::builder("about")
|
||||
.activate(|app: &Self, _, _| {
|
||||
app.show_about_dialog();
|
||||
})
|
||||
let about_action = gio::ActionEntry::builder("about")
|
||||
.activate(move |app: &Self, _, _| app.show_about())
|
||||
.build();
|
||||
self.add_action_entries([action_quit, action_about]);
|
||||
}
|
||||
|
||||
// Sets up keyboard shortcuts
|
||||
fn setup_accels(&self) {
|
||||
self.set_accels_for_action("app.quit", &["<Control>q"]);
|
||||
self.set_accels_for_action("window.close", &["<Control>w"]);
|
||||
self.add_action_entries([quit_action, about_action]);
|
||||
}
|
||||
|
||||
fn setup_css(&self) {
|
||||
|
@ -112,38 +130,18 @@ impl ExampleApplication {
|
|||
}
|
||||
}
|
||||
|
||||
fn show_about_dialog(&self) {
|
||||
let dialog = gtk::AboutDialog::builder()
|
||||
.logo_icon_name(APP_ID)
|
||||
// Insert your license of choice here
|
||||
// .license_type(gtk::License::MitX11)
|
||||
// Insert your website here
|
||||
// .website("https://gitlab.gnome.org/bilelmoussaoui/mod-manager/")
|
||||
fn show_about(&self) {
|
||||
let window = self.active_window().unwrap();
|
||||
let about = adw::AboutWindow::builder()
|
||||
.transient_for(&window)
|
||||
.application_name("mod-manager")
|
||||
.application_icon(APP_ID)
|
||||
.developer_name("Tine Jozelj")
|
||||
.version(VERSION)
|
||||
.transient_for(&self.main_window())
|
||||
.translator_credits(gettext("translator-credits"))
|
||||
.modal(true)
|
||||
.authors(vec!["Tine Jozelj"])
|
||||
.artists(vec!["Tine Jozelj"])
|
||||
.developers(vec!["Tine Jozelj <tine@tjo.space>"])
|
||||
.copyright("© 2023 Tine Jozelj and other developers")
|
||||
.build();
|
||||
|
||||
dialog.present();
|
||||
}
|
||||
|
||||
pub fn run(&self) -> glib::ExitCode {
|
||||
info!("Mod Manager ({})", APP_ID);
|
||||
info!("Version: {} ({})", VERSION, PROFILE);
|
||||
info!("Datadir: {}", PKGDATADIR);
|
||||
|
||||
ApplicationExtManual::run(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ExampleApplication {
|
||||
fn default() -> Self {
|
||||
glib::Object::builder()
|
||||
.property("application-id", APP_ID)
|
||||
.property("resource-base-path", "/dev/mnts/ModManager/")
|
||||
.build()
|
||||
about.present();
|
||||
}
|
||||
}
|
||||
|
|
2
src/components/mod.rs
Normal file
2
src/components/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
|||
pub mod mods_list;
|
||||
pub use mods_list::*;
|
64
src/components/mods_list.rs
Normal file
64
src/components/mods_list.rs
Normal file
|
@ -0,0 +1,64 @@
|
|||
/* welcome.rs
|
||||
*
|
||||
* Copyright 2023 Tine
|
||||
*
|
||||
* 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-or-later
|
||||
*/
|
||||
|
||||
use adw::subclass::prelude::*;
|
||||
use gtk::{gio, glib};
|
||||
use gtk::{glib::clone, prelude::*};
|
||||
|
||||
mod imp {
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Default, gtk::CompositeTemplate)]
|
||||
#[template(resource = "/dev/mnts/ModManager/ui/components/mods_list.ui")]
|
||||
pub struct ModsList {}
|
||||
|
||||
#[glib::object_subclass]
|
||||
impl ObjectSubclass for ModsList {
|
||||
const NAME: &'static str = "ModsList";
|
||||
type Type = super::ModsList;
|
||||
type ParentType = adw::NavigationPage;
|
||||
|
||||
fn class_init(klass: &mut Self::Class) {
|
||||
klass.bind_template();
|
||||
}
|
||||
|
||||
fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
|
||||
obj.init_template();
|
||||
}
|
||||
}
|
||||
|
||||
impl ObjectImpl for ModsList {
|
||||
fn constructed(&self) {}
|
||||
}
|
||||
impl WidgetImpl for ModsList {}
|
||||
impl NavigationPageImpl for ModsList {}
|
||||
}
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct ModsList(ObjectSubclass<imp::ModsList>)
|
||||
@extends gtk::Widget, gtk::Buildable, adw::NavigationPage,
|
||||
@implements gio::ActionGroup, gio::ActionMap;
|
||||
}
|
||||
|
||||
impl ModsList {
|
||||
pub fn new() -> Self {
|
||||
glib::Object::builder().build()
|
||||
}
|
||||
}
|
9
src/config.rs
Normal file
9
src/config.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
pub const APP_ID: &str = "dev.mnts.ModManager.Devel";
|
||||
pub const GETTEXT_PACKAGE: &str = "mod-manager";
|
||||
pub const LOCALEDIR: &str = "/app/share/locale";
|
||||
pub const PKGDATADIR: &str = "/app/share/mod-manager";
|
||||
pub const PROFILE: &str = "Devel";
|
||||
pub const RESOURCES_FILE: &str = concat!("/app/share/mod-manager", "/resources.gresource");
|
||||
pub const VERSION: &str = "0.1.0-be1d5b0";
|
||||
|
||||
pub const API_KEY: &str = "$2a$10$AtaQ/fkWxMoVHVhO.6PMoOHQq7ERdSdpmegqJ09.2Mgj5iTQP3r.2";
|
|
@ -5,3 +5,5 @@ pub const PKGDATADIR: &str = @PKGDATADIR@;
|
|||
pub const PROFILE: &str = @PROFILE@;
|
||||
pub const RESOURCES_FILE: &str = concat!(@PKGDATADIR@, "/resources.gresource");
|
||||
pub const VERSION: &str = @VERSION@;
|
||||
|
||||
pub const API_KEY: &str = @API_KEY@;
|
61
src/main.rs
61
src/main.rs
|
@ -1,32 +1,53 @@
|
|||
mod config {
|
||||
#![allow(dead_code)]
|
||||
/*
|
||||
Copyright (c) 2023 Tine Jozelj
|
||||
|
||||
include!(concat!(env!("CODEGEN_BUILD_DIR"), "/config.rs"));
|
||||
}
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
mod api;
|
||||
mod application;
|
||||
mod window;
|
||||
mod components;
|
||||
mod config;
|
||||
mod settings;
|
||||
mod windows;
|
||||
|
||||
use gettextrs::{gettext, LocaleCategory};
|
||||
use self::application::ModManagerApplication;
|
||||
|
||||
use config::{GETTEXT_PACKAGE, LOCALEDIR, RESOURCES_FILE};
|
||||
use gettextrs::{bind_textdomain_codeset, bindtextdomain, textdomain};
|
||||
use gtk::prelude::*;
|
||||
use gtk::{gio, glib};
|
||||
|
||||
use self::application::ExampleApplication;
|
||||
use self::config::{GETTEXT_PACKAGE, LOCALEDIR, RESOURCES_FILE};
|
||||
|
||||
fn main() -> glib::ExitCode {
|
||||
// Initialize logger
|
||||
tracing_subscriber::fmt::init();
|
||||
// Set up gettext translations
|
||||
bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR).expect("Unable to bind the text domain");
|
||||
bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8")
|
||||
.expect("Unable to set the text domain encoding");
|
||||
textdomain(GETTEXT_PACKAGE).expect("Unable to switch to the text domain");
|
||||
|
||||
// Prepare i18n
|
||||
gettextrs::setlocale(LocaleCategory::LcAll, "");
|
||||
gettextrs::bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR).expect("Unable to bind the text domain");
|
||||
gettextrs::textdomain(GETTEXT_PACKAGE).expect("Unable to switch to the text domain");
|
||||
// Load resources
|
||||
let resources = gio::Resource::load(RESOURCES_FILE).expect("Could not load resources");
|
||||
gio::resources_register(&resources);
|
||||
|
||||
glib::set_application_name(&gettext("Mod Manager"));
|
||||
// Create a new GtkApplication. The application manages our main loop,
|
||||
// application windows, integration with the window manager/compositor, and
|
||||
// desktop features such as file opening and single-instance applications.
|
||||
let app = ModManagerApplication::new(&gio::ApplicationFlags::empty());
|
||||
|
||||
let res = gio::Resource::load(RESOURCES_FILE).expect("Could not load gresource file");
|
||||
gio::resources_register(&res);
|
||||
|
||||
let app = ExampleApplication::default();
|
||||
// Run the application. This function will block until the application
|
||||
// exits. Upon return, we have our exit code to return to the shell. (This
|
||||
// is the code you see when you do `echo $?` after running a command in a
|
||||
// terminal.
|
||||
app.run()
|
||||
}
|
||||
|
|
|
@ -5,12 +5,21 @@ global_conf.set_quoted('PROFILE', profile)
|
|||
global_conf.set_quoted('VERSION', version + version_suffix)
|
||||
global_conf.set_quoted('GETTEXT_PACKAGE', gettext_package)
|
||||
global_conf.set_quoted('LOCALEDIR', localedir)
|
||||
global_conf.set_quoted('API_KEY', '$2a$10$AtaQ/fkWxMoVHVhO.6PMoOHQq7ERdSdpmegqJ09.2Mgj5iTQP3r.2')
|
||||
config = configure_file(
|
||||
input: 'config.rs.in',
|
||||
output: 'config.rs',
|
||||
configuration: global_conf
|
||||
)
|
||||
|
||||
# Copy the config.rs output to the source directory.
|
||||
run_command(
|
||||
'cp',
|
||||
meson.project_build_root() / 'src' / 'config.rs',
|
||||
meson.project_source_root() / 'src' / 'config.rs',
|
||||
check: true
|
||||
)
|
||||
|
||||
cargo_options = [ '--manifest-path', meson.project_source_root() / 'Cargo.toml' ]
|
||||
cargo_options += [ '--target-dir', meson.project_build_root() / 'src' ]
|
||||
|
||||
|
|
5
src/mod.rs
Normal file
5
src/mod.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
mod base;
|
||||
pub use base::*;
|
||||
|
||||
pub mod games;
|
||||
pub use games::*;
|
66
src/mods_list.rs
Normal file
66
src/mods_list.rs
Normal file
|
@ -0,0 +1,66 @@
|
|||
/* welcome.rs
|
||||
*
|
||||
* Copyright 2023 Tine
|
||||
*
|
||||
* 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-or-later
|
||||
*/
|
||||
|
||||
use adw::subclass::prelude::*;
|
||||
use gtk::{gio, glib};
|
||||
use gtk::{glib::clone, prelude::*};
|
||||
|
||||
mod imp {
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Default, gtk::CompositeTemplate)]
|
||||
#[template(resource = "/dev/mnts/ModManager/components/mods_list.ui")]
|
||||
pub struct ModsList {
|
||||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
impl ObjectSubclass for ModsList {
|
||||
const NAME: &'static str = "ModsList";
|
||||
type Type = super::ModsList;
|
||||
type ParentType = adw::NavigationPage;
|
||||
|
||||
fn class_init(klass: &mut Self::Class) {
|
||||
klass.bind_template();
|
||||
}
|
||||
|
||||
fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
|
||||
obj.init_template();
|
||||
}
|
||||
}
|
||||
|
||||
impl ObjectImpl for ModsList {
|
||||
fn constructed(&self) {
|
||||
}
|
||||
}
|
||||
impl WidgetImpl for ModsList {}
|
||||
impl NavigationPageImpl for ModsList {}
|
||||
}
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct ModsList(ObjectSubclass<imp::ModsList>)
|
||||
@extends gtk::Widget, gtk::Buildable, adw::NavigationPage,
|
||||
@implements gio::ActionGroup, gio::ActionMap;
|
||||
}
|
||||
|
||||
impl ModsList {
|
||||
pub fn new() -> Self {
|
||||
glib::Object::builder().build()
|
||||
}
|
||||
}
|
20
src/settings.rs
Normal file
20
src/settings.rs
Normal file
|
@ -0,0 +1,20 @@
|
|||
use gio::glib;
|
||||
use gsettings_macro::gen_settings;
|
||||
use gtk::gio;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::config::APP_ID;
|
||||
|
||||
#[gen_settings(file = "./data/dev.mnts.ModManager.gschema.xml.in")]
|
||||
#[gen_settings_define(
|
||||
key_name = "games",
|
||||
arg_type = "HashMap<String, String>",
|
||||
ret_type = "HashMap<String, String>"
|
||||
)]
|
||||
pub struct ModManagerSettings;
|
||||
|
||||
impl Default for ModManagerSettings {
|
||||
fn default() -> Self {
|
||||
Self::new(APP_ID)
|
||||
}
|
||||
}
|
117
src/window.rs
117
src/window.rs
|
@ -1,117 +0,0 @@
|
|||
use gtk::prelude::*;
|
||||
use gtk::subclass::prelude::*;
|
||||
use gtk::{gio, glib};
|
||||
|
||||
use crate::application::ExampleApplication;
|
||||
use crate::config::{APP_ID, PROFILE};
|
||||
|
||||
mod imp {
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, gtk::CompositeTemplate)]
|
||||
#[template(resource = "/dev/mnts/ModManager/ui/window.ui")]
|
||||
pub struct ExampleApplicationWindow {
|
||||
#[template_child]
|
||||
pub headerbar: TemplateChild<gtk::HeaderBar>,
|
||||
pub settings: gio::Settings,
|
||||
}
|
||||
|
||||
impl Default for ExampleApplicationWindow {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
headerbar: TemplateChild::default(),
|
||||
settings: gio::Settings::new(APP_ID),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
impl ObjectSubclass for ExampleApplicationWindow {
|
||||
const NAME: &'static str = "ExampleApplicationWindow";
|
||||
type Type = super::ExampleApplicationWindow;
|
||||
type ParentType = gtk::ApplicationWindow;
|
||||
|
||||
fn class_init(klass: &mut Self::Class) {
|
||||
klass.bind_template();
|
||||
}
|
||||
|
||||
// You must call `Widget`'s `init_template()` within `instance_init()`.
|
||||
fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
|
||||
obj.init_template();
|
||||
}
|
||||
}
|
||||
|
||||
impl ObjectImpl for ExampleApplicationWindow {
|
||||
fn constructed(&self) {
|
||||
self.parent_constructed();
|
||||
let obj = self.obj();
|
||||
|
||||
// Devel Profile
|
||||
if PROFILE == "Devel" {
|
||||
obj.add_css_class("devel");
|
||||
}
|
||||
|
||||
// Load latest window state
|
||||
obj.load_window_size();
|
||||
}
|
||||
|
||||
fn dispose(&self) {
|
||||
self.dispose_template();
|
||||
}
|
||||
}
|
||||
|
||||
impl WidgetImpl for ExampleApplicationWindow {}
|
||||
impl WindowImpl for ExampleApplicationWindow {
|
||||
// Save window state on delete event
|
||||
fn close_request(&self) -> glib::Propagation {
|
||||
if let Err(err) = self.obj().save_window_size() {
|
||||
tracing::warn!("Failed to save window state, {}", &err);
|
||||
}
|
||||
|
||||
// Pass close request on to the parent
|
||||
self.parent_close_request()
|
||||
}
|
||||
}
|
||||
|
||||
impl ApplicationWindowImpl for ExampleApplicationWindow {}
|
||||
}
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct ExampleApplicationWindow(ObjectSubclass<imp::ExampleApplicationWindow>)
|
||||
@extends gtk::Widget, gtk::Window, gtk::ApplicationWindow,
|
||||
@implements gio::ActionMap, gio::ActionGroup, gtk::Root;
|
||||
}
|
||||
|
||||
impl ExampleApplicationWindow {
|
||||
pub fn new(app: &ExampleApplication) -> Self {
|
||||
glib::Object::builder().property("application", app).build()
|
||||
}
|
||||
|
||||
fn save_window_size(&self) -> Result<(), glib::BoolError> {
|
||||
let imp = self.imp();
|
||||
|
||||
let (width, height) = self.default_size();
|
||||
|
||||
imp.settings.set_int("window-width", width)?;
|
||||
imp.settings.set_int("window-height", height)?;
|
||||
|
||||
imp.settings
|
||||
.set_boolean("is-maximized", self.is_maximized())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn load_window_size(&self) {
|
||||
let imp = self.imp();
|
||||
|
||||
let width = imp.settings.int("window-width");
|
||||
let height = imp.settings.int("window-height");
|
||||
let is_maximized = imp.settings.boolean("is-maximized");
|
||||
|
||||
self.set_default_size(width, height);
|
||||
|
||||
if is_maximized {
|
||||
self.maximize();
|
||||
}
|
||||
}
|
||||
}
|
96
src/windows/add_new_game/add_new_game.rs
Normal file
96
src/windows/add_new_game/add_new_game.rs
Normal file
|
@ -0,0 +1,96 @@
|
|||
/* welcome.rs
|
||||
*
|
||||
* Copyright 2023 Tine
|
||||
*
|
||||
* 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-or-later
|
||||
*/
|
||||
|
||||
use adw::subclass::prelude::*;
|
||||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use gtk::{gio, glib};
|
||||
|
||||
use crate::api::*;
|
||||
|
||||
mod imp {
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Default, gtk::CompositeTemplate)]
|
||||
#[template(resource = "/dev/mnts/ModManager/ui/windows/add_new_game/add_new_game.ui")]
|
||||
pub struct ModManagerWindowAddNewGame {
|
||||
#[template_child]
|
||||
pub complete_button: TemplateChild<gtk::Button>,
|
||||
|
||||
#[template_child]
|
||||
pub games_dropdown: TemplateChild<gtk::DropDown>,
|
||||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
impl ObjectSubclass for ModManagerWindowAddNewGame {
|
||||
const NAME: &'static str = "ModManagerWindowAddNewGame";
|
||||
type Type = super::ModManagerWindowAddNewGame;
|
||||
type ParentType = adw::ApplicationWindow;
|
||||
|
||||
fn class_init(klass: &mut Self::Class) {
|
||||
klass.bind_template();
|
||||
}
|
||||
|
||||
fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
|
||||
obj.init_template();
|
||||
}
|
||||
}
|
||||
|
||||
impl ObjectImpl for ModManagerWindowAddNewGame {}
|
||||
impl WidgetImpl for ModManagerWindowAddNewGame {}
|
||||
impl WindowImpl for ModManagerWindowAddNewGame {}
|
||||
impl ApplicationWindowImpl for ModManagerWindowAddNewGame {}
|
||||
impl AdwApplicationWindowImpl for ModManagerWindowAddNewGame {}
|
||||
}
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct ModManagerWindowAddNewGame(ObjectSubclass<imp::ModManagerWindowAddNewGame>)
|
||||
@extends gtk::Widget, gtk::Window, gtk::ApplicationWindow, adw::ApplicationWindow,
|
||||
@implements gio::ActionGroup, gio::ActionMap;
|
||||
}
|
||||
|
||||
impl ModManagerWindowAddNewGame {
|
||||
pub fn new() -> Self {
|
||||
glib::Object::builder().build()
|
||||
}
|
||||
|
||||
pub fn setup(&self) {
|
||||
let games = games::get_games();
|
||||
let games_strs: Vec<&str> = games.iter().map(|s| s.as_str()).collect();
|
||||
let games_list = >k::StringList::new(&games_strs);
|
||||
|
||||
let complete_button = &imp::ModManagerWindowAddNewGame::from_obj(self).complete_button;
|
||||
let games_dropdown = &imp::ModManagerWindowAddNewGame::from_obj(self).games_dropdown;
|
||||
|
||||
games_dropdown.set_property("model", games_list);
|
||||
|
||||
let instance = self;
|
||||
|
||||
complete_button.connect_clicked(clone!(@strong instance => move |_| {
|
||||
//let selected_game = games_dropdown.selected_item();
|
||||
|
||||
println!("complete button clicked");
|
||||
|
||||
//if let Some(selected_game) = selected_game {
|
||||
instance.hide()
|
||||
//}
|
||||
}));
|
||||
}
|
||||
}
|
2
src/windows/add_new_game/mod.rs
Normal file
2
src/windows/add_new_game/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
|||
pub mod add_new_game;
|
||||
pub use add_new_game::*;
|
68
src/windows/main/main.rs
Normal file
68
src/windows/main/main.rs
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
Copyright (c) 2023 Tine Jozelj
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use adw::subclass::prelude::*;
|
||||
use gtk::prelude::*;
|
||||
use gtk::{gio, glib};
|
||||
|
||||
mod imp {
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Default, gtk::CompositeTemplate)]
|
||||
#[template(resource = "/dev/mnts/ModManager/ui/windows/main/main.ui")]
|
||||
pub struct ModManagerWindowMain {}
|
||||
|
||||
#[glib::object_subclass]
|
||||
impl ObjectSubclass for ModManagerWindowMain {
|
||||
const NAME: &'static str = "ModManagerWindowMain";
|
||||
type Type = super::ModManagerWindowMain;
|
||||
type ParentType = adw::ApplicationWindow;
|
||||
|
||||
fn class_init(klass: &mut Self::Class) {
|
||||
klass.bind_template();
|
||||
}
|
||||
|
||||
fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
|
||||
obj.init_template();
|
||||
}
|
||||
}
|
||||
|
||||
impl ObjectImpl for ModManagerWindowMain {
|
||||
fn constructed(&self) {
|
||||
self.parent_constructed();
|
||||
}
|
||||
}
|
||||
impl WidgetImpl for ModManagerWindowMain {}
|
||||
impl WindowImpl for ModManagerWindowMain {}
|
||||
impl ApplicationWindowImpl for ModManagerWindowMain {}
|
||||
impl AdwApplicationWindowImpl for ModManagerWindowMain {}
|
||||
}
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct ModManagerWindowMain(ObjectSubclass<imp::ModManagerWindowMain>)
|
||||
@extends gtk::Widget, gtk::Window, gtk::ApplicationWindow, adw::ApplicationWindow,
|
||||
@implements gio::ActionGroup, gio::ActionMap;
|
||||
}
|
||||
|
||||
impl ModManagerWindowMain {
|
||||
pub fn new<P: glib::IsA<gtk::Application>>(application: &P, content: >k::Widget) -> Self {
|
||||
glib::Object::builder()
|
||||
.property("application", application)
|
||||
.property("content", content)
|
||||
.build()
|
||||
}
|
||||
}
|
5
src/windows/main/mod.rs
Normal file
5
src/windows/main/mod.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
pub mod main;
|
||||
pub use main::*;
|
||||
|
||||
pub mod pages;
|
||||
pub use pages::*;
|
60
src/windows/main/pages/games_and_mods.rs
Normal file
60
src/windows/main/pages/games_and_mods.rs
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
Copyright (c) 2023 Tine Jozelj
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use adw::subclass::prelude::*;
|
||||
use gtk::prelude::*;
|
||||
use gtk::{gio, glib};
|
||||
|
||||
mod imp {
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Default, gtk::CompositeTemplate)]
|
||||
#[template(resource = "/dev/mnts/ModManager/ui/windows/main/pages/games_and_mods.ui")]
|
||||
pub struct GamesAndMods {}
|
||||
|
||||
#[glib::object_subclass]
|
||||
impl ObjectSubclass for GamesAndMods {
|
||||
const NAME: &'static str = "GamesAndMods";
|
||||
type Type = super::GamesAndMods;
|
||||
type ParentType = adw::Bin;
|
||||
|
||||
fn class_init(klass: &mut Self::Class) {
|
||||
klass.bind_template();
|
||||
}
|
||||
|
||||
fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
|
||||
obj.init_template();
|
||||
}
|
||||
}
|
||||
|
||||
impl ObjectImpl for GamesAndMods {}
|
||||
impl WidgetImpl for GamesAndMods {}
|
||||
impl BinImpl for GamesAndMods {}
|
||||
}
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct GamesAndMods(ObjectSubclass<imp::GamesAndMods>)
|
||||
@extends gtk::Widget, adw::NavigationSplitView,
|
||||
@implements gio::ActionGroup, gio::ActionMap;
|
||||
}
|
||||
|
||||
impl GamesAndMods {
|
||||
pub fn new() -> Self {
|
||||
glib::Object::builder().build()
|
||||
}
|
||||
}
|
5
src/windows/main/pages/mod.rs
Normal file
5
src/windows/main/pages/mod.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
pub mod games_and_mods;
|
||||
pub use games_and_mods::*;
|
||||
|
||||
pub mod welcome;
|
||||
pub use welcome::*;
|
76
src/windows/main/pages/welcome.rs
Normal file
76
src/windows/main/pages/welcome.rs
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
Copyright (c) 2023 Tine Jozelj
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use adw::subclass::prelude::*;
|
||||
use gtk::prelude::*;
|
||||
use gtk::{gio, glib};
|
||||
|
||||
use crate::windows::ModManagerWindowAddNewGame;
|
||||
|
||||
mod imp {
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Default, gtk::CompositeTemplate)]
|
||||
#[template(resource = "/dev/mnts/ModManager/ui/windows/main/pages/welcome.ui")]
|
||||
pub struct Welcome {
|
||||
#[template_child]
|
||||
pub add_new_game: gtk::TemplateChild<gtk::Button>,
|
||||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
impl ObjectSubclass for Welcome {
|
||||
const NAME: &'static str = "Welcome";
|
||||
type Type = super::Welcome;
|
||||
type ParentType = adw::Bin;
|
||||
|
||||
fn class_init(klass: &mut Self::Class) {
|
||||
klass.bind_template();
|
||||
}
|
||||
|
||||
fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
|
||||
obj.init_template();
|
||||
}
|
||||
}
|
||||
|
||||
impl ObjectImpl for Welcome {
|
||||
fn constructed(&self) {
|
||||
self.parent_constructed();
|
||||
|
||||
self.add_new_game.connect_clicked(|_| {
|
||||
let welcome = ModManagerWindowAddNewGame::new();
|
||||
welcome.setup();
|
||||
welcome.set_modal(true);
|
||||
welcome.present();
|
||||
});
|
||||
}
|
||||
}
|
||||
impl WidgetImpl for Welcome {}
|
||||
impl BinImpl for Welcome {}
|
||||
}
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct Welcome(ObjectSubclass<imp::Welcome>)
|
||||
@extends gtk::Widget, adw::ToolbarView,
|
||||
@implements gio::ActionGroup, gio::ActionMap;
|
||||
}
|
||||
|
||||
impl Welcome {
|
||||
pub fn new() -> Self {
|
||||
glib::Object::builder().build()
|
||||
}
|
||||
}
|
5
src/windows/mod.rs
Normal file
5
src/windows/mod.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
pub mod main;
|
||||
pub use main::*;
|
||||
|
||||
pub mod add_new_game;
|
||||
pub use add_new_game::*;
|
Loading…
Reference in a new issue