table_header.rs

 1use gpui::ElementId;
 2use ui::{Tooltip, prelude::*};
 3
 4use crate::{
 5    CsvPreviewView,
 6    settings::FontType,
 7    table_data_engine::sorting_by_column::{AppliedSorting, SortDirection},
 8    types::AnyColumn,
 9};
10
11impl CsvPreviewView {
12    /// Create header for data, which is orderable with text on the left and sort button on the right
13    pub(crate) fn create_header_element_with_sort_button(
14        &self,
15        header_text: SharedString,
16        cx: &mut Context<'_, CsvPreviewView>,
17        col_idx: AnyColumn,
18    ) -> AnyElement {
19        // CSV data columns: text + filter/sort buttons
20        h_flex()
21            .justify_between()
22            .items_center()
23            .w_full()
24            .map(|div| match self.settings.font_type {
25                FontType::Ui => div.font_ui(cx),
26                FontType::Monospace => div.font_buffer(cx),
27            })
28            .child(div().child(header_text))
29            .child(h_flex().gap_1().child(self.create_sort_button(cx, col_idx)))
30            .into_any_element()
31    }
32
33    fn create_sort_button(
34        &self,
35        cx: &mut Context<'_, CsvPreviewView>,
36        col_idx: AnyColumn,
37    ) -> Button {
38        let sort_btn = Button::new(
39            ElementId::NamedInteger("sort-button".into(), col_idx.get() as u64),
40            match self.engine.applied_sorting {
41                Some(ordering) if ordering.col_idx == col_idx => match ordering.direction {
42                    SortDirection::Asc => "",
43                    SortDirection::Desc => "",
44                },
45                _ => "", // Unsorted/available for sorting
46            },
47        )
48        .size(ButtonSize::Compact)
49        .style(
50            if self
51                .engine
52                .applied_sorting
53                .is_some_and(|o| o.col_idx == col_idx)
54            {
55                ButtonStyle::Filled
56            } else {
57                ButtonStyle::Subtle
58            },
59        )
60        .tooltip(Tooltip::text(match self.engine.applied_sorting {
61            Some(ordering) if ordering.col_idx == col_idx => match ordering.direction {
62                SortDirection::Asc => "Sorted A-Z. Click to sort Z-A",
63                SortDirection::Desc => "Sorted Z-A. Click to disable sorting",
64            },
65            _ => "Not sorted. Click to sort A-Z",
66        }))
67        .on_click(cx.listener(move |this, _event, _window, cx| {
68            let new_sorting = match this.engine.applied_sorting {
69                Some(ordering) if ordering.col_idx == col_idx => {
70                    // Same column clicked - cycle through states
71                    match ordering.direction {
72                        SortDirection::Asc => Some(AppliedSorting {
73                            col_idx,
74                            direction: SortDirection::Desc,
75                        }),
76                        SortDirection::Desc => None, // Clear sorting
77                    }
78                }
79                _ => {
80                    // Different column or no sorting - start with ascending
81                    Some(AppliedSorting {
82                        col_idx,
83                        direction: SortDirection::Asc,
84                    })
85                }
86            };
87
88            this.engine.applied_sorting = new_sorting;
89            this.apply_sort();
90            cx.notify();
91        }));
92        sort_btn
93    }
94}