Ely Office: six offline-first desktop apps in Rust and GPUI
ElyDoc, ElyTable, ElyShow (LibreOfficeKit), ElyPDF (MuPDF), ElyTree (Git), ElyMark (Milkdown and CodeMirror in CEF). ElyMail and ElyAgent follow.
This commit is contained in:
817 files changed
+143101
No files matched your search
@@ -0,0 +1,296 @@
|
||||
//! 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,
|
||||
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 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)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user