Skip to main content

hadrone_wasm/
lib.rs

1use hadrone_core::interaction::{InteractionSession, InteractionType};
2use hadrone_core::{
3    CollisionStrategy, CompactionType, FreePlacementCompactor, LayoutEngine, LayoutItem,
4    ResizeHandle, RisingTideCompactor,
5};
6use wasm_bindgen::prelude::*;
7
8#[wasm_bindgen]
9pub struct GridEngineWasm {
10    layout: Vec<LayoutItem>,
11    cols: i32,
12    compaction: CompactionType,
13    session: Option<InteractionSession>,
14}
15
16#[wasm_bindgen]
17impl GridEngineWasm {
18    #[wasm_bindgen(constructor)]
19    pub fn new(cols: i32, compaction_str: &str) -> Self {
20        let compaction = match compaction_str {
21            "FreePlacement" => CompactionType::FreePlacement,
22            _ => CompactionType::Gravity,
23        };
24        Self {
25            layout: Vec::new(),
26            cols,
27            compaction,
28            session: None,
29        }
30    }
31
32    #[wasm_bindgen]
33    pub fn set_layout(&mut self, items: JsValue) -> Result<(), JsValue> {
34        self.layout = serde_wasm_bindgen::from_value(items)?;
35        self.compact();
36        Ok(())
37    }
38
39    #[wasm_bindgen]
40    pub fn get_layout(&self) -> Result<JsValue, JsValue> {
41        serde_wasm_bindgen::to_value(&self.layout).map_err(|e| e.into())
42    }
43
44    fn compact(&mut self) {
45        let compactor: Box<dyn hadrone_core::Compactor> = match self.compaction {
46            CompactionType::Gravity => Box::new(RisingTideCompactor),
47            CompactionType::FreePlacement => Box::new(FreePlacementCompactor),
48        };
49        let engine = LayoutEngine::with_default_collision(compactor, self.cols);
50        engine.compact(&mut self.layout);
51    }
52
53    #[allow(clippy::too_many_arguments)]
54    #[wasm_bindgen]
55    pub fn start_interaction(
56        &mut self,
57        id: &str,
58        interaction_type: &str,
59        handle_str: &str,
60        mouse_x: f32,
61        mouse_y: f32,
62        col_width_px: f32,
63        row_height_px: f32,
64        margin_x: i32,
65        margin_y: i32,
66        padding_x: i32,
67        padding_y: i32,
68    ) {
69        if let Some(item) = self.layout.iter().find(|i| i.id == id) {
70            let i_type = match interaction_type {
71                "Resize" => InteractionType::Resize,
72                _ => InteractionType::Drag,
73            };
74
75            let handle = match handle_str {
76                "East" => ResizeHandle::East,
77                "West" => ResizeHandle::West,
78                "North" => ResizeHandle::North,
79                "South" => ResizeHandle::South,
80                "NorthEast" => ResizeHandle::NorthEast,
81                "NorthWest" => ResizeHandle::NorthWest,
82                "SouthEast" => ResizeHandle::SouthEast,
83                "SouthWest" => ResizeHandle::SouthWest,
84                _ => ResizeHandle::SouthEast,
85            };
86
87            self.session = Some(InteractionSession {
88                id: id.to_string(),
89                interaction_type: i_type,
90                start_mouse: (mouse_x, mouse_y),
91                start_rect: (item.x, item.y, item.w, item.h),
92                handle,
93                col_width_px,
94                row_height_px,
95                margin: (margin_x, margin_y),
96                container_padding: (padding_x, padding_y),
97                compaction: self.compaction,
98                collision: CollisionStrategy::PushDown,
99            });
100        }
101    }
102
103    #[wasm_bindgen]
104    pub fn update_interaction(&mut self, mouse_x: f32, mouse_y: f32) -> Result<JsValue, JsValue> {
105        if let Some(session) = &self.session {
106            let mut virtual_layout = self.layout.clone();
107            session.update((mouse_x, mouse_y), &mut virtual_layout, self.cols);
108
109            // Return updated layout while interacting
110            serde_wasm_bindgen::to_value(&virtual_layout).map_err(|e| e.into())
111        } else {
112            self.get_layout()
113        }
114    }
115
116    #[wasm_bindgen]
117    pub fn end_interaction(&mut self, mouse_x: f32, mouse_y: f32) {
118        if let Some(session) = self.session.take() {
119            session.update((mouse_x, mouse_y), &mut self.layout, self.cols);
120        }
121    }
122}