Initializes global graphics settings (#1308)

This commit is contained in:
Putta Khunchalee 2025-03-09 18:33:12 +09:00 committed by GitHub
parent 9de6e3237b
commit 45c447737a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 162 additions and 121 deletions

View file

@ -1,4 +1,4 @@
<p align="center"><img alt="Logo" src="logo.png"></p>
<p align="center"><img alt="Logo" src="gui/ui/assets/logo.png"></p>
## About
[![CI](https://github.com/obhq/obliteration/actions/workflows/main.yml/badge.svg)](https://github.com/obhq/obliteration/actions/workflows/main.yml)

View file

@ -10,7 +10,7 @@ fn main() {
.with_style(String::from("fluent-dark"))
.with_library_paths(HashMap::from([("root".into(), root.join("ui"))]));
slint_build::compile_with_config(PathBuf::from_iter(["ui", "main.slint"]), config).unwrap();
slint_build::compile_with_config(PathBuf::from_iter(["ui", "lib.slint"]), config).unwrap();
// Compile resources.rc.
#[cfg(windows)]

View file

@ -60,6 +60,114 @@ struct MainProgram {
}
impl MainProgram {
async fn run_launcher(
graphics: &impl EngineBuilder,
data: &Arc<DataMgr>,
profiles: Vec<Profile>,
) -> Result<Option<(Profile, ExitAction)>, ProgramError> {
// Create window and register callback handlers.
let win = MainWindow::new().map_err(ProgramError::CreateMainWindow)?;
let resolutions = Rc::new(ResolutionModel::default());
let profiles = Rc::new(ProfileModel::new(profiles, resolutions.clone()));
let exit = Rc::new(Cell::new(None));
win.on_settings({
let win = win.as_weak();
move || spawn_handler(&win, |w| MainProgram::settings(w))
});
win.on_report_issue({
let win = win.as_weak();
move || spawn_handler(&win, |w| MainProgram::report_issue(w))
});
win.on_about({
let win = win.as_weak();
move || spawn_handler(&win, |w| MainProgram::about(w))
});
win.on_profile_selected({
let win = win.as_weak();
let profiles = profiles.clone();
move || {
// TODO: Check if previous profile has unsaved data before switch the profile.
let win = win.unwrap();
let row: usize = win.get_selected_profile().try_into().unwrap();
profiles.select(row, &win);
}
});
win.on_save_profile({
let data = data.clone();
let win = win.as_weak();
let profiles = profiles.clone();
move || spawn_handler(&win, |w| save_profile(w, data.clone(), profiles.clone()))
});
win.on_start_vmm({
let win = win.as_weak();
let profiles = profiles.clone();
let exit = exit.clone();
let ty = ExitAction::Run;
move || spawn_handler(&win, |w| start_vmm(w, profiles.clone(), exit.clone(), ty))
});
win.on_start_debug({
let win = win.as_weak();
let profiles = profiles.clone();
let exit = exit.clone();
let ty = ExitAction::Debug;
move || spawn_handler(&win, |w| start_vmm(w, profiles.clone(), exit.clone(), ty))
});
// Set window properties.
let physical_devices = ModelRc::new(VecModel::from_iter(
graphics
.physical_devices()
.iter()
.map(|p| SharedString::from(p.name())),
));
win.set_devices(physical_devices);
win.set_resolutions(resolutions.into());
win.set_profiles(profiles.clone().into());
// Load selected profile.
let row: usize = win.get_selected_profile().try_into().unwrap();
profiles.select(row, &win);
// Run the window.
win.show().map_err(ProgramError::ShowMainWindow)?;
win.set_center().map_err(ProgramError::CenterMainWindow)?;
win.wait().await;
// Extract window states.
let profile = win.get_selected_profile();
drop(win);
// Check how we exit.
let exit = match Rc::into_inner(exit).unwrap().into_inner() {
Some(v) => v,
None => return Ok(None),
};
// Get selected profile.
let mut profiles = Rc::into_inner(profiles).unwrap().into_inner();
let profile = profiles.remove(profile.try_into().unwrap());
Ok(Some((profile, exit)))
}
async fn settings(main: MainWindow) {
// Setup window.
let win = match SettingsWindow::new() {
@ -71,6 +179,12 @@ impl MainProgram {
}
};
#[cfg(target_os = "macos")]
win.set_graphics_debug_layer_name("MTL_DEBUG_LAYER".into());
#[cfg(not(target_os = "macos"))]
win.set_graphics_debug_layer_name("VK_LAYER_KHRONOS_validation".into());
// Run the window.
if let Err(e) = win.show() {
let m = slint::format!("Failed to show settings window: {}.", e.display());
@ -237,7 +351,7 @@ impl App for MainProgram {
// TODO: Select last used profile.
(profiles.pop().unwrap(), Some(v))
} else {
let (profile, exit) = match run_launcher(&graphics, &data, profiles).await? {
let (profile, exit) = match Self::run_launcher(&graphics, &data, profiles).await? {
Some(v) => v,
None => return Ok(()),
};
@ -318,114 +432,6 @@ impl App for MainProgram {
}
}
async fn run_launcher(
graphics: &impl EngineBuilder,
data: &Arc<DataMgr>,
profiles: Vec<Profile>,
) -> Result<Option<(Profile, ExitAction)>, ProgramError> {
// Create window and register callback handlers.
let win = MainWindow::new().map_err(ProgramError::CreateMainWindow)?;
let resolutions = Rc::new(ResolutionModel::default());
let profiles = Rc::new(ProfileModel::new(profiles, resolutions.clone()));
let exit = Rc::new(Cell::new(None));
win.on_settings({
let win = win.as_weak();
move || spawn_handler(&win, |w| MainProgram::settings(w))
});
win.on_report_issue({
let win = win.as_weak();
move || spawn_handler(&win, |w| MainProgram::report_issue(w))
});
win.on_about({
let win = win.as_weak();
move || spawn_handler(&win, |w| MainProgram::about(w))
});
win.on_profile_selected({
let win = win.as_weak();
let profiles = profiles.clone();
move || {
// TODO: Check if previous profile has unsaved data before switch the profile.
let win = win.unwrap();
let row: usize = win.get_selected_profile().try_into().unwrap();
profiles.select(row, &win);
}
});
win.on_save_profile({
let data = data.clone();
let win = win.as_weak();
let profiles = profiles.clone();
move || spawn_handler(&win, |w| save_profile(w, data.clone(), profiles.clone()))
});
win.on_start_vmm({
let win = win.as_weak();
let profiles = profiles.clone();
let exit = exit.clone();
let ty = ExitAction::Run;
move || spawn_handler(&win, |w| start_vmm(w, profiles.clone(), exit.clone(), ty))
});
win.on_start_debug({
let win = win.as_weak();
let profiles = profiles.clone();
let exit = exit.clone();
let ty = ExitAction::Debug;
move || spawn_handler(&win, |w| start_vmm(w, profiles.clone(), exit.clone(), ty))
});
// Set window properties.
let physical_devices = ModelRc::new(VecModel::from_iter(
graphics
.physical_devices()
.iter()
.map(|p| SharedString::from(p.name())),
));
win.set_devices(physical_devices);
win.set_resolutions(resolutions.into());
win.set_profiles(profiles.clone().into());
// Load selected profile.
let row: usize = win.get_selected_profile().try_into().unwrap();
profiles.select(row, &win);
// Run the window.
win.show().map_err(ProgramError::ShowMainWindow)?;
win.set_center().map_err(ProgramError::CenterMainWindow)?;
win.wait().await;
// Extract window states.
let profile = win.get_selected_profile();
drop(win);
// Check how we exit.
let exit = match Rc::into_inner(exit).unwrap().into_inner() {
Some(v) => v,
None => return Ok(None),
};
// Get selected profile.
let mut profiles = Rc::into_inner(profiles).unwrap().into_inner();
let profile = profiles.remove(profile.try_into().unwrap());
Ok(Some((profile, exit)))
}
async fn wait_for_debugger(addr: SocketAddr) -> Result<Option<TcpStream>, ProgramError> {
// Start server.
let server = TcpListener::bind(addr)

View file

@ -3,7 +3,7 @@ import { AboutSlint, VerticalBox, TabWidget } from "std-widgets.slint";
component Obliteration {
VerticalBox {
Image {
source: @image-url("about/logo.png");
source: @image-url("@root/assets/logo.png");
}
Text {

View file

Before

Width:  |  Height:  |  Size: 256 KiB

After

Width:  |  Height:  |  Size: 256 KiB

View file

Before

Width:  |  Height:  |  Size: 200 B

After

Width:  |  Height:  |  Size: 200 B

6
gui/ui/lib.slint Normal file
View file

@ -0,0 +1,6 @@
export { AboutWindow } from "about.slint";
export { WaitForDebugger } from "debug.slint";
export { ErrorWindow } from "error.slint";
export { MainWindow } from "main.slint";
export { SettingsWindow } from "settings.slint";
export { InstallFirmware, SetupWizard } from "setup.slint";

View file

@ -1,13 +1,7 @@
import { VerticalBox, HorizontalBox, Button, ComboBox } from "std-widgets.slint";
import { TabBar, TabContainer } from "@root/widgets/tab.slint";
import { DisplayTab } from "main/display.slint";
import { CpuTab } from "main/cpu.slint";
import { TabBar, TabContainer } from "main/tab.slint";
export { AboutWindow } from "about.slint";
export { WaitForDebugger } from "debug.slint";
export { ErrorWindow } from "error.slint";
export { SettingsWindow } from "settings.slint";
export { InstallFirmware, SetupWizard } from "setup.slint";
export component MainWindow inherits Window {
in property <[string]> devices;
@ -72,7 +66,7 @@ export component MainWindow inherits Window {
tab := TabBar {
tabs: [
{ text: "Display", icon: @image-url("main/monitor.svg") },
{ text: "Display", icon: @image-url("@root/assets/monitor.svg") },
{ text: "CPU", icon: @image-url("main/cpu-64-bit.svg") }
];
}

View file

@ -1,3 +1,27 @@
export component SettingsWindow inherits Window {
import { StandardButton } from "std-widgets.slint";
import { TabBar, TabContainer } from "@root/widgets/tab.slint";
import { GraphicsTab } from "settings/graphics.slint";
export component SettingsWindow inherits Dialog {
in property <string> graphics-debug-layer-name: "VK_LAYER_KHRONOS_validation";
title: "Settings";
TabContainer {
tab := TabBar {
tabs: [{ text: "Graphics", icon: @image-url("@root/assets/monitor.svg") }];
}
if tab.current-page == 0: GraphicsTab {
debug-layer-name: root.graphics-debug-layer-name;
}
}
StandardButton {
kind: ok;
}
StandardButton {
kind: cancel;
}
}

View file

@ -0,0 +1,11 @@
import { CheckBox, VerticalBox } from "std-widgets.slint";
export component GraphicsTab {
in property <string> debug-layer-name;
VerticalBox {
CheckBox {
text: "Enable \{debug-layer-name}";
}
}
}

BIN
logo.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 256 KiB