Implement stable serialization and restoration for dock layouts, including auto-hidden and floating panels

- Add `persistence.rs` for stable serialization of dock layouts without runtime identifiers.
- Introduce `preview.rs` for geometry handling of dock drop previews.
- Create `sizing.rs` to manage content-aware sizing policies and constraint solving for dock panels.
- Implement `welcome.rs` to provide a welcome surface when no documents are open, featuring New and Open actions.
This commit is contained in:
2026-07-16 22:10:22 +03:00
parent 1240d25011
commit b09795ccff
72 changed files with 11898 additions and 3115 deletions
+31 -13
View File
@@ -3,7 +3,7 @@
//! Compiles only when running `cargo run --example draw_tester`.
use eframe::egui;
use hcie_draw::{draw_line, draw_filled_rect, draw_filled_circle, flood_fill};
use hcie_draw::{draw_filled_circle, draw_filled_rect, draw_line, flood_fill};
use hcie_protocol::Layer;
fn main() -> eframe::Result {
@@ -86,7 +86,8 @@ impl eframe::App for DrawTesterApp {
[self.layer.width as usize, self.layer.height as usize],
&self.layer.pixels,
);
self.texture = Some(ctx.load_texture("canvas_preview", color_image, Default::default()));
self.texture =
Some(ctx.load_texture("canvas_preview", color_image, Default::default()));
}
let texture = self.texture.as_ref().unwrap().clone();
@@ -99,22 +100,29 @@ impl eframe::App for DrawTesterApp {
ui.label("Click & drag to draw on this canvas:");
ui.add_space(5.0);
let image_widget = egui::Image::new((texture.id(), texture.size_vec2())).sense(egui::Sense::click_and_drag());
let image_widget = egui::Image::new((texture.id(), texture.size_vec2()))
.sense(egui::Sense::click_and_drag());
let resp = ui.add(image_widget);
if resp.dragged() || resp.clicked() {
if let Some(hover_pos) = resp.hover_pos() {
let rect = resp.rect;
let px = ((hover_pos.x - rect.min.x) / rect.width() * self.layer.width as f32).clamp(0.0, self.layer.width as f32 - 1.0);
let py = ((hover_pos.y - rect.min.y) / rect.height() * self.layer.height as f32).clamp(0.0, self.layer.height as f32 - 1.0);
let px = ((hover_pos.x - rect.min.x) / rect.width()
* self.layer.width as f32)
.clamp(0.0, self.layer.width as f32 - 1.0);
let py = ((hover_pos.y - rect.min.y) / rect.height()
* self.layer.height as f32)
.clamp(0.0, self.layer.height as f32 - 1.0);
match self.selected_tool {
"Line" => {
if let Some(last_pos) = self.last_drag_pos {
draw_line(
&mut self.layer,
last_pos.x, last_pos.y,
px, py,
last_pos.x,
last_pos.y,
px,
py,
self.current_color,
self.thickness,
None,
@@ -127,7 +135,8 @@ impl eframe::App for DrawTesterApp {
if resp.drag_started() || resp.clicked() {
draw_filled_circle(
&mut self.layer,
px, py,
px,
py,
self.thickness * 2.0,
self.current_color,
None,
@@ -140,8 +149,10 @@ impl eframe::App for DrawTesterApp {
let size = self.thickness * 3.0;
draw_filled_rect(
&mut self.layer,
px - size, py - size,
px + size, py + size,
px - size,
py - size,
px + size,
py + size,
self.current_color,
None,
);
@@ -152,7 +163,8 @@ impl eframe::App for DrawTesterApp {
if resp.clicked() {
flood_fill(
&mut self.layer,
px as u32, py as u32,
px as u32,
py as u32,
self.current_color,
20,
None,
@@ -195,7 +207,10 @@ impl eframe::App for DrawTesterApp {
self.current_color[2] as f32 / 255.0,
self.current_color[3] as f32 / 255.0,
];
if ui.color_edit_button_rgba_unmultiplied(&mut color_f32).changed() {
if ui
.color_edit_button_rgba_unmultiplied(&mut color_f32)
.changed()
{
self.current_color = [
(color_f32[0] * 255.0).round() as u8,
(color_f32[1] * 255.0).round() as u8,
@@ -213,7 +228,10 @@ impl eframe::App for DrawTesterApp {
ui.add_space(35.0);
ui.colored_label(egui::Color32::LIGHT_GREEN, "Layer-based drawing API");
ui.colored_label(egui::Color32::LIGHT_GREEN, "Decoupled from hcie-protocol");
ui.colored_label(egui::Color32::LIGHT_GREEN, "Operating with 100% GUI neutrality");
ui.colored_label(
egui::Color32::LIGHT_GREEN,
"Operating with 100% GUI neutrality",
);
});
});
});