enum MenuLine {
Blank,
Key(MenuKeypressLine),
+ Info(CentredInfoLine),
}
fn find_substring(haystack: &str, needle: &str)
title: FileHeader,
status: FileStatusLineFinal,
lines: Vec<MenuLine>,
+ bottom_lines: Vec<MenuLine>,
actions: HashMap<OurKey, LogicalAction>,
}
title: FileHeader::new(title),
status: status.finalise(),
lines: Vec::new(),
+ bottom_lines: Vec::new(),
actions: HashMap::new(),
};
self.lines.push(MenuLine::Blank);
}
+ fn add_info_coloured(&mut self, desc: ColouredString) {
+ self.bottom_lines.push(MenuLine::Info(CentredInfoLine::new(desc)));
+ }
+ fn add_info(&mut self, desc: &str) {
+ self.add_info_coloured(ColouredString::uniform(desc, 'H'));
+ }
+
fn finalise(mut self) -> Self {
let mut lmaxwid = 0;
let mut rmaxwid = 0;
lines.extend_from_slice(&match line {
MenuLine::Blank => BlankLine::render_static(),
MenuLine::Key(mk) => mk.render(w),
+ MenuLine::Info(cl) => cl.render(w),
+ });
+ }
+
+ while lines.len() + 2 + self.bottom_lines.len() < h {
+ lines.extend_from_slice(&BlankLine::render_static());
+ }
+
+ for line in &self.bottom_lines {
+ lines.extend_from_slice(&match line {
+ MenuLine::Blank => BlankLine::render_static(),
+ MenuLine::Key(mk) => mk.render(w),
+ MenuLine::Info(cl) => cl.render(w),
});
}
}
}
-pub fn main_menu() -> Box<dyn ActivityState> {
+pub fn main_menu(client: &Client) -> Box<dyn ActivityState> {
let mut menu = Menu::new(
ColouredString::uniform("Mastodonochrome Main Menu", 'H'), true);
// anywhere.
menu.add_action(Escape, "Utilities and Exit", LogicalAction::Nothing);
+ menu.add_info(&format!("Logged in as {}", &client.our_account_fq()));
+
Box::new(menu.finalise())
}
});
}
+pub struct CentredInfoLine {
+ text: ColouredString,
+}
+
+impl CentredInfoLine {
+ pub fn new(text: ColouredString) -> Self {
+ CentredInfoLine {
+ text,
+ }
+ }
+}
+
+impl TextFragment for CentredInfoLine {
+ fn render_highlighted(&self, width: usize, _highlight: Option<Highlight>)
+ -> Vec<ColouredString>
+ {
+ let twidth = width.saturating_sub(1);
+ let title = self.text.truncate(twidth);
+ let tspace = twidth - title.width();
+ let tleft = tspace / 2;
+ let textpad = ColouredString::plain(" ").repeat(tleft) + &self.text;
+ vec! { textpad }
+ }
+}
+
pub struct StatusDisplay {
sep: SeparatorLine,
from: UsernameHeader,
let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?;
terminal.clear()?;
+ let state = TuiLogicalState::new(&client);
+
let mut tui = Tui {
terminal,
subthread_sender: sender,
subthread_receiver: receiver,
- state: TuiLogicalState::new(),
+ state,
client,
};
}
impl TuiLogicalState {
- fn new() -> Self {
+ fn new(client: &Client) -> Self {
let activity_stack = ActivityStack::new();
- // It would be nice to construct this by calling
- // new_activity_state, but we don't have a &mut Client to give
- // it, and in this case we know we don't need one.
- let activity_state = main_menu();
+ let activity_state = main_menu(client);
TuiLogicalState {
activity_stack,
{
let result = match activity {
Activity::NonUtil(NonUtilityActivity::MainMenu) =>
- Ok(main_menu()),
+ Ok(main_menu(client)),
Activity::Util(UtilityActivity::UtilsMenu) =>
Ok(utils_menu(client)),
Activity::Util(UtilityActivity::ExitMenu) =>