328 lines
10 KiB
Rust
328 lines
10 KiB
Rust
//! ElyTable's one open dialog.
|
|
|
|
use ely_gpui_component::{
|
|
forms::TextInput,
|
|
tables::{FilterRule, SortKey},
|
|
};
|
|
use ely_lok::sheet::{Entry, Format, References, Selection, Validation};
|
|
use gpui::{AnyElement, App, Context, Entity, IntoElement, SharedString, Window};
|
|
|
|
use crate::book::Book;
|
|
use crate::{analysis, data, rules};
|
|
|
|
/// Changes the open dialog's state.
|
|
pub(crate) fn edit(
|
|
this: &Entity<Book>,
|
|
cx: &mut App,
|
|
change: impl FnOnce(&mut Dialog, &mut Book, &mut Context<Book>),
|
|
) {
|
|
this.update(cx, |book, cx| {
|
|
if let Some(mut dialog) = book.dialog.take() {
|
|
change(&mut dialog, book, cx);
|
|
book.dialog = Some(dialog);
|
|
}
|
|
cx.notify();
|
|
});
|
|
}
|
|
|
|
/// What the open dialog asks, for which workbook.
|
|
pub enum Dialog {
|
|
Rename {
|
|
tab: u64,
|
|
/// The state the sheet number was read in.
|
|
at: ely_lok::Doc,
|
|
index: usize,
|
|
field: Entity<TextInput>,
|
|
},
|
|
Show {
|
|
tab: u64,
|
|
hidden: Vec<String>,
|
|
chosen: String,
|
|
},
|
|
Delete {
|
|
tab: u64,
|
|
/// The state the sheet number was read in.
|
|
at: ely_lok::Doc,
|
|
index: usize,
|
|
name: String,
|
|
references: References,
|
|
},
|
|
Size {
|
|
tab: u64,
|
|
column: bool,
|
|
field: Entity<TextInput>,
|
|
},
|
|
Merge {
|
|
tab: u64,
|
|
},
|
|
Define {
|
|
tab: u64,
|
|
name: Entity<TextInput>,
|
|
range: Entity<TextInput>,
|
|
scope: String,
|
|
},
|
|
Names {
|
|
tab: u64,
|
|
names: Vec<ely_lok::sheet::Name>,
|
|
chosen: usize,
|
|
range: Entity<TextInput>,
|
|
},
|
|
Sort {
|
|
tab: u64,
|
|
picked: Selection,
|
|
keys: Vec<SortKey>,
|
|
header: bool,
|
|
},
|
|
Filter {
|
|
tab: u64,
|
|
picked: Selection,
|
|
rules: Vec<FilterRule>,
|
|
any: bool,
|
|
},
|
|
Dedupe {
|
|
tab: u64,
|
|
picked: Selection,
|
|
header: bool,
|
|
state: crate::data::ReadState,
|
|
},
|
|
Columns {
|
|
tab: u64,
|
|
separators: Vec<SharedString>,
|
|
other: Entity<TextInput>,
|
|
},
|
|
/// A column button's filter menu.
|
|
Column {
|
|
tab: u64,
|
|
column: u32,
|
|
/// The button's row: its cell names the filtered range.
|
|
row: u32,
|
|
entries: Vec<Entry>,
|
|
picked: Vec<SharedString>,
|
|
},
|
|
Validation {
|
|
tab: u64,
|
|
rule: Box<Validation>,
|
|
fields: Box<crate::rules::Fields>,
|
|
},
|
|
Conditional {
|
|
tab: u64,
|
|
kind: &'static str,
|
|
operator: &'static str,
|
|
style: &'static str,
|
|
preset: usize,
|
|
value1: Entity<TextInput>,
|
|
value2: Entity<TextInput>,
|
|
},
|
|
Formats {
|
|
tab: u64,
|
|
formats: Vec<Format>,
|
|
chosen: usize,
|
|
},
|
|
Pivot {
|
|
tab: u64,
|
|
source: String,
|
|
fields: Vec<String>,
|
|
layout: ely_lok::sheet::Layout,
|
|
/// Changes the pivot table at the cursor.
|
|
editing: bool,
|
|
},
|
|
Chart {
|
|
tab: u64,
|
|
/// The selected chart; none inserts one.
|
|
chart: Option<Box<ely_lok::sheet::Chart>>,
|
|
look: Box<ely_lok::sheet::Look>,
|
|
fields: Box<crate::analysis::ChartFields>,
|
|
},
|
|
/// A text file before it opens.
|
|
Import(Box<crate::text::Pending>),
|
|
Export {
|
|
tab: u64,
|
|
format: crate::output::Format,
|
|
},
|
|
Page {
|
|
tab: u64,
|
|
layout: Box<ely_lok::sheet::PrintLayout>,
|
|
landscape: bool,
|
|
scale: ely_lok::sheet::Scale,
|
|
fields: Box<crate::page::PageFields>,
|
|
},
|
|
Protect {
|
|
tab: u64,
|
|
protecting: Box<crate::protect::Protecting>,
|
|
},
|
|
}
|
|
|
|
impl Dialog {
|
|
/// The workbook it asks about; imports have none yet.
|
|
pub fn tab(&self) -> Option<u64> {
|
|
match self {
|
|
Dialog::Rename { tab, .. }
|
|
| Dialog::Show { tab, .. }
|
|
| Dialog::Delete { tab, .. }
|
|
| Dialog::Size { tab, .. }
|
|
| Dialog::Merge { tab, .. }
|
|
| Dialog::Define { tab, .. }
|
|
| Dialog::Names { tab, .. }
|
|
| Dialog::Sort { tab, .. }
|
|
| Dialog::Filter { tab, .. }
|
|
| Dialog::Dedupe { tab, .. }
|
|
| Dialog::Columns { tab, .. }
|
|
| Dialog::Column { tab, .. }
|
|
| Dialog::Validation { tab, .. }
|
|
| Dialog::Conditional { tab, .. }
|
|
| Dialog::Formats { tab, .. }
|
|
| Dialog::Pivot { tab, .. }
|
|
| Dialog::Chart { tab, .. }
|
|
| Dialog::Export { tab, .. }
|
|
| Dialog::Page { tab, .. }
|
|
| Dialog::Protect { tab, .. } => Some(*tab),
|
|
Dialog::Import(_) => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Book {
|
|
/// The define dialog's sheets: its own workbook's.
|
|
pub(crate) fn define_scopes(&self) -> Option<Vec<String>> {
|
|
let Some(Dialog::Define { tab, .. }) = &self.dialog else {
|
|
return None;
|
|
};
|
|
self.sheet_in(*tab).map(|(_, _, names)| names)
|
|
}
|
|
|
|
/// ElyTable's open dialog, if any.
|
|
pub fn dialog_element(&mut self, cx: &mut Context<Self>) -> Option<AnyElement> {
|
|
let this = cx.entity();
|
|
let dismiss = {
|
|
let this = this.clone();
|
|
move |_: &mut Window, cx: &mut App| {
|
|
this.update(cx, |book, cx| {
|
|
book.dialog = None;
|
|
cx.notify();
|
|
})
|
|
}
|
|
};
|
|
let element = match self.dialog.as_ref()? {
|
|
Dialog::Rename { tab, index, field, .. } => {
|
|
let names = self.sheet_in(*tab)?.2;
|
|
crate::sheets::dialogs::rename(this, (*index, field, names), dismiss, cx)
|
|
.into_any_element()
|
|
}
|
|
Dialog::Show {
|
|
tab,
|
|
hidden,
|
|
chosen,
|
|
} => crate::sheets::dialogs::show(this, (*tab, hidden, chosen), dismiss, cx)
|
|
.into_any_element(),
|
|
Dialog::Delete {
|
|
name, references, ..
|
|
} => crate::sheets::dialogs::delete(this, (name, references), dismiss, cx)
|
|
.into_any_element(),
|
|
Dialog::Size { column, field, .. } => {
|
|
crate::cells::size_dialog(this, (*column, field), dismiss, cx).into_any_element()
|
|
}
|
|
Dialog::Merge { tab } => {
|
|
crate::cells::merge_dialog(this, *tab, dismiss, cx).into_any_element()
|
|
}
|
|
Dialog::Define {
|
|
name, range, scope, ..
|
|
} => crate::formulas::define_dialog(
|
|
this,
|
|
(name, range, scope, self.define_scopes()?),
|
|
dismiss,
|
|
cx,
|
|
)
|
|
.into_any_element(),
|
|
Dialog::Names {
|
|
names,
|
|
chosen,
|
|
range,
|
|
..
|
|
} => crate::formulas::names_dialog(this, (names, *chosen, range), dismiss, cx)
|
|
.into_any_element(),
|
|
Dialog::Sort {
|
|
picked,
|
|
keys,
|
|
header,
|
|
..
|
|
} => data::sort_dialog(this, (picked, keys, *header), dismiss, cx).into_any_element(),
|
|
Dialog::Filter {
|
|
picked, rules, any, ..
|
|
} => data::filter_dialog(this, (picked, rules, *any), dismiss, cx).into_any_element(),
|
|
Dialog::Dedupe { picked, header, .. } => {
|
|
data::dedupe_dialog(this, (picked, *header), dismiss, cx).into_any_element()
|
|
}
|
|
Dialog::Columns {
|
|
separators, other, ..
|
|
} => data::columns_dialog(this, (separators, other), dismiss, cx).into_any_element(),
|
|
Dialog::Column {
|
|
column,
|
|
entries,
|
|
picked,
|
|
..
|
|
} => data::column_dialog(this, (*column, entries, picked), dismiss, cx)
|
|
.into_any_element(),
|
|
Dialog::Validation { rule, fields, .. } => {
|
|
rules::validation_dialog(this, (rule, fields), dismiss, cx).into_any_element()
|
|
}
|
|
Dialog::Conditional {
|
|
kind,
|
|
operator,
|
|
style,
|
|
preset,
|
|
value1,
|
|
value2,
|
|
..
|
|
} => {
|
|
let shown = rules::Shown {
|
|
kind,
|
|
operator,
|
|
style,
|
|
preset: *preset,
|
|
value1,
|
|
value2,
|
|
};
|
|
rules::conditional_dialog(this, shown, dismiss, cx).into_any_element()
|
|
}
|
|
Dialog::Formats {
|
|
formats, chosen, ..
|
|
} => rules::formats_dialog(this, (formats, *chosen), dismiss, cx).into_any_element(),
|
|
Dialog::Pivot {
|
|
source,
|
|
fields,
|
|
layout,
|
|
editing,
|
|
..
|
|
} => analysis::pivot_dialog(this, (source, fields, layout, *editing), dismiss, cx)
|
|
.into_any_element(),
|
|
Dialog::Chart {
|
|
chart,
|
|
look,
|
|
fields,
|
|
..
|
|
} => analysis::chart_dialog(this, (chart.as_deref(), look, fields), dismiss, cx)
|
|
.into_any_element(),
|
|
Dialog::Import(pending) => {
|
|
crate::text::import_dialog(this, pending, dismiss, cx).into_any_element()
|
|
}
|
|
Dialog::Export { tab, format } => {
|
|
let sheet = self.sheet_in(*tab)?.1;
|
|
crate::output::export_dialog(this, (*format, &sheet), dismiss, cx)
|
|
.into_any_element()
|
|
}
|
|
Dialog::Page {
|
|
layout,
|
|
landscape,
|
|
scale,
|
|
fields,
|
|
..
|
|
} => crate::page::page_dialog(this, (layout, *landscape, *scale, fields), dismiss, cx)
|
|
.into_any_element(),
|
|
Dialog::Protect { protecting, .. } => {
|
|
crate::protect::protect_dialog(this, protecting, dismiss, cx).into_any_element()
|
|
}
|
|
};
|
|
Some(element)
|
|
}
|
|
}
|