use iced::widget::{Space, column, container, mouse_area, opaque, row, scrollable, stack};
use iced::{Element, Length};
use super::super::theme::{TOKYO_MUTED, ui_text};
use super::consts::{CONTENT_PADDING, SETTING_ROW_HEIGHT};
use super::language::{language_dropdown_list, language_setting_row};
use super::network::network_defaults_row;
use super::shortcuts_row::shortcuts_setting_row;
use super::speed::speed_setting_row;
use super::theme_row::theme_setting_row;
use crate::app::{Message, SettingsCategory, SettingsDialog};
use crate::i18n::{Key, Lang, NetworkKey};
mod rows;
use rows::*;
pub(super) fn settings_content<'a>(dialog: &'a SettingsDialog, lang: Lang) -> Element<'a, Message> {
let lower_query = dialog.search_query().to_lowercase();
let searching = !lower_query.is_empty();
let mut rows: Vec<Element<'a, Message>> = Vec::new();
let mut language_row_index: Option<usize> = None;
if searching {
for (i, cat) in SettingsCategory::ALL.iter().enumerate() {
let mut group: Vec<Element<'a, Message>> = Vec::new();
collect_category_rows(*cat, dialog, lang, &lower_query, &mut group, &mut |idx| {
language_row_index = Some(rows.len() + 1 + idx);
});
if group.is_empty() {
continue;
}
if i > 0 && !rows.is_empty() {
rows.push(Space::new().height(Length::Fixed(8.0)).into());
}
rows.push(group_header(lang.t(cat.label_key())));
rows.extend(group);
}
} else {
collect_category_rows(
dialog.category,
dialog,
lang,
&lower_query,
&mut rows,
&mut |idx| {
language_row_index = Some(idx);
},
);
}
let body: Element<'a, Message> = if rows.is_empty() {
container(ui_text(lang.t(Key::SettingsNoMatches), 13, TOKYO_MUTED))
.padding(CONTENT_PADDING)
.into()
} else {
column(rows).spacing(20).padding(CONTENT_PADDING).into()
};
let body: Element<'a, Message> = scrollable(body)
.direction(scrollable::Direction::Vertical(
scrollable::Scrollbar::hidden(),
))
.width(Length::Fill)
.height(Length::Fill)
.into();
let body: Element<'a, Message> = match (dialog.language_dropdown_open, language_row_index) {
(true, Some(idx)) if !searching => {
let row_top = CONTENT_PADDING + (idx as f32) * (SETTING_ROW_HEIGHT + 20.0);
let overlay_top = row_top + SETTING_ROW_HEIGHT - 4.0;
let (visible_selection, highlighted) = match dialog.dropdown_highlight {
Some(h) => (None, h),
None => (Some(dialog.draft_lang), dialog.draft_lang),
};
let dropdown = language_dropdown_list(visible_selection, highlighted, lang);
let close_layer = mouse_area(
container(Space::new())
.width(Length::Fill)
.height(Length::Fill),
)
.on_press(Message::SettingsLanguageDropdownToggled);
let positioned_dropdown = column![
Space::new().height(Length::Fixed(overlay_top)),
row![
Space::new().width(Length::Fill),
opaque(dropdown),
Space::new().width(Length::Fixed(CONTENT_PADDING)),
]
.width(Length::Fill),
Space::new().height(Length::Fill),
]
.width(Length::Fill)
.height(Length::Fill);
stack![body, close_layer, positioned_dropdown]
.width(Length::Fill)
.height(Length::Fill)
.into()
}
_ => body,
};
container(body)
.width(Length::Fill)
.height(Length::Fill)
.into()
}
fn collect_category_rows<'a>(
category: SettingsCategory,
dialog: &'a SettingsDialog,
lang: Lang,
lower_query: &str,
out: &mut Vec<Element<'a, Message>>,
mut on_language_row: impl FnMut(usize),
) {
let start = out.len();
match category {
SettingsCategory::General => {
if matches_query(
&[Key::SettingsLanguageLabel, Key::SettingsLanguageHint],
lang,
lower_query,
) {
on_language_row(out.len() - start);
out.push(language_setting_row(dialog, lang));
}
if matches_query(
&[Key::SettingsSpeedLabel, Key::SettingsSpeedHint],
lang,
lower_query,
) {
out.push(speed_setting_row(dialog, lang));
}
if matches_query(
&[Key::SettingsFollowPcLabel, Key::SettingsFollowPcHint],
lang,
lower_query,
) {
out.push(follow_pc_toggle_row(dialog, lang));
}
if matches_query(
&[
Key::SettingsMemoryOperandHighlightingLabel,
Key::SettingsMemoryOperandHighlightingHint,
],
lang,
lower_query,
) {
out.push(memory_operand_highlighting_row(dialog, lang));
}
if matches_query(
&[
Key::SettingsFileAssociationLabel,
Key::SettingsFileAssociationHint,
Key::SettingsFileAssociationAdd,
Key::SettingsFileAssociationRemove,
],
lang,
lower_query,
) {
out.push(file_association_row(dialog, lang));
}
}
SettingsCategory::ExternalDevices => {
if matches_query(
&[Key::SettingsFloppyImageLabel, Key::SettingsFloppyImageHint],
lang,
lower_query,
) {
out.push(floppy_image_row(dialog, lang));
}
if matches_query(
&[
Key::SettingsHddDirectoryLabel,
Key::SettingsHddDirectoryHint,
],
lang,
lower_query,
) {
out.push(hdd_directory_row(dialog, lang));
}
if matches_query(
&[
Key::Network(NetworkKey::GeneralSettingsLabel),
Key::Network(NetworkKey::GeneralSettingsHint),
Key::Network(NetworkKey::ModeClient),
Key::Network(NetworkKey::ModeServer),
],
lang,
lower_query,
) {
out.push(network_defaults_row(dialog, lang));
}
}
SettingsCategory::Appearance => {
if matches_query(
&[Key::SettingsThemeLabel, Key::SettingsThemeHint],
lang,
lower_query,
) {
out.push(theme_setting_row(dialog, lang));
}
}
SettingsCategory::Shortcuts => {
if matches_query(
&[Key::SettingsShortcutsLabel, Key::SettingsShortcutsHint],
lang,
lower_query,
) {
out.push(shortcuts_setting_row(dialog, lang));
}
}
}
}
fn group_header(label: &'static str) -> Element<'static, Message> {
ui_text(label, 11, TOKYO_MUTED).into()
}
pub(super) fn matches_query(keys: &[Key], lang: Lang, lower_query: &str) -> bool {
if lower_query.is_empty() {
return true;
}
keys.iter()
.any(|k| lang.t(*k).to_lowercase().contains(lower_query))
}