ElyDoc, ElyTable, ElyShow (LibreOfficeKit), ElyPDF (MuPDF), ElyTree (Git), ElyMark (Milkdown and CodeMirror in CEF). ElyMail and ElyAgent follow.
138 lines
5.4 KiB
Rust
138 lines
5.4 KiB
Rust
//! The output dialog: what, which slides, how many a page.
|
|
|
|
use ely_gpui_component::{
|
|
buttons::{Button, ButtonVariant, SegmentedControl},
|
|
data_display::DescriptionList,
|
|
forms::{Choice, NumberInput, Select},
|
|
overlays::Dialog as Card,
|
|
theme::ControlSize,
|
|
};
|
|
use gpui::{ParentElement as _, Styled as _, Window, div};
|
|
|
|
use super::{Kind, Output, Range};
|
|
use crate::deck::Deck;
|
|
use crate::dialog::Dialog;
|
|
|
|
/// What goes out, which slides, how many a page.
|
|
pub fn output_dialog(
|
|
this: gpui::Entity<Deck>,
|
|
output: &Output,
|
|
dismiss: impl Fn(&mut Window, &mut gpui::App) + 'static,
|
|
cx: &gpui::App,
|
|
) -> Card {
|
|
let text = |key: &str| Deck::text(cx, key, &[]);
|
|
let change = |this: &gpui::Entity<Deck>, cx: &mut gpui::App, edit: &dyn Fn(&mut Output)| {
|
|
this.update(cx, |deck, cx| {
|
|
if let Some(Dialog::Output(output)) = &mut deck.dialog {
|
|
edit(output);
|
|
}
|
|
cx.notify();
|
|
})
|
|
};
|
|
let kinds: &[(Kind, &str)] = match output.print {
|
|
true => &[(Kind::Slides, "slides"), (Kind::Handouts, "handouts")],
|
|
false => &[(Kind::Slides, "pdf"), (Kind::Pictures, "pictures"), (Kind::Handouts, "handouts")],
|
|
};
|
|
let now = kinds.iter().find(|(kind, _)| *kind == output.kind).map_or("pdf", |(_, id)| id);
|
|
let kind = {
|
|
let (this, kinds) = (this.clone(), kinds.to_vec());
|
|
kinds
|
|
.iter()
|
|
.fold(SegmentedControl::new("show-output-kind", now), |control, (_, id)| {
|
|
control.segment(*id, text(&format!("show.output.{id}")), None)
|
|
})
|
|
.size(ControlSize::Sm)
|
|
.on_change(move |value, _, cx| {
|
|
if let Some((kind, _)) = kinds.iter().find(|(_, id)| *id == value.as_ref()) {
|
|
let kind = *kind;
|
|
change(&this, cx, &|output| output.kind = kind);
|
|
}
|
|
})
|
|
};
|
|
let which = match output.range {
|
|
Range::All => "all",
|
|
Range::Current => "current",
|
|
Range::Slides(..) => "range",
|
|
};
|
|
let last = output.hidden.len() as u32;
|
|
let range = {
|
|
let this = this.clone();
|
|
let control = SegmentedControl::new("show-output-range", which)
|
|
.size(ControlSize::Sm)
|
|
.segment("all", text("show.output.all"), None);
|
|
// Master view has no current slide.
|
|
let control = match output.current {
|
|
Some(_) => control.segment("current", text("show.output.current"), None),
|
|
None => control,
|
|
};
|
|
control
|
|
.segment("range", text("show.output.range"), None)
|
|
.on_change(move |value, _, cx| {
|
|
let range = match value.as_ref() {
|
|
"all" => Range::All,
|
|
"current" => Range::Current,
|
|
_ => Range::Slides(1, last),
|
|
};
|
|
change(&this, cx, &|output| output.range = range);
|
|
})
|
|
};
|
|
let bound = |id: &'static str, value: u32, first: bool| {
|
|
// A typed number counts before blur commits it.
|
|
let set = move |this: &gpui::Entity<Deck>, value: f64, cx: &mut gpui::App| {
|
|
let value = value.round() as u32;
|
|
change(this, cx, &|output| {
|
|
if let Range::Slides(from, to) = &mut output.range {
|
|
*(if first { from } else { to }) = value;
|
|
}
|
|
})
|
|
};
|
|
let (typed, committed) = (this.clone(), this.clone());
|
|
NumberInput::new(id, f64::from(value))
|
|
.label(text(if first { "show.output.from" } else { "show.output.to" }))
|
|
.range(1.0, f64::from(last))
|
|
.size(ControlSize::Sm)
|
|
.on_change(move |value, _, cx| set(&typed, value, cx))
|
|
.on_commit(move |value, _, cx| set(&committed, value, cx))
|
|
};
|
|
let bounds = match output.range {
|
|
Range::Slides(from, to) => Some(
|
|
div()
|
|
.flex()
|
|
.gap_2()
|
|
.child(div().w_full().max_w_24().child(bound("show-output-from", from, true)))
|
|
.child(div().w_full().max_w_24().child(bound("show-output-to", to, false))),
|
|
),
|
|
_ => None,
|
|
};
|
|
let per = (output.kind == Kind::Handouts).then(|| {
|
|
let this = this.clone();
|
|
let choices = [1u8, 2, 3, 4, 6, 9].map(|n| Choice::new(n.to_string(), n.to_string()));
|
|
Select::new("show-output-per", choices)
|
|
.label(text("show.output.per"))
|
|
.selected(output.per.to_string())
|
|
.on_change(move |value, _, cx| {
|
|
let per: u8 = value.parse().expect("listed numbers");
|
|
change(&this, cx, &|output| output.per = per);
|
|
})
|
|
});
|
|
let mut rows = DescriptionList::new()
|
|
.item(text("show.output.what"), kind)
|
|
.item(text("show.output.which"), div().flex().flex_col().gap_2().child(range).children(bounds));
|
|
if let Some(per) = per {
|
|
rows = rows.item(text("show.output.per"), per);
|
|
}
|
|
let (title, go) = match output.print {
|
|
true => ("show.output.print_title", "show.output.print"),
|
|
false => ("show.output.export_title", "show.output.export"),
|
|
};
|
|
let go = text(go);
|
|
Card::new("show-output", text(title), dismiss)
|
|
.child(rows)
|
|
.action(ely_office::cancel(cx))
|
|
.action(move |_| {
|
|
Button::new("show-output-go", go)
|
|
.variant(ButtonVariant::Primary)
|
|
.on_click(move |_, _, cx| this.update(cx, |deck, cx| deck.output(cx)))
|
|
})
|
|
}
|