summaryrefslogtreecommitdiffstats
path: root/examples/lib-dfscq-log/src/layer.rs
blob: 45edb56b97384acdb64e84d5d78c56d47e546ccc (plain)
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
use diaphragm_core::{
    core_shapes::Rectangle,
    core_shapes::Text,
    text::FontDescription,
    types::{Bounds, Float, ShapeContext},
    ComplexShape, DrawResult, Drawable, DynDrawable, SolverContext,
};

#[derive(Clone)]
pub struct Entry {
    // TODO: transform this to just Text
    pub label: Option<String>,
    pub label_vert_center_offset: Option<Float>,
    pub content: DynDrawable,
}

#[derive(Clone)]
pub struct Layer {
    // TODO: transform this to just Text
    pub name: String,
    pub name_font: FontDescription,
    pub label_font: FontDescription,
    pub padding: Float,
    pub entries: Vec<Entry>,
    pub entries_width: Float,
}

impl ComplexShape for Layer {
    fn draw(&self, context: &ShapeContext, solver: &mut dyn SolverContext) -> DrawResult {
        let mut result = DrawResult::new();

        let bounds_top = context.bounds().top(solver);
        let bounds_left = context.bounds().left(solver);
        let bounds_right = context.bounds().right(solver);
        let bounds_height = context.bounds().height(solver);

        let inner_top = solver.float_add(&[bounds_top, self.padding]);
        let inner_right = solver.float_sub(&[bounds_right, self.padding]);

        // Outer box

        result.push(Drawable::new(Rectangle {}, context.clone()));

        // Layer name

        let layer_name = Drawable::builder(Text {
            content: self.name.clone(),
            font: self.name_font.clone(),
        })
        .bounds(
            Bounds::builder()
                .top(inner_top)
                .left(solver.float_add(&[bounds_left, self.padding]))
                .build(solver),
        )
        .stroke(context.stroke().clone())
        .fill(context.fill().clone())
        .build(solver);

        let layer_name_bottom = layer_name.bounds().bottom(solver);

        /*
        let mut rect_context = layer_name_context.clone();
        rect_context.stroke = StrokeStyle::solid(Color::from_rgb(1., 0., 0.));
        result.push_shape(Rectangle {}, rect_context);
        */

        result.push(layer_name);

        // Entries

        let mut entry_y_acc = inner_top;

        for entry in &self.entries {
            // Entry content

            /*
            let content_context = ShapeContext {
                bounds: Bounds {
                    top: solver.new_free_float(),
                    left: content_left,
                    width: entry.width,
                    height: entry.height,
                },
                fill: Default::default(),
                stroke: Default::default(),
            };
            */

            let content_vert_center = entry.content.bounds().vert_center(solver);
            let content_top = entry.content.bounds().top(solver);
            let content_left = entry.content.bounds().left(solver);
            let content_bottom = entry.content.bounds().bottom(solver);

            // TODO: to replace with label offset
            let content_half_height = solver.float_sub(&[content_vert_center, content_top]);

            result.push_dyn(entry.content.clone());

            // Entry label

            if let Some(label_content) = entry.label.clone() {
                let label_top = solver.new_free_float();
                let label_width = solver.new_free_float();
                let label_left = solver.float_sub(&[inner_right, self.entries_width, label_width]);

                let label = Drawable::builder(Text {
                    content: label_content,
                    font: self.label_font.clone(),
                })
                .bounds(
                    Bounds::builder()
                        .top(label_top)
                        .left(label_left)
                        .width(label_width)
                        .build(solver),
                )
                .build(solver);

                /*
                let mut rect_context = label_context.clone();
                rect_context.stroke = StrokeStyle::solid(Color::from_rgb(1., 0., 0.));
                result.push_shape(Rectangle {}, rect_context);
                */

                // TODO
                let label_vert_center = label.bounds().vert_center(solver);
                let label_top = label.bounds().top(solver);
                let label_right = label.bounds().right(solver);

                let label_vert_center_constraint =
                    solver.float_eq(label_vert_center, content_vert_center);
                solver.constrain(label_vert_center_constraint);

                let label_half_height = solver.float_sub(&[label_vert_center, label_top]);

                let dumb_label_mid_placement =
                    solver.float_add(&[entry_y_acc, content_half_height]);
                let safe_label_mid_placement =
                    solver.float_add(&[layer_name_bottom, label_half_height]);
                let label_mid_placement =
                    solver.float_max(&[safe_label_mid_placement, dumb_label_mid_placement]);
                let label_mid_placement_constraint =
                    solver.float_eq(label_vert_center, label_mid_placement);
                solver.constrain(label_mid_placement_constraint);

                let label_right_constraint = solver.float_eq(label_right, content_left);
                solver.constrain(label_right_constraint);

                result.push(label);
            } else {
                let content_top_constraint = solver.float_eq(content_top, entry_y_acc);
                solver.constrain(content_top_constraint);

                let wanted_content_left = solver.float_sub(&[inner_right, self.entries_width]);
                let content_left_constraint = solver.float_eq(content_left, wanted_content_left);
                solver.constrain(content_left_constraint);
            }

            entry_y_acc = solver.float_add(&[content_bottom, self.padding]);
        }

        let wanted_bounds_height = solver.float_sub(&[entry_y_acc, bounds_top]);
        let height_constraint = solver.float_eq(bounds_height, wanted_bounds_height);
        solver.constrain(height_constraint);

        result
    }
}