use super::ViewId;
use super::button::Button;
use super::dialog::Dialog;
use super::group::{Group, GroupLike};
use super::help_file::HelpFile;
use super::input_line::InputLine;
use super::label::Label;
use super::listbox::ListBox;
use super::static_text::StaticText;
use super::window::{Window, WindowLike};
use crate::core::command::{CM_CANCEL, CM_OK};
use crate::core::event::{Event, EventType};
use crate::core::geometry::Rect;
use std::cell::RefCell;
use std::rc::Rc;
const CMD_TOPIC_SELECTED: u16 = 1002;
pub struct HelpIndex {
dialog: Dialog,
_help_file: Rc<RefCell<HelpFile>>,
#[allow(dead_code)]
all_topics: Vec<(String, String)>, filtered_topics: Vec<(String, String)>,
_search_input_id: ViewId,
_topic_list_id: ViewId,
selected_topic: Option<String>,
}
impl HelpIndex {
pub fn new(bounds: Rect, title: &str, help_file: Rc<RefCell<HelpFile>>) -> Self {
let mut dialog = Dialog::new(bounds, title);
dialog.add(StaticText::new(
Rect::new(2, 2, bounds.width() - 4, 3),
"Search for a topic:",
));
let search_label = Label::new(Rect::new(2, 4, 10, 5), "Search:");
dialog.add(search_label);
let search_input = InputLine::new(Rect::new(10, 4, bounds.width() - 4, 5), 100);
let search_input_id = dialog.add(search_input);
let list_label = Label::new(Rect::new(2, 6, 12, 7), "Topics:");
dialog.add(list_label);
let topic_list = ListBox::new(
Rect::new(2, 7, bounds.width() - 4, bounds.height() - 6),
CMD_TOPIC_SELECTED,
);
let topic_list_id = dialog.add(topic_list);
dialog.add(Button::new(
Rect::new(
bounds.width() - 24,
bounds.height() - 4,
bounds.width() - 14,
bounds.height() - 2,
),
"View",
CM_OK,
true,
));
dialog.add(Button::new(
Rect::new(
bounds.width() - 12,
bounds.height() - 4,
bounds.width() - 2,
bounds.height() - 2,
),
"Close",
CM_CANCEL,
false,
));
let help = help_file.borrow();
let topic_ids = help.get_topic_ids();
let mut all_topics = Vec::new();
for id in topic_ids {
if let Some(topic) = help.get_topic(&id) {
all_topics.push((id.clone(), topic.title.clone()));
}
}
drop(help);
all_topics.sort_by(|a, b| a.1.cmp(&b.1));
let filtered_topics = all_topics.clone();
let mut index = Self {
dialog,
_help_file: help_file,
all_topics,
filtered_topics,
_search_input_id: search_input_id,
_topic_list_id: topic_list_id,
selected_topic: None,
};
index.update_topic_list();
index
}
fn update_topic_list(&mut self) {
let _topic_titles: Vec<String> = self
.filtered_topics
.iter()
.map(|(_, title)| title.clone())
.collect();
}
#[allow(dead_code)]
fn filter_topics(&mut self, search_text: &str) {
if search_text.is_empty() {
self.filtered_topics = self.all_topics.clone();
} else {
let search_lower = search_text.to_lowercase();
self.filtered_topics = self
.all_topics
.iter()
.filter(|(id, title)| {
title.to_lowercase().contains(&search_lower)
|| id.to_lowercase().contains(&search_lower)
})
.cloned()
.collect();
}
self.update_topic_list();
}
pub fn execute(&mut self, app: &mut crate::app::Application) -> Option<String> {
let result = self.dialog.execute(app);
if result == CM_OK && !self.filtered_topics.is_empty() {
Some(self.filtered_topics[0].0.clone())
} else {
None
}
}
pub fn get_selected_topic(&self) -> Option<String> {
self.selected_topic.clone()
}
}
impl GroupLike for HelpIndex {
fn group(&self) -> &Group {
self.dialog.group()
}
fn group_mut(&mut self) -> &mut Group {
self.dialog.group_mut()
}
}
impl WindowLike for HelpIndex {
fn window(&self) -> &Window {
self.dialog.window()
}
fn window_mut(&mut self) -> &mut Window {
self.dialog.window_mut()
}
}
crate::impl_view_for_window!(HelpIndex {
fn handle_event(&mut self, event: &mut Event) {
if event.what == EventType::Command && event.command == CMD_TOPIC_SELECTED {
*event = Event::command(CM_OK);
}
self.dialog.handle_event(event);
}
fn get_palette(&self) -> Option<crate::core::palette::Palette> {
self.dialog.get_palette()
}
fn valid(&mut self, command: crate::core::command::CommandId) -> bool {
self.dialog.valid(command)
}
});
pub struct HelpIndexBuilder {
bounds: Option<Rect>,
title: Option<String>,
help_file: Option<Rc<RefCell<HelpFile>>>,
}
impl HelpIndexBuilder {
pub fn new() -> Self {
Self {
bounds: None,
title: None,
help_file: None,
}
}
#[must_use]
pub fn bounds(mut self, bounds: Rect) -> Self {
self.bounds = Some(bounds);
self
}
#[must_use]
pub fn title(mut self, title: impl Into<String>) -> Self {
self.title = Some(title.into());
self
}
#[must_use]
pub fn help_file(mut self, help_file: Rc<RefCell<HelpFile>>) -> Self {
self.help_file = Some(help_file);
self
}
pub fn build(self) -> HelpIndex {
let bounds = self.bounds.expect("HelpIndex bounds must be set");
let title = self.title.expect("HelpIndex title must be set");
let help_file = self.help_file.expect("HelpIndex help_file must be set");
HelpIndex::new(bounds, &title, help_file)
}
pub fn build_boxed(self) -> Box<HelpIndex> {
Box::new(self.build())
}
}
impl Default for HelpIndexBuilder {
fn default() -> Self {
Self::new()
}
}