-
Notifications
You must be signed in to change notification settings - Fork 0
/
util.rs
275 lines (260 loc) · 9.94 KB
/
util.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
#![feature(core_intrinsics)]
use std::char::from_u32;
use std::collections::HashMap;
use std::num::NonZeroU32;
use std::ops::Deref;
use std::option::Option;
use stdweb::unstable::TryFrom;
use stdweb::web::{document, HtmlElement, IHtmlElement, INonElementParentNode};
use stdweb::Value;
use crate::coordinate::{Col, Coordinate, Row};
use crate::grammar::{Grammar, Kind};
use crate::grammar_map::*;
use crate::model::Model;
use crate::style::Style;
use crate::{g, grid, row_col_vec};
// `move_grammar` function does all the necessary operations when copying nested grammars from one
// coordinate in the grid to another including:
// - copying each nested grammar all the way to the innermost cell
// - adjusting the sizes of the grammars in row_heights and col_widths
//
// TODO:
// - add error return value that can be checked to see if grammar move was successful
// - add UNIT TEST to ensure that destination coord is only manipulated if source coord exists
// - (maybe) incorporate dom_resize to get correct values
pub fn move_grammar(m: &mut Model, source: Coordinate, dest: Coordinate) {
if let Some(source_grammar) = m.get_session_mut().grammars.clone().get(&source) {
// copy source grammar from map and insert into destination coordinate
m.get_session_mut()
.grammars
.insert(dest.clone(), source_grammar.clone());
// resizes new grammar
let row_height = m.row_heights.get(&source.full_row()).unwrap_or(&30.0);
let col_width = m.col_widths.get(&source.full_col()).unwrap_or(&90.0);
resize(m, dest.clone(), *row_height, *col_width);
// copying over child grammar values
if let Kind::Grid(sub_coords) = source_grammar.clone().kind {
for sub_coord in sub_coords {
move_grammar(
m,
Coordinate::child_of(&source, sub_coord),
Coordinate::child_of(&dest, sub_coord),
);
}
}
}
}
pub fn non_zero_u32_tuple(val: (u32, u32)) -> (NonZeroU32, NonZeroU32) {
let (row, col) = val;
(NonZeroU32::new(row).unwrap(), NonZeroU32::new(col).unwrap())
}
pub fn row_col_to_string((row, col): (u32, u32)) -> String {
let row_str = row.to_string();
let col_str = from_u32(col + 64).unwrap();
format! {"{}{}", col_str, row_str}
}
pub fn coord_show(row_cols: Vec<(u32, u32)>) -> Option<String> {
match row_cols.split_first() {
Some((&(1, 1), rest)) => {
let mut output = "root".to_string();
for rc in rest.iter() {
output.push('-');
output.push_str(row_col_to_string(*rc).deref());
}
Some(output)
}
Some((&(1, 2), rest)) => {
let mut output = "meta".to_string();
for rc in rest.iter() {
output.push('-');
output.push_str(row_col_to_string(*rc).deref());
}
Some(output)
}
_ => None,
}
}
pub fn apply_definition_grammar(m: &mut Model, root_coord: Coordinate) {
// definition grammar contains the name of the grammar and then the list of
// different parts of the grammar
//
// ------------------------------
// | Definition | { name } |
// ------------------------------
// |----------------------------|
// || {rule name} | { rule ||
// || | grammar } ||
// ||-------------|------------||
// || | ||
// || | ||
// |--------(expandable)--------|
// ------------------------------
//
let mut defn_label_style = Style::default();
defn_label_style.font_weight = 600;
m.col_widths.insert(root_coord.full_col(), 184.0); // set width of col
m.row_heights.insert(root_coord.full_row(), 184.0); // set width of col
build_grammar_map(
&mut m.get_session_mut().grammars,
root_coord,
grid![
[
g!(Grammar {
name: "defn_label".to_string(),
style: defn_label_style,
kind: Kind::Text("Define Grammar".to_string()),
}),
g!(Grammar {
name: "defn_name".to_string(),
style: Style::default(),
kind: Kind::Input(String::new()),
})
],
[grid![
[
g!(Grammar::input("rule_name", "")),
g!(Grammar::input("rule_grammar", ""))
],
[
g!(Grammar::input("rule_name", "")),
g!(Grammar::input("rule_grammar", ""))
]
]]
],
);
}
pub fn resize(m: &mut Model, coord: Coordinate, row_height: f64, col_width: f64) {
if let Some(parent_coord) = coord.parent() {
let mut row_height_diff = 0.0;
let mut col_width_diff = 0.0;
let mut new_row_height = 0.0;
let mut new_col_width = 0.0;
let mut new_grammar = Grammar::default();
if let Some(old_row_height) = m.row_heights.get_mut(&coord.full_row()) {
new_row_height = row_height + /* horizontal border width */ 2.0;
row_height_diff = new_row_height - *old_row_height;
*old_row_height = new_row_height;
}
if let Some(old_col_width) = m.col_widths.get_mut(&coord.full_col()) {
new_col_width = col_width + /* vertiacl border height */ 2.0;
col_width_diff = new_col_width - *old_col_width;
*old_col_width = new_col_width;
}
/* Update style width and height for the resize coord and neighbor with same column or row
Also update new size for its parent coord and associate neighbor.
*/
let mut current_coord = coord.clone();
let mut get_grammar = m.get_session_mut().grammars.clone();
while !current_coord.parent().is_none() {
let p_coord = current_coord.parent().clone();
for (c, g) in m.get_session_mut().grammars.iter_mut() {
if c.parent() == p_coord {
if c.row().get() == current_coord.row().get() {
g.style.height = new_row_height;
}
if c.col().get() == current_coord.col().get() {
g.style.width = new_col_width;
}
}
}
if let Some(parent_grammar) = get_grammar.get_mut(&p_coord.clone().unwrap()) {
new_row_height = parent_grammar.style.height + (2 * 32) as f64;
new_col_width = parent_grammar.style.width + (2 * 92) as f64;
}
current_coord = p_coord.unwrap();
}
info! {"resizing cell: (row: {}, col: {}); height: {}, width: {}", coord.row_to_string(), coord.col_to_string(), row_height_diff, col_width_diff};
resize_diff(m, parent_coord, row_height_diff, col_width_diff);
}
}
pub fn resize_diff(m: &mut Model, coord: Coordinate, row_height_diff: f64, col_width_diff: f64) {
let additional_offset = if m.resizing.is_none() {
2.0 /* if not resizing, account for internal borders width */
} else {
0.0
};
if let Some(parent_coord) = coord.parent() {
if let Some(row_height) = m.row_heights.get_mut(&coord.full_row()) {
*row_height += row_height_diff + additional_offset;
}
if let Some(col_width) = m.col_widths.get_mut(&coord.full_col()) {
*col_width += col_width_diff + additional_offset;
}
resize_diff(m, parent_coord, row_height_diff, col_width_diff);
}
}
// Use width and height values from DOM to resize element
pub fn dom_resize(m: &mut Model, on: Coordinate) {
let (height, width) = {
let element = HtmlElement::try_from(
document()
.get_element_by_id(format! {"cell-{}", on.to_string()}.deref())
.unwrap(),
)
.unwrap();
let rect = element.get_bounding_client_rect();
(rect.get_height(), rect.get_width())
};
info! {"expanding...: H {}px, W {}px", height.clone(), width.clone()}
resize(m, on, height, width);
/*
let on_grammar = map.get_mut(&on).unwrap();
on_grammar.style.height = height.clone();
on_grammar.style.width = width.clone();
let parent_kind = on
.parent()
.and_then(|p| map.get(&p))
.map(|g| g.kind.clone());
if let Some(Kind::Grid(neighbors_coords)) = parent_kind {
for (row, col) in neighbors_coords {
if let Some(cell) = map.get_mut(&Coordinate::child_of(&on, (row.clone(), col.clone())))
{
if row == on.row() {
cell.style.height = height.clone();
} else if col == on.col() {
cell.style.width = width.clone();
}
}
}
}
*/
}
// macro for easily defining a vector of non-zero tuples
// used in Coordinate::root() below
#[macro_export]
macro_rules! row_col_vec {
( $( $x:expr ), * ) => {
{
let mut v: Vec<(NonZeroU32, NonZeroU32)> = Vec::new();
$(
v.push(non_zero_u32_tuple($x));
)*
v
}
};
}
/* TODO: get this working so w can color code lookups */
mod tests {
use super::*;
#[test]
fn test_non_zero_u32_tuple() {
assert_eq!(
non_zero_u32_tuple((1, 2)),
(NonZeroU32::new(1).unwrap(), NonZeroU32::new(2).unwrap())
);
assert_ne!(
non_zero_u32_tuple((1, 2)),
(NonZeroU32::new(2).unwrap(), NonZeroU32::new(2).unwrap())
);
}
#[test]
fn test_row_col_to_string() {
assert_eq!(row_col_to_string((2, 2)), "B2");
assert_ne!(row_col_to_string((2, 2)), "A2");
}
#[test]
fn test_coord_show() {
assert_eq!(coord_show(vec![(1, 1), (1, 1)]).unwrap(), "root-A1");
assert_ne!(coord_show(vec![(1, 1), (1, 1)]).unwrap(), "root")
}
}