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
use re_format::{format_f32, format_uint};
use re_types::components::{LineStrip2D, LineStrip3D};
use re_viewer_context::{MaybeMutRef, UiLayout, ViewerContext};

use crate::DEFAULT_NUMBER_WIDTH;

fn singleline_view_line_strip_3d(
    _ctx: &ViewerContext<'_>,
    ui: &mut egui::Ui,
    value: &mut MaybeMutRef<'_, LineStrip3D>,
) -> egui::Response {
    UiLayout::List.label(
        ui,
        format!("{} positions", format_uint(value.as_ref().0.len())),
    )
}

fn multiline_view_line_strip_3d(
    _ctx: &ViewerContext<'_>,
    ui: &mut egui::Ui,
    value: &mut MaybeMutRef<'_, LineStrip3D>,
) -> egui::Response {
    use egui_extras::Column;

    // TODO(andreas): Editing this would be nice!
    let value = value.as_ref();

    // TODO(andreas): Is it really a good idea to always have the full table here?
    // Can we use the ui stack to know where we are and do the right thing instead?
    UiLayout::SelectionPanel
        .table(ui)
        .resizable(true)
        .cell_layout(egui::Layout::left_to_right(egui::Align::Center))
        .columns(Column::initial(DEFAULT_NUMBER_WIDTH).clip(true), 3)
        .header(re_ui::DesignTokens::table_header_height(), |mut header| {
            re_ui::DesignTokens::setup_table_header(&mut header);
            header.col(|ui| {
                ui.label("x");
            });
            header.col(|ui| {
                ui.label("y");
            });
            header.col(|ui| {
                ui.label("z");
            });
        })
        .body(|mut body| {
            re_ui::DesignTokens::setup_table_body(&mut body);
            let row_height = re_ui::DesignTokens::table_line_height();
            body.rows(row_height, value.0.len(), |mut row| {
                if let Some(pos) = value.0.get(row.index()) {
                    row.col(|ui| {
                        ui.label(format_f32(pos.x()));
                    });
                    row.col(|ui| {
                        ui.label(format_f32(pos.y()));
                    });
                    row.col(|ui| {
                        ui.label(format_f32(pos.z()));
                    });
                }
            });
        });

    // Placeholder response.
    ui.allocate_response(egui::Vec2::ZERO, egui::Sense::hover())
}

fn singleline_view_line_strip_2d(
    _ctx: &ViewerContext<'_>,
    ui: &mut egui::Ui,
    value: &mut MaybeMutRef<'_, LineStrip2D>,
) -> egui::Response {
    UiLayout::List.label(
        ui,
        format!("{} positions", format_uint(value.as_ref().0.len())),
    )
}

fn multiline_view_line_strip_2d(
    _ctx: &ViewerContext<'_>,
    ui: &mut egui::Ui,
    value: &mut MaybeMutRef<'_, LineStrip2D>,
) -> egui::Response {
    use egui_extras::Column;

    // TODO(andreas): Editing this would be nice!
    let value = value.as_ref();

    // TODO(andreas): Is it really a good idea to always have the full table here?
    // Can we use the ui stack to know where we are and do the right thing instead?
    UiLayout::SelectionPanel
        .table(ui)
        .resizable(true)
        .cell_layout(egui::Layout::left_to_right(egui::Align::Center))
        .columns(Column::initial(DEFAULT_NUMBER_WIDTH).clip(true), 2)
        .header(re_ui::DesignTokens::table_header_height(), |mut header| {
            re_ui::DesignTokens::setup_table_header(&mut header);
            header.col(|ui| {
                ui.label("x");
            });
            header.col(|ui| {
                ui.label("y");
            });
        })
        .body(|mut body| {
            re_ui::DesignTokens::setup_table_body(&mut body);
            let row_height = re_ui::DesignTokens::table_line_height();
            body.rows(row_height, value.0.len(), |mut row| {
                if let Some(pos) = value.0.get(row.index()) {
                    row.col(|ui| {
                        ui.label(format_f32(pos.x()));
                    });
                    row.col(|ui| {
                        ui.label(format_f32(pos.y()));
                    });
                }
            });
        });

    // Placeholder response.
    ui.allocate_response(egui::Vec2::ZERO, egui::Sense::hover())
}

pub fn register_linestrip_component_ui(registry: &mut re_viewer_context::ComponentUiRegistry) {
    registry.add_multiline_edit_or_view(multiline_view_line_strip_3d);
    registry.add_singleline_edit_or_view(singleline_view_line_strip_3d);
    registry.add_multiline_edit_or_view(multiline_view_line_strip_2d);
    registry.add_singleline_edit_or_view(singleline_view_line_strip_2d);
}