Persist window positions when possible
This commit is contained in:
parent
c96368da0e
commit
ec1fe6e0d3
|
|
@ -1,6 +1,6 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use egui::{Color32, Vec2};
|
use egui::{Color32, Pos2, Vec2};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{emulator::SimId, persistence::Persistence, window::DisplayMode};
|
use crate::{emulator::SimId, persistence::Persistence, window::DisplayMode};
|
||||||
|
|
@ -75,6 +75,8 @@ pub struct SimConfig {
|
||||||
pub dimensions: Vec2,
|
pub dimensions: Vec2,
|
||||||
#[serde(default = "default_audio_enabled")]
|
#[serde(default = "default_audio_enabled")]
|
||||||
pub audio_enabled: bool,
|
pub audio_enabled: bool,
|
||||||
|
#[serde(default)]
|
||||||
|
pub position: Option<Pos2>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SimConfig {
|
impl SimConfig {
|
||||||
|
|
@ -87,6 +89,7 @@ impl SimConfig {
|
||||||
colors: COLOR_PRESETS[0],
|
colors: COLOR_PRESETS[0],
|
||||||
dimensions: DisplayMode::Anaglyph.proportions() + Vec2::new(0.0, 22.0),
|
dimensions: DisplayMode::Anaglyph.proportions() + Vec2::new(0.0, 22.0),
|
||||||
audio_enabled: true,
|
audio_enabled: true,
|
||||||
|
position: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,11 @@ use crate::{
|
||||||
};
|
};
|
||||||
use anyhow::Context as _;
|
use anyhow::Context as _;
|
||||||
use egui::{
|
use egui::{
|
||||||
Align2, Button, CentralPanel, Color32, Context, Frame, MenuBar, Panel, Ui, Vec2,
|
Align2, Button, CentralPanel, Color32, Context, Frame, MenuBar, Panel, Pos2, Ui, Vec2,
|
||||||
ViewportBuilder, ViewportCommand, ViewportId, ViewportIdMap, Window,
|
ViewportBuilder, ViewportCommand, ViewportId, ViewportIdMap, Window,
|
||||||
};
|
};
|
||||||
use egui_notify::{Anchor, Toast, Toasts};
|
use egui_notify::{Anchor, Toast, Toasts};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use winit::{event::KeyEvent, event_loop::EventLoopProxy};
|
use winit::{event::KeyEvent, event_loop::EventLoopProxy};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
|
@ -50,7 +51,7 @@ pub struct GameWindow {
|
||||||
images: Arc<ImageTextureLoader>,
|
images: Arc<ImageTextureLoader>,
|
||||||
mappings: MappingProvider,
|
mappings: MappingProvider,
|
||||||
children: ViewportIdMap<ChildWindowWrapper>,
|
children: ViewportIdMap<ChildWindowWrapper>,
|
||||||
child_sizes: UiData<ViewportIdMap<Vec2>>,
|
child_states: UiData<ViewportIdMap<ChildState>>,
|
||||||
queued_children: Vec<ChildWindow>,
|
queued_children: Vec<ChildWindow>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -91,7 +92,7 @@ impl GameWindow {
|
||||||
images: images.clone(),
|
images: images.clone(),
|
||||||
mappings: mappings.clone(),
|
mappings: mappings.clone(),
|
||||||
children: ViewportIdMap::default(),
|
children: ViewportIdMap::default(),
|
||||||
child_sizes: UiData::new(),
|
child_states: UiData::new(),
|
||||||
queued_children: vec![],
|
queued_children: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -175,8 +176,9 @@ impl GameWindow {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut viewport = child.initial_viewport();
|
let mut viewport = child.initial_viewport();
|
||||||
if let Some(size) = self.child_sizes.get(&viewport_id) {
|
if let Some(state) = self.child_states.get(&viewport_id) {
|
||||||
viewport.inner_size = Some(*size);
|
viewport.position = Some(state.position);
|
||||||
|
viewport.inner_size = Some(state.size);
|
||||||
}
|
}
|
||||||
self.children.insert(
|
self.children.insert(
|
||||||
viewport_id,
|
viewport_id,
|
||||||
|
|
@ -626,18 +628,27 @@ impl AppWindow for GameWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initial_viewport(&self) -> ViewportBuilder {
|
fn initial_viewport(&self) -> ViewportBuilder {
|
||||||
ViewportBuilder::default()
|
let builder = ViewportBuilder::default()
|
||||||
.with_title("Lemur")
|
.with_title("Lemur")
|
||||||
.with_inner_size(self.config.dimensions)
|
.with_inner_size(self.config.dimensions);
|
||||||
|
if let Some(position) = self.config.position {
|
||||||
|
builder.with_position(position)
|
||||||
|
} else {
|
||||||
|
builder
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show(&mut self, ui: &mut Ui) {
|
fn show(&mut self, ui: &mut Ui) {
|
||||||
self.child_sizes.load(ui);
|
self.child_states.load(ui);
|
||||||
let dimensions = {
|
let dimensions = {
|
||||||
let bounds = ui.content_rect();
|
let bounds = ui.content_rect();
|
||||||
bounds.max - bounds.min
|
bounds.max - bounds.min
|
||||||
};
|
};
|
||||||
self.update_config(|c| c.dimensions = dimensions);
|
let position = ui.input(|i| i.viewport().outer_rect.map(|r| r.min));
|
||||||
|
self.update_config(|c| {
|
||||||
|
c.dimensions = dimensions;
|
||||||
|
c.position = position;
|
||||||
|
});
|
||||||
|
|
||||||
while let Ok(toast) = self.messages.try_recv() {
|
while let Ok(toast) = self.messages.try_recv() {
|
||||||
self.toasts.add(toast);
|
self.toasts.add(toast);
|
||||||
|
|
@ -679,8 +690,15 @@ impl AppWindow for GameWindow {
|
||||||
let app = child.app.clone();
|
let app = child.app.clone();
|
||||||
let viewport_builder = child.updates.take().unwrap_or_default();
|
let viewport_builder = child.updates.take().unwrap_or_default();
|
||||||
let close_requested = child.close_requested.clone();
|
let close_requested = child.close_requested.clone();
|
||||||
let size = ui.input_for(*id, |v| v.viewport_rect().size());
|
if let Some(rect) = ui.input_for(*id, |inp| inp.viewport().outer_rect) {
|
||||||
self.child_sizes.insert(*id, size);
|
self.child_states.insert(
|
||||||
|
*id,
|
||||||
|
ChildState {
|
||||||
|
position: rect.min,
|
||||||
|
size: rect.size(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
ui.show_viewport_deferred(*id, viewport_builder, move |ui, _| {
|
ui.show_viewport_deferred(*id, viewport_builder, move |ui, _| {
|
||||||
app.lock().unwrap().show(ui);
|
app.lock().unwrap().show(ui);
|
||||||
if ui.input(|s| s.viewport().close_requested()) {
|
if ui.input(|s| s.viewport().close_requested()) {
|
||||||
|
|
@ -689,7 +707,7 @@ impl AppWindow for GameWindow {
|
||||||
});
|
});
|
||||||
true
|
true
|
||||||
});
|
});
|
||||||
self.child_sizes.save(ui);
|
self.child_states.save(ui);
|
||||||
ui.request_repaint_after(Duration::from_millis(10));
|
ui.request_repaint_after(Duration::from_millis(10));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -795,3 +813,9 @@ impl ChildWindow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
struct ChildState {
|
||||||
|
position: Pos2,
|
||||||
|
size: Vec2,
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue