Skip to content

Commit

Permalink
Per-project UI persistence (Astrabit-ST#96)
Browse files Browse the repository at this point in the history
* feat: add random `persistence_id` field to project config

* feat: some scrollbars now have project-specific IDs

* feat: persist map editor position and scale
  • Loading branch information
white-axe authored Jan 26, 2024
1 parent 41205d6 commit fa6240f
Show file tree
Hide file tree
Showing 8 changed files with 118 additions and 24 deletions.
45 changes: 40 additions & 5 deletions crates/components/src/map_view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ pub struct MapView {
/// Used to store the bounding boxes of event graphics in order to render them on top of the
/// fog and collision layers
pub event_rects: Vec<egui::Rect>,

pub data_id: egui::Id,
}

#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Default)]
Expand Down Expand Up @@ -121,19 +123,35 @@ impl MapView {
&passages,
)?;

let data_id = egui::Id::new("luminol_map_view")
.with(
update_state
.project_config
.as_ref()
.expect("project not loaded")
.project
.persistence_id,
)
.with(map_id);
let (cursor_pos, pan, inter_tile_pan, scale) = update_state.ctx.data_mut(|d| {
*d.get_persisted_mut_or_insert_with(data_id, || {
(egui::Pos2::ZERO, egui::Vec2::ZERO, egui::Vec2::ZERO, 100.)
})
});

Ok(Self {
visible_display: false,
move_preview: false,

pan: egui::Vec2::ZERO,
inter_tile_pan: egui::Vec2::ZERO,
pan,
inter_tile_pan,

events,
map,

selected_layer: SelectedLayer::default(),
selected_event_id: None,
cursor_pos: egui::Pos2::ZERO,
cursor_pos,
event_enabled: true,
snap_to_grid: false,

Expand All @@ -143,10 +161,12 @@ impl MapView {

selected_event_is_hovered: false,

scale: 100.,
previous_scale: 100.,
scale,
previous_scale: scale,

event_rects: Vec::new(),

data_id,
})
}

Expand Down Expand Up @@ -176,6 +196,14 @@ impl MapView {
let clip_offset = (max_clip - min_clip) / 2.;
let canvas_rect = ui.ctx().screen_rect().intersect(canvas_rect);

self.cursor_pos = self.cursor_pos.clamp(
egui::Pos2::ZERO,
egui::pos2(
map.data.xsize().saturating_sub(1) as f32,
map.data.ysize().saturating_sub(1) as f32,
),
);

// If the user changed the scale using the scale slider, pan the map so that the scale uses
// the center of the visible part of the map as the scale center
if self.scale != self.previous_scale {
Expand Down Expand Up @@ -621,6 +649,13 @@ impl MapView {
egui::Stroke::new(1., egui::Color32::YELLOW),
);

ui.ctx().data_mut(|d| {
d.insert_persisted(
self.data_id,
(self.cursor_pos, self.pan, self.inter_tile_pan, self.scale),
);
});

response
}
}
10 changes: 9 additions & 1 deletion crates/components/src/sound_tab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,15 @@ impl SoundTab {
// Group together so it looks nicer.
ui.group(|ui| {
egui::ScrollArea::both()
.id_source(self.source)
.id_source((
update_state
.project_config
.as_ref()
.expect("project not loaded")
.project
.persistence_id,
self.source,
))
.auto_shrink([false, false])
// Show only visible rows.
.show_rows(
Expand Down
2 changes: 2 additions & 0 deletions crates/config/src/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ pub struct Project {
pub editor_ver: RMVer,
pub playtest_exe: String,
pub prefer_rgssad: bool,
pub persistence_id: u64,
}

impl Default for Project {
Expand All @@ -57,6 +58,7 @@ impl Default for Project {
editor_ver: RMVer::XP,
playtest_exe: "game".to_string(),
prefer_rgssad: false,
persistence_id: 0,
}
}
}
Expand Down
12 changes: 10 additions & 2 deletions crates/filesystem/src/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,17 @@ impl FileSystem {
let project = match self
.read_to_string(".luminol/config")
.ok()
.and_then(|s| ron::from_str(&s).ok())
.and_then(|s| ron::from_str::<luminol_config::project::Project>(&s).ok())
{
Some(c) => c,
Some(config) if config.persistence_id != 0 => config,
Some(mut config) => {
while config.persistence_id == 0 {
config.persistence_id = rand::random();
}
self.write(".luminol/config", ron::to_string(&config).wrap_err(c)?)
.wrap_err(c)?;
config
}
None => {
let Some(editor_ver) = self.detect_rm_ver() else {
return Err(Error::UnableToDetectRMVer).wrap_err(c);
Expand Down
19 changes: 14 additions & 5 deletions crates/ui/src/tabs/map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,11 +291,20 @@ impl luminol_core::Tab for Tab {
.default_width(tilepicker_default_width)
.max_width(tilepicker_default_width)
.show_inside(ui, |ui| {
egui::ScrollArea::both().show_viewport(ui, |ui, rect| {
self.tilepicker
.ui(update_state, ui, rect, self.view.map.coll_enabled);
ui.separator();
});
egui::ScrollArea::both()
.id_source(
update_state
.project_config
.as_ref()
.expect("project not loaded")
.project
.persistence_id,
)
.show_viewport(ui, |ui, rect| {
self.tilepicker
.ui(update_state, ui, rect, self.view.map.coll_enabled);
ui.separator();
});
});

egui::CentralPanel::default().show_inside(ui, |ui| {
Expand Down
9 changes: 8 additions & 1 deletion crates/ui/src/windows/items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ impl luminol_core::Window for Window {
) {
let change_maximum_text = "Change maximum...";

let p = update_state
.project_config
.as_ref()
.expect("project not loaded")
.project
.persistence_id;
let mut items = update_state.data.items();
let animations = update_state.data.animations();
let common_events = update_state.data.common_events();
Expand Down Expand Up @@ -103,6 +109,7 @@ impl luminol_core::Window for Window {
ui.with_cross_justify(|ui| {
ui.label("Items");
egui::ScrollArea::both()
.id_source(p)
.min_scrolled_width(button_width + ui.spacing().item_spacing.x)
.max_height(
ui.available_height()
Expand Down Expand Up @@ -161,7 +168,7 @@ impl luminol_core::Window for Window {

ui.with_left_margin(ui.spacing().window_margin.left, |ui| {
ui.with_cross_justify(|ui| {
egui::ScrollArea::vertical().show(ui, |ui| {
egui::ScrollArea::vertical().id_source(p).show(ui, |ui| {
ui.set_width(ui.available_width());
ui.set_min_width(
2. * (ui.spacing().slider_width + ui.spacing().interact_size.x)
Expand Down
8 changes: 8 additions & 0 deletions crates/ui/src/windows/map_picker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@ impl luminol_core::Window for Window {
.open(&mut window_open)
.show(ctx, |ui| {
egui::ScrollArea::both()
.id_source(
update_state
.project_config
.as_ref()
.expect("project not loaded")
.project
.persistence_id,
)
.auto_shrink([false; 2])
.show(ui, |ui| {
// Aquire the data cache.
Expand Down
37 changes: 27 additions & 10 deletions crates/ui/src/windows/script_edit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,14 @@ impl luminol_core::Window for Window {
.show(ctx, |ui| {
egui::SidePanel::left("script_edit_script_panel").show_inside(ui, |ui| {
egui::ScrollArea::both()
.id_source(
update_state
.project_config
.as_ref()
.expect("project not loaded")
.project
.persistence_id,
)
.auto_shrink([false; 2])
.show(ui, |ui| {
let mut scripts = update_state.data.scripts();
Expand Down Expand Up @@ -185,16 +193,25 @@ impl luminol_core::Tab for ScriptTab {
ui.fonts(|f| f.layout_job(layout_job))
};

egui::ScrollArea::vertical().show(ui, |ui| {
ui.add(
egui::TextEdit::multiline(&mut self.script_text)
.code_editor()
.desired_rows(10)
.lock_focus(true)
.desired_width(f32::INFINITY)
.layouter(&mut layouter),
);
});
egui::ScrollArea::vertical()
.id_source(
update_state
.project_config
.as_ref()
.expect("project not loaded")
.project
.persistence_id,
)
.show(ui, |ui| {
ui.add(
egui::TextEdit::multiline(&mut self.script_text)
.code_editor()
.desired_rows(10)
.lock_focus(true)
.desired_width(f32::INFINITY)
.layouter(&mut layouter),
);
});
}

fn force_close(&mut self) -> bool {
Expand Down

0 comments on commit fa6240f

Please sign in to comment.