Big commit with lots of stuff

This commit is contained in:
Asriel Camora 2023-04-01 00:56:22 -07:00
parent 630b57566b
commit 9b8ca984f4
19 changed files with 701 additions and 52 deletions

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "app/resources/Sweet"]
path = app/resources/Sweet
url = https://github.com/WorkingRobot/Sweet.git

165
Cargo.lock generated
View file

@ -165,6 +165,12 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "embed-manifest"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40ff574b0b0a794f8995383bb83f21f8f99214422cae791cb48d66da524b00f7"
[[package]]
name = "encoding_rs"
version = "0.8.32"
@ -373,6 +379,34 @@ dependencies = [
"system-deps",
]
[[package]]
name = "gdk4-win32"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a79a5672b4b26ece3fc144c5be6c8d0ef2d84d37fed65002e5b1576fbc3ec00"
dependencies = [
"gdk4",
"gdk4-win32-sys",
"gio",
"glib",
"libc",
"system-deps",
"windows 0.44.0",
]
[[package]]
name = "gdk4-win32-sys"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2c1b84458185383da1d8877f812cccffd83a3cb42959d646e3e9a4ad0bc09ac"
dependencies = [
"gdk-pixbuf-sys",
"gdk4-sys",
"glib-sys",
"libc",
"system-deps",
]
[[package]]
name = "gio"
version = "0.17.4"
@ -763,12 +797,16 @@ dependencies = [
name = "l4"
version = "0.1.0"
dependencies = [
"embed-manifest",
"gdk4-win32",
"glib-build-tools",
"gtk4",
"libadwaita",
"libloading",
"plugins_core",
"walkdir",
"windows 0.47.0",
"winres",
]
[[package]]
@ -1046,7 +1084,7 @@ dependencies = [
"rustc_version",
"semver",
"tokio",
"toml",
"toml 0.7.2",
]
[[package]]
@ -1387,7 +1425,7 @@ dependencies = [
"cfg-expr",
"heck",
"pkg-config",
"toml",
"toml 0.7.2",
"version-compare",
]
@ -1494,6 +1532,15 @@ dependencies = [
"tracing",
]
[[package]]
name = "toml"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
dependencies = [
"serde",
]
[[package]]
name = "toml"
version = "0.7.2"
@ -1749,19 +1796,37 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows"
version = "0.44.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e745dab35a0c4c77aa3ce42d595e13d2003d6902d6b08c9ef5fc326d08da12b"
dependencies = [
"windows-targets 0.42.1",
]
[[package]]
name = "windows"
version = "0.47.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2649ff315bee4c98757f15dac226efe3d81927adbb6e882084bb1ee3e0c330a7"
dependencies = [
"windows-targets 0.47.0",
]
[[package]]
name = "windows-sys"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
"windows_aarch64_gnullvm 0.42.1",
"windows_aarch64_msvc 0.42.1",
"windows_i686_gnu 0.42.1",
"windows_i686_msvc 0.42.1",
"windows_x86_64_gnu 0.42.1",
"windows_x86_64_gnullvm 0.42.1",
"windows_x86_64_msvc 0.42.1",
]
[[package]]
@ -1770,7 +1835,7 @@ version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
dependencies = [
"windows-targets",
"windows-targets 0.42.1",
]
[[package]]
@ -1779,13 +1844,28 @@ version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
"windows_aarch64_gnullvm 0.42.1",
"windows_aarch64_msvc 0.42.1",
"windows_i686_gnu 0.42.1",
"windows_i686_msvc 0.42.1",
"windows_x86_64_gnu 0.42.1",
"windows_x86_64_gnullvm 0.42.1",
"windows_x86_64_msvc 0.42.1",
]
[[package]]
name = "windows-targets"
version = "0.47.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f8996d3f43b4b2d44327cd71b7b0efd1284ab60e6e9d0e8b630e18555d87d3e"
dependencies = [
"windows_aarch64_gnullvm 0.47.0",
"windows_aarch64_msvc 0.47.0",
"windows_i686_gnu 0.47.0",
"windows_i686_msvc 0.47.0",
"windows_x86_64_gnu 0.47.0",
"windows_x86_64_gnullvm 0.47.0",
"windows_x86_64_msvc 0.47.0",
]
[[package]]
@ -1794,42 +1874,84 @@ version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.47.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "831d567d53d4f3cb1db332b68e6e2b6260228eb4d99a777d8b2e8ed794027c90"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
[[package]]
name = "windows_aarch64_msvc"
version = "0.47.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a42d54a417c60ce4f0e31661eed628f0fa5aca73448c093ec4d45fab4c51cdf"
[[package]]
name = "windows_i686_gnu"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
[[package]]
name = "windows_i686_gnu"
version = "0.47.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1925beafdbb22201a53a483db861a5644123157c1c3cee83323a2ed565d71e3"
[[package]]
name = "windows_i686_msvc"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
[[package]]
name = "windows_i686_msvc"
version = "0.47.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a8ef8f2f1711b223947d9b69b596cf5a4e452c930fb58b6fc3fdae7d0ec6b31"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
[[package]]
name = "windows_x86_64_gnu"
version = "0.47.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7acaa0c2cf0d2ef99b61c308a0c3dbae430a51b7345dedec470bd8f53f5a3642"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.47.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5a0628f71be1d11e17ca4a0e9e15b3a5180f6fbf1c2d55e3ba3f850378052c1"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
[[package]]
name = "windows_x86_64_msvc"
version = "0.47.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d6e62c256dc6d40b8c8707df17df8d774e60e39db723675241e7c15e910bce7"
[[package]]
name = "winnow"
version = "0.3.5"
@ -1847,3 +1969,12 @@ checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
dependencies = [
"winapi",
]
[[package]]
name = "winres"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b68db261ef59e9e52806f688020631e987592bd83619edccda9c47d42cde4f6c"
dependencies = [
"toml 0.5.11",
]

View file

@ -3,11 +3,20 @@ name = "l4"
version = "0.1.0"
edition = "2021"
[package.metadata.winres]
OriginalFilename = "L4.exe"
ProductName = "L4"
FileDescription = "Launcher v4 or something"
LegalCopyright = "Copyright © 2023, Asriel Camora"
CompanyName = "WorkingRobot"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
libloading = "0.7.4"
plugins_core = { path = "../plugins/core" }
gdk4-win32 = { version = "0.6.3", features = ["win32"] }
windows = { version = "0.47.0", features = ["Win32_UI_HiDpi", "Win32_Foundation"]}
[dependencies.gtk]
package = "gtk4"
@ -21,3 +30,5 @@ version = "0.3.1"
[build-dependencies]
glib-build-tools = "0.17.0"
walkdir = "2.3.3"
embed-manifest = "1.3.1"
winres = "0.1.12"

View file

@ -1,5 +1,6 @@
use std::process::Command;
use std::{env, path::Path};
use embed_manifest::{embed_manifest, manifest::DpiAwareness, new_manifest};
use std::process::{Command, Stdio};
use std::{env, path::Path, path::PathBuf};
use walkdir::WalkDir;
fn main() {
@ -8,6 +9,41 @@ fn main() {
"resources/resources.gresource.xml",
"L4.gresource",
);
let out_dir = env::var("OUT_DIR").unwrap();
for theme in &[
"Sweet",
"Sweet-Ambar",
"Sweet-Ambar-Blue",
"Sweet-Dark",
"Sweet-Mars",
] {
let mut from_path = PathBuf::new();
from_path.push("resources");
from_path.push("Sweet");
from_path.push(theme);
from_path.set_extension("gresource");
let mut to_path = PathBuf::new();
to_path.push(out_dir.as_str());
to_path.push(theme);
to_path.set_extension("gresource");
std::fs::copy(&from_path, &to_path).unwrap();
println!("cargo:rerun-if-changed={}", &from_path.display());
}
if cfg!(target_os = "windows") {
embed_manifest(
new_manifest("WorkingRobot.L4").dpi_awareness(DpiAwareness::PerMonitorV2Only),
)
.expect("Unable to embed manifest file");
let mut res = winres::WindowsResource::new();
res.set_icon("resources/icon.ico")
.set("InternalName", "L4.EXE");
res.compile().unwrap();
}
println!("cargo:rerun-if-changed=build.rs");
}
fn blueprint_batch_compile<P: AsRef<Path>>(sources: &[P], input_dir: &str, output_dir: &str) {
@ -17,16 +53,19 @@ fn blueprint_batch_compile<P: AsRef<Path>>(sources: &[P], input_dir: &str, outpu
for source in sources {
command.arg(source.as_ref());
println!("cargo:rerun-if-changed={:?}", source.as_ref());
println!("cargo:rerun-if-changed={}", source.as_ref().display());
}
let output = command.output().unwrap();
let output = command
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.output()
.unwrap();
assert!(
output.status.success(),
"blueprint-compiler failed with exit status {} and stderr:\n{}",
output.status,
String::from_utf8_lossy(&output.stderr)
"blueprint-compiler failed with exit status {}",
output.status
)
}

1
app/resources/Sweet Submodule

@ -0,0 +1 @@
Subproject commit ac1568c63953feadc74fa80f20ba9d6639495b95

BIN
app/resources/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

122
app/resources/icon.svg Normal file
View file

@ -0,0 +1,122 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 320 320"
version="1.1"
id="svg4"
sodipodi:docname="egl3.svg"
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
width="320"
height="320"
inkscape:export-filename="J:\Code\Visual Studio 2017\Projects\EGL3\256.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<title
id="title4678">EGL2</title>
<metadata
id="metadata10">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>EGL2</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs8">
<linearGradient
inkscape:collect="always"
id="background">
<stop
id="stop4657"
offset="0"
style="stop-color:#2f2f31;stop-opacity:1" />
<stop
id="stop4655"
offset="1"
style="stop-color:#475467;stop-opacity:1" />
</linearGradient>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : -1678 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="100 : -1678 : 1"
inkscape:persp3d-origin="50 : -1694.6667 : 1"
id="perspective4637" />
<linearGradient
inkscape:collect="always"
xlink:href="#background"
id="linearGradient4661"
x1="100"
y1="100"
x2="0"
y2="0"
gradientUnits="userSpaceOnUse"
spreadMethod="pad"
gradientTransform="matrix(20.48,0,0,20.48,-3412.6101,35.254237)" />
</defs>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2560"
inkscape:window-height="1361"
id="namedview6"
showgrid="false"
inkscape:pagecheckerboard="true"
inkscape:zoom="2.2692308"
inkscape:cx="109.0678"
inkscape:cy="168.11864"
inkscape:window-x="2551"
inkscape:window-y="-9"
inkscape:window-maximized="1"
inkscape:current-layer="svg4"
inkscape:document-rotation="0"
lock-margins="true" />
<circle
r="1024"
cy="1024"
cx="1024"
id="path838"
style="fill:#000000;fill-opacity:0;stroke-width:226.772;stroke-linecap:round;stroke-opacity:0.386139;paint-order:stroke fill markers" />
<rect
style="opacity:1;fill:url(#linearGradient4661);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.0151181;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill"
id="rect4653"
width="2048"
height="2048"
x="-3412.6101"
y="35.254238"
rx="299.93985"
ry="299.93985" />
<path
id="path4615"
style="fill:#3a8fad;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.015118;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill"
d="m 270.06011,208.79788 -145.473,31.62079 -74.647225,16.21374 74.647225,63.3676 145.473,-31.6208 z"
inkscape:connector-curvature="0"
inkscape:export-filename="J:\Code\Visual Studio 2017\Projects\EGL3\slim.png"
inkscape:export-xdpi="768.0166"
inkscape:export-ydpi="768.0166" />
<path
style="fill:#54b5cc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.015118;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill"
d="M 49.940105,-5.0000001e-6 V 256.63243 L 124.58711,320 V -5.0000001e-6 Z"
id="rect4629"
inkscape:connector-curvature="0"
inkscape:export-filename="J:\Code\Visual Studio 2017\Projects\EGL3\tall.png"
inkscape:export-xdpi="767.77362"
inkscape:export-ydpi="767.77362" />
</svg>

After

Width:  |  Height:  |  Size: 4.3 KiB

View file

@ -1,6 +1,83 @@
using Gtk 4.0;
using Adw 1;
Adw.ApplicationWindow window {
menu main-menu {
submenu {
label: _("_Filter");
item {
label: _("_All");
action: "win.filter";
target: "All";
}
item {
label: _("_Open");
action: "win.filter";
target: "Open";
}
item {
label: _("_Done");
action: "win.filter";
target: "Done";
}
}
item {
label: _("_Remove Done Tasks");
action: "win.remove-done-tasks";
}
item {
label: _("_Keyboard Shortcuts");
action: "win.show-help-overlay";
}
}
ApplicationWindow window {
default-width: 650;
default-height: 550;
icon-name: "icon";
titlebar: HeaderBar {
decoration-layout: "icon:minimize,maximize,close";
title-widget: StackSwitcher title {
stack: main-stack;
};
[start]
Label {
label: _("L4");
}
};
Box {
orientation: vertical;
Stack main-stack {
StackPage page-games {
name: "games";
title: _("Games");
child: Adw.StatusPage leaflet2 {
};
}
StackPage {
name: "main";
title: _("maintitle");
child: Adw.StatusPage {
Box {
[start]
DropDown theme_dropdown {
model: StringList {
strings ["Sweet", "Dark", "Mars", "Ambar", "Blue"]
};
}
}
};
}
}
}
}

12
app/resources/main.css Normal file
View file

@ -0,0 +1,12 @@
headerbar entry,
headerbar spinbutton,
headerbar button,
headerbar separator {
margin-top: 0px;
margin-bottom: 0px;
font-weight: bold;
}
headerbar {
min-height: 1.5em;
}

View file

@ -1,6 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/me/workingrobot/l4/">
<file compressed="true" preprocess="xml-stripblanks" alias="gtk/help-overlay.ui">main.ui</file>
<file compressed="true" preprocess="xml-stripblanks">main.ui</file>
<file compressed="true" preprocess="xml-stripblanks">icon.svg</file>
<file compressed="true">main.css</file>
</gresource>
</gresources>

View file

@ -1,35 +1,35 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
mod modules;
mod utils;
mod widgets;
use gtk::prelude::*;
use gtk::{gio, glib};
use window::Window;
use widgets::Application;
static APP_ID: &str = "org.gtk_rs.Todo5";
static APP_ID: &str = "me.workingrobot.l4";
// ANCHOR: main
fn main() -> glib::ExitCode {
gio::resources_register_include!("L4.gresource").expect("Failed to register resources.");
//#[cfg(debug_assertions)]
// Cairo is enabled for faster launch times
//std::env::set_var("GSK_RENDERER", "cairo");
// Create a new application
// 👇 changed
let app = adw::Application::builder().application_id(APP_ID).build();
std::env::set_var("GTK_DEBUG", "interactive");
// Connect to signals
app.connect_startup(setup_shortcuts);
app.connect_activate(build_ui);
gio::resources_register_include!("Sweet.gresource").expect("Failed to register theme");
gio::resources_register_include!("Sweet-Ambar.gresource").expect("Failed to register theme");
gio::resources_register_include!("Sweet-Ambar-Blue.gresource")
.expect("Failed to register theme");
gio::resources_register_include!("Sweet-Dark.gresource").expect("Failed to register theme");
gio::resources_register_include!("Sweet-Mars.gresource").expect("Failed to register theme");
gio::resources_register_include!("L4.gresource").expect("Failed to register app resources");
// Run the application
app.run()
}
// 👇 changed
fn setup_shortcuts(app: &adw::Application) {
app.set_accels_for_action("win.filter('All')", &["<Ctrl>a"]);
app.set_accels_for_action("win.filter('Open')", &["<Ctrl>o"]);
app.set_accels_for_action("win.filter('Done')", &["<Ctrl>d"]);
}
// 👇 changed
fn build_ui(app: &adw::Application) {
// Create a new custom window and show it
let window = Window::new(app);
window.show();
gtk::init().expect("Failed to initialize GTK");
adw::init().expect("Failed to initialize LibAdwaita");
glib::set_application_name("L4");
glib::set_program_name(Some("L4"));
Application::new().with_application_id(APP_ID).run()
}

8
app/src/modules/mod.rs Normal file
View file

@ -0,0 +1,8 @@
mod module;
mod theme_picker;
pub use module::Module;
pub use module::ModuleCtx;
pub use module::ModuleList;
pub use theme_picker::ThemePicker;

54
app/src/modules/module.rs Normal file
View file

@ -0,0 +1,54 @@
use gtk::prelude::*;
use gtk::Builder;
use gtk::{gdk, glib, IconTheme};
use std::cell::RefCell;
use std::rc::Rc;
pub trait ModuleCtx {
fn try_get_object<T: IsA<glib::Object>>(&self, name: &'static str) -> Option<T>;
fn get_object<T: IsA<glib::Object>>(&self, name: &'static str) -> T {
self.try_get_object(name)
.expect(format!("Failed to get object {}", name).as_str())
}
}
pub trait Module {
fn new(ctx: &impl ModuleCtx) -> Rc<RefCell<Self>>
where
Self: Sized;
}
pub struct ModuleList {
builder: Builder,
modules: Vec<Rc<RefCell<dyn Module>>>,
}
impl ModuleCtx for ModuleList {
fn try_get_object<T: IsA<glib::Object>>(&self, name: &'static str) -> Option<T> {
self.builder.object(name)
}
}
impl Default for ModuleList {
fn default() -> Self {
Self::new()
}
}
impl ModuleList {
pub fn new() -> Self {
let display = gdk::Display::default().expect("Could not get a display");
let icon_theme = IconTheme::for_display(&display);
icon_theme.add_resource_path("/me/workingrobot/l4");
Self {
builder: Builder::from_resource("/me/workingrobot/l4/main.ui"),
modules: vec![],
}
}
pub fn add<T: Module + 'static>(&mut self) {
self.modules.push(T::new(self));
}
}

View file

@ -0,0 +1,65 @@
use super::{Module, ModuleCtx};
use gtk::gdk;
use std::cell::RefCell;
use std::rc::Rc;
pub struct ThemePicker {
provider: gtk::CssProvider,
}
impl ThemePicker {
fn set_theme(&self, theme_idx: u32) {
return;
let theme_name = match theme_idx {
0 => "Sweet",
1 => "Sweet-Dark",
2 => "Sweet-Mars",
3 => "Sweet-Ambar",
4 => "Sweet-Ambar-Blue",
_ => todo!(),
};
self.provider.load_from_resource(
format!("/org/gtk/libgtk/theme/{theme_name}/gtk-dark.css").as_str(),
);
}
}
impl Module for ThemePicker {
fn new(ctx: &impl ModuleCtx) -> Rc<RefCell<Self>> {
gtk::Settings::default()
.unwrap()
.set_gtk_theme_name(Some("Sweet-Dark"));
let this = Self {
provider: gtk::CssProvider::new(),
};
let display = gdk::Display::default().expect("Could not get a display");
this.provider.connect_parsing_error(|_, section, error| {
panic!("Could not parse css data ({} at {})", error, section);
});
#[allow(deprecated)]
// add_provider_for_display isn't actually deprecated, but the rest of StyleContext is
gtk::StyleContext::add_provider_for_display(
&display,
&this.provider,
gtk::STYLE_PROVIDER_PRIORITY_THEME,
);
this.set_theme(0);
let this = Rc::new(RefCell::new(this));
let dropdown = ctx.get_object::<gtk::DropDown>("theme_dropdown");
let this_clone = this.clone();
dropdown.connect_selected_notify(move |drop| {
if drop.selected() != gtk::INVALID_LIST_POSITION {
this_clone.borrow().set_theme(drop.selected());
}
});
this
}
}

19
app/src/utils/dpi.rs Normal file
View file

@ -0,0 +1,19 @@
use gdk4_win32::prelude::*;
use gdk4_win32::Win32Surface;
use gtk::{traits::NativeExt, Native};
use windows::Win32::Foundation::HWND;
use windows::Win32::UI::HiDpi::GetDpiForWindow;
pub trait UsesDpi: IsA<Native> {
fn get_dpi(&self) -> Option<u32>;
}
impl<T> UsesDpi for T
where
T: IsA<Native>,
{
fn get_dpi(&self) -> Option<u32> {
let hwnd = HWND(self.surface().downcast_ref::<Win32Surface>()?.handle().0);
unsafe { Some(GetDpiForWindow(hwnd)) }
}
}

1
app/src/utils/mod.rs Normal file
View file

@ -0,0 +1 @@
pub mod dpi;

View file

@ -0,0 +1,73 @@
use crate::modules::{ModuleCtx, ModuleList, ThemePicker};
use crate::utils::dpi::UsesDpi;
use adw::subclass::prelude::*;
use gtk::{gdk, glib, prelude::Cast, traits::GtkWindowExt};
use std::cell::RefCell;
use std::rc::Rc;
#[derive(Default)]
pub struct Application {
modules: Rc<RefCell<ModuleList>>,
}
#[glib::object_subclass]
impl ObjectSubclass for Application {
const NAME: &'static str = "L4Application";
type Type = super::Application;
type ParentType = adw::Application;
}
impl ObjectImpl for Application {}
impl ApplicationImpl for Application {
fn startup(&self) {
self.parent_startup();
let manager = adw::StyleManager::default();
manager.set_color_scheme(adw::ColorScheme::ForceDark);
let display = gdk::Display::default().expect("Could not get a display");
let provider = gtk::CssProvider::new();
provider.connect_parsing_error(|_, section, error| {
panic!("Could not parse css data ({} at {})", error, section);
});
provider.load_from_resource("/me/workingrobot/l4/main.css");
#[allow(deprecated)]
// add_provider_for_display isn't actually deprecated, but the rest of StyleContext is
gtk::StyleContext::add_provider_for_display(
&display,
&provider,
gtk::STYLE_PROVIDER_PRIORITY_APPLICATION,
);
let window = self
.modules
.borrow()
.get_object::<gtk::ApplicationWindow>("window");
window.set_application(Some(self.obj().upcast_ref::<gtk::Application>()));
}
fn activate(&self) {
self.parent_activate();
let window = self
.modules
.borrow()
.get_object::<gtk::ApplicationWindow>("window");
window.minimize();
window.present();
let settings = gtk::Settings::default().expect("Could not get default settings");
settings.set_gtk_xft_dpi(window.get_dpi().unwrap_or(96) as i32 * 1024);
self.modules.borrow_mut().add::<ThemePicker>();
}
}
impl GtkApplicationImpl for Application {}
impl AdwApplicationImpl for Application {}

View file

@ -0,0 +1,28 @@
mod imp;
use glib::Object;
use gtk::{gio, glib};
glib::wrapper! {
pub struct Application(ObjectSubclass<imp::Application>)
@extends adw::Application, gtk::Application, gio::Application,
@implements gio::ActionGroup, gio::ActionMap;
}
impl Application {
pub fn new() -> Self {
Object::builder().build()
}
pub fn with_application_id(&self, application_id: &str) -> Self {
Object::builder()
.property("application-id", application_id)
.build()
}
}
impl Default for Application {
fn default() -> Self {
Self::new()
}
}

3
app/src/widgets/mod.rs Normal file
View file

@ -0,0 +1,3 @@
mod application;
pub use application::Application;