Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,568 changes: 1,006 additions & 562 deletions Cargo.lock

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions Trunk.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,13 @@
[build]
target = "crates/maps/index.html"
filehash = true

# Replace __CACHE_VERSION__ in sw.js with the current git short hash,
# so the service worker cache is automatically busted on each new WASM build.
[[hooks]]
stage = "post_build"
command = "sh"
command_arguments = [
"-c",
"sed -i'' -e \"s/__CACHE_VERSION__/$(git rev-parse --short HEAD)/\" dist/sw.js",
]
44 changes: 28 additions & 16 deletions crates/maps/.wasm/sw.js
Original file line number Diff line number Diff line change
@@ -1,38 +1,50 @@
var cacheName = 'maps-pwa';
var cacheName = 'maps-pwa-__CACHE_VERSION__';
var filesToCache = [
'./',
'./index.html',
];

/* Start the service worker and cache all of the app's content */
self.addEventListener('install', function (e) {
self.skipWaiting();
e.waitUntil(
caches.open(cacheName).then(function (cache) {
return cache.addAll(filesToCache);
})
);
});

/* Serve cached content when offline */
/* Delete old caches when a new service worker activates */
self.addEventListener('activate', function (e) {
e.waitUntil(
caches.keys().then(function (cacheNames) {
return Promise.all(
cacheNames.map(function (name) {
if (name !== cacheName) {
return caches.delete(name);
}
})
);
}).then(function () {
return self.clients.claim();
})
);
});

/* Network-first strategy: try network, fall back to cache for offline use */
self.addEventListener('fetch', function (e) {
e.respondWith(
caches.match(e.request).then(function (response) {
if (response) {
fetch(e.request).then(function (response) {
if (!response || response.status !== 200 || response.type !== 'basic') {
return response;
}
// Fetch and cache the response for future use
return fetch(e.request).then(function(response) {
// Check if we received a valid response
if (!response || response.status !== 200 || response.type !== 'basic') {
return response;
}
// Clone the response as it can only be consumed once
var responseToCache = response.clone();
caches.open(cacheName).then(function(cache) {
cache.put(e.request, responseToCache);
});
return response;
var responseToCache = response.clone();
caches.open(cacheName).then(function (cache) {
cache.put(e.request, responseToCache);
});
return response;
}).catch(function () {
return caches.match(e.request);
})
);
});
12 changes: 6 additions & 6 deletions crates/maps/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,18 @@ default = ["kittest_snapshots"]
built = { version = "0.7.5", features = ["git2"] }

[dev-dependencies]
egui_kittest = { version = "0.32.0", features = ["wgpu", "snapshot", "eframe"] }
egui_kittest = { version = "0.34.0", features = ["wgpu", "snapshot", "eframe"] }

# Dependencies of the main app crate.
[dependencies]
maps_io_ros = { workspace = true }
maps_rendering = { workspace = true }
confy = "0.6.1"
eframe = {version = "0.32.1", features = ["wgpu"]}
egui_dnd = "0.13.0"
egui-file-dialog = "0.11.0"
egui_plot = "0.33.0"
egui_tiles = "0.13.0"
eframe = {version = "0.34.0", features = ["wgpu"]}
egui_dnd = "0.15.0"
egui-file-dialog = "0.13.0"
egui_plot = "0.35.0"
egui_tiles = "0.15.0"
image = { workspace = true }
lazy_static = { workspace = true }
log = { workspace = true }
Expand Down
20 changes: 11 additions & 9 deletions crates/maps/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,14 +265,15 @@ impl AppState {
}

impl eframe::App for AppState {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
self.tracing.start();

let mut central_rect = egui::Rect::ZERO;
ui.ctx()
.set_theme(self.options.canvas_settings.theme_preference);

egui::CentralPanel::default().show(ctx, |ui| {
ctx.set_theme(self.options.canvas_settings.theme_preference);
let mut central_rect = egui::Rect::ZERO;

egui::CentralPanel::no_frame().show_inside(ui, |ui| {
self.error_modal(ui);
self.quit_modal(ui);
self.handle_key_shortcuts(ui);
Expand All @@ -284,26 +285,27 @@ impl eframe::App for AppState {
central_rect = self.central_panel(ui);

self.info_window(ui);
self.debug_window(ctx, ui);
self.debug_window(ui);
});

self.handle_new_screenshot(ctx, &central_rect);
self.handle_new_screenshot(ui.ctx(), &central_rect);

#[cfg(target_arch = "wasm32")]
self.consume_wasm_io();

if ctx.input(|i| i.viewport().close_requested())
if ui.ctx().input(|i| i.viewport().close_requested())
&& self.status.unsaved_changes
&& !self.data.maps.is_empty()
{
ctx.send_viewport_cmd(egui::ViewportCommand::CancelClose);
ui.ctx()
.send_viewport_cmd(egui::ViewportCommand::CancelClose);
self.status.quit_modal_active = true;
}

self.tracing.measure();
}

fn on_exit(&mut self, _gl: Option<&eframe::glow::Context>) {
fn on_exit(&mut self) {
if !self.options.persistence.autosave {
return;
}
Expand Down
29 changes: 26 additions & 3 deletions crates/maps/src/app_impl/canvas_settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@ use crate::app_impl::ui_helpers::section_heading;
const MIN_STACK_SCALE: f32 = 1.0;
const MAX_STACK_SCALE: f32 = 10.0;

const DEFAULT_BG_COLOR_LIGHT: egui::Color32 = egui::Color32::from_rgb(240, 240, 240);
const DEFAULT_BG_COLOR_DARK: egui::Color32 = egui::Color32::from_rgb(32, 32, 32);

const fn default_stack_scale_factor() -> f32 {
MIN_STACK_SCALE
}

#[derive(Debug, Serialize, Deserialize)]
pub struct CanvasOptions {
pub background_color: egui::Color32,
pub background_color: Option<egui::Color32>,
#[serde(default)]
pub theme_preference: egui::ThemePreference,
#[serde(skip, default = "default_stack_scale_factor")]
Expand All @@ -23,13 +26,23 @@ pub struct CanvasOptions {
impl Default for CanvasOptions {
fn default() -> Self {
Self {
background_color: egui::Visuals::default().faint_bg_color,
background_color: None,
theme_preference: egui::ThemePreference::default(),
stack_scale_factor: MIN_STACK_SCALE,
}
}
}

impl CanvasOptions {
pub fn background_color_or_default(&self, ctx: &egui::Context) -> egui::Color32 {
self.background_color
.unwrap_or_else(|| match ctx.global_style().visuals.dark_mode {
true => DEFAULT_BG_COLOR_DARK,
false => DEFAULT_BG_COLOR_LIGHT,
})
}
}

impl AppState {
pub(crate) fn canvas_settings(&mut self, ui: &mut egui::Ui) {
section_heading(ui, "Canvas", &mut self.options.collapsed.canvas_settings);
Expand All @@ -48,7 +61,17 @@ impl AppState {
.radio_buttons(ui);
ui.end_row();
ui.label("Background color");
ui.color_edit_button_srgba(&mut self.options.canvas_settings.background_color);
if let Some(color) = &mut self.options.canvas_settings.background_color {
ui.color_edit_button_srgba(color);
} else {
if ui.button("Customize").clicked() {
self.options.canvas_settings.background_color = Some(
self.options
.canvas_settings
.background_color_or_default(ui.ctx()),
);
}
}

if self.options.view_mode == ViewMode::Stacked {
ui.end_row();
Expand Down
16 changes: 13 additions & 3 deletions crates/maps/src/app_impl/central_panel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,11 @@ impl AppState {
.with_texture_crop_threshold(0);
// Always fill the lens window with a background rectangle.
// Ensure that the lens uses the same background color as the main grid canvas.
mini_grid.draw_background(self.options.canvas_settings.background_color);
mini_grid.draw_background(
self.options
.canvas_settings
.background_color_or_default(ui.ctx()),
);
// Only show actual data if the center is set (can be None when hover lens loses focus).
if center_pos.is_some() {
mini_grid.show_maps(ui, &mut self.data.maps, options, &self.data.draw_order);
Expand Down Expand Up @@ -308,8 +312,14 @@ impl AppState {
let mut viewport_rect = egui::Rect::ZERO;

egui::CentralPanel::default()
.frame(egui::Frame::default().fill(self.options.canvas_settings.background_color))
.show(ui.ctx(), |ui| {
.frame(
egui::Frame::default().fill(
self.options
.canvas_settings
.background_color_or_default(ui.ctx()),
),
)
.show_inside(ui, |ui| {
viewport_rect = ui.clip_rect();

if self.data.maps.is_empty() {
Expand Down
3 changes: 2 additions & 1 deletion crates/maps/src/app_impl/debug_window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ use eframe::egui;
use crate::app::AppState;

impl AppState {
pub(crate) fn debug_window(&mut self, ctx: &egui::Context, ui: &mut egui::Ui) {
pub(crate) fn debug_window(&mut self, ui: &mut egui::Ui) {
if !self.status.debug_window_active {
return;
}
egui::Window::new("Debug")
.open(&mut self.status.debug_window_active)
.frame(egui::Frame::canvas(ui.style()).multiply_with_opacity(0.75))
.show(ui.ctx(), |ui| {
let ctx = ui.ctx().clone();
egui::ScrollArea::both().show(ui, |ui| {
ui.collapsing("Settings", |ui| {
ctx.settings_ui(ui);
Expand Down
6 changes: 3 additions & 3 deletions crates/maps/src/app_impl/file_dialog_builder.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
//! Simple builders for creating file dialogs with some defaults used by this crate.

use std::{env::current_dir, path::PathBuf, sync::Arc};
use std::{env::current_dir, path::Path, path::PathBuf};

use eframe::egui;
use egui_file_dialog::FileDialog;
use egui_file_dialog::{FileDialog, Filter};

/// Creates a file dialog for YAML files.
pub fn yaml(initial_dir: Option<&PathBuf>) -> FileDialog {
Expand Down Expand Up @@ -49,7 +49,7 @@ impl FileDialogBuilder {
.dialog
.add_file_filter(
name,
Arc::new(move |path| {
Filter::new(move |path: &Path| {
suffixes_vec.iter().any(|suffix| {
path.extension()
.unwrap_or_default()
Expand Down
19 changes: 8 additions & 11 deletions crates/maps/src/app_impl/footer_panel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,16 +87,13 @@ impl AppState {
}

pub(crate) fn footer_panel(&mut self, ui: &mut egui::Ui) {
egui::TopBottomPanel::new(egui::containers::panel::TopBottomSide::Bottom, "footer").show(
ui.ctx(),
|ui| {
ui.horizontal(|ui| {
// Hide non-essential things if the available width is too narrow.
let narrow = ui.available_width() < 750.;
self.footer_left(ui, narrow);
self.footer_right(ui, narrow);
});
},
);
egui::Panel::bottom("footer").show_inside(ui, |ui| {
ui.horizontal(|ui| {
// Hide non-essential things if the available width is too narrow.
let narrow = ui.available_width() < 750.;
self.footer_left(ui, narrow);
self.footer_right(ui, narrow);
});
});
}
}
41 changes: 21 additions & 20 deletions crates/maps/src/app_impl/header_panel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,31 +67,32 @@ impl AppState {

let fullscreen = ui.ctx().input(|i| i.viewport().fullscreen.unwrap_or(false));

egui::TopBottomPanel::new(egui::containers::panel::TopBottomSide::Top, "header").show(
ui.ctx(),
|ui| {
ui.horizontal(|ui| {
ui.with_layout(egui::Layout::left_to_right(egui::Align::TOP), |ui| {
if !fullscreen && self.options.custom_titlebar() {
ui.add_space(HEADER_PANEL_INDENT);
}
add_toggle_button(ui, "☰", "Show Menu", &mut self.options.menu_visible);
ui.add_space(ICON_SIZE);
egui::Panel::top("header").show_inside(ui, |ui| {
ui.horizontal(|ui| {
ui.with_layout(egui::Layout::left_to_right(egui::Align::TOP), |ui| {
if !fullscreen && self.options.custom_titlebar() {
ui.add_space(HEADER_PANEL_INDENT);
}
add_toggle_button(ui, "☰", "Show Menu", &mut self.options.menu_visible);
ui.add_space(ICON_SIZE);
ui.add_enabled_ui(!self.data.maps.is_empty(), |ui| {
self.tool_buttons(ui);
});
});

ui.with_layout(egui::Layout::right_to_left(egui::Align::TOP), |ui| {
add_toggle_button(
ui,
"⚙",
"Show app options.",
&mut self.options.settings_visible,
);
ui.add_space(ICON_SIZE);
ui.with_layout(egui::Layout::right_to_left(egui::Align::TOP), |ui| {
add_toggle_button(
ui,
"⚙",
"Show app options.",
&mut self.options.settings_visible,
);
ui.add_space(ICON_SIZE);
ui.add_enabled_ui(!self.data.maps.is_empty(), |ui| {
self.view_buttons(ui);
});
});
},
);
});
});
}
}
2 changes: 1 addition & 1 deletion crates/maps/src/app_impl/info_window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ impl AppState {
egui::Window::new("Info")
.open(&mut self.options.help_visible)
.pivot(egui::Align2::CENTER_CENTER)
.default_pos(ui.ctx().used_rect().center())
.default_pos(ui.ctx().content_rect().center())
.fixed_size(egui::Vec2::splat(INFO_WINDOW_WIDTH))
.collapsible(false)
.show(ui.ctx(), |ui| {
Expand Down
12 changes: 6 additions & 6 deletions crates/maps/src/app_impl/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ use crate::movable::{DragDirection, Draggable, MovableAmounts, Rotatable};

impl AppState {
fn dialogs_open(&self) -> bool {
self.load_meta_file_dialog.state() == DialogState::Open
|| self.load_map_pose_file_dialog.state() == DialogState::Open
|| self.save_map_pose_file_dialog.state() == DialogState::Open
|| self.load_session_file_dialog.state() == DialogState::Open
|| self.save_session_file_dialog.state() == DialogState::Open
|| self.save_screenshot_dialog.state() == DialogState::Open
*self.load_meta_file_dialog.state() == DialogState::Open
|| *self.load_map_pose_file_dialog.state() == DialogState::Open
|| *self.save_map_pose_file_dialog.state() == DialogState::Open
|| *self.load_session_file_dialog.state() == DialogState::Open
|| *self.save_session_file_dialog.state() == DialogState::Open
|| *self.save_screenshot_dialog.state() == DialogState::Open
|| self.status.quit_modal_active
|| !self.status.error.is_empty()
}
Expand Down
Loading
Loading