notedeck

One damus client to rule them all
git clone git://jb55.com/notedeck
Log | Files | Refs | README | LICENSE

host_picker.rs (5273B)


      1 use crate::ui::keybind_hint::paint_keybind_hint;
      2 use egui::{RichText, Vec2};
      3 
      4 /// Actions from the host picker overlay.
      5 #[derive(Debug, Clone)]
      6 pub enum HostPickerAction {
      7     /// User picked a host. `None` = local, `Some(hostname)` = remote.
      8     HostSelected(Option<String>),
      9     /// User cancelled.
     10     Cancelled,
     11 }
     12 
     13 /// Render the host picker as a full-panel overlay.
     14 ///
     15 /// `known_hosts` should contain all remote hostnames (not the local one).
     16 /// The local machine is always shown as the first option.
     17 pub fn host_picker_overlay_ui(
     18     ui: &mut egui::Ui,
     19     local_hostname: &str,
     20     known_hosts: &[String],
     21     has_sessions: bool,
     22 ) -> Option<HostPickerAction> {
     23     let mut action = None;
     24     let is_narrow = notedeck::ui::is_narrow(ui.ctx());
     25     let ctrl_held = ui.input(|i| i.modifiers.ctrl);
     26 
     27     // Keyboard shortcuts: Ctrl+1 = local, Ctrl+2..9 = remote hosts
     28     if ctrl_held {
     29         if ui.input(|i| i.key_pressed(egui::Key::Num1)) {
     30             return Some(HostPickerAction::HostSelected(None));
     31         }
     32         for (idx, host) in known_hosts.iter().take(8).enumerate() {
     33             let key = match idx {
     34                 0 => egui::Key::Num2,
     35                 1 => egui::Key::Num3,
     36                 2 => egui::Key::Num4,
     37                 3 => egui::Key::Num5,
     38                 4 => egui::Key::Num6,
     39                 5 => egui::Key::Num7,
     40                 6 => egui::Key::Num8,
     41                 7 => egui::Key::Num9,
     42                 _ => continue,
     43             };
     44             if ui.input(|i| i.key_pressed(key)) {
     45                 return Some(HostPickerAction::HostSelected(Some(host.clone())));
     46             }
     47         }
     48     }
     49 
     50     egui::Frame::new()
     51         .fill(ui.visuals().panel_fill)
     52         .inner_margin(egui::Margin::symmetric(if is_narrow { 16 } else { 40 }, 20))
     53         .show(ui, |ui| {
     54             // Header
     55             ui.horizontal(|ui| {
     56                 if has_sessions {
     57                     if ui.button("< Back").clicked() {
     58                         action = Some(HostPickerAction::Cancelled);
     59                     }
     60                     ui.add_space(16.0);
     61                 }
     62                 ui.heading("Select Host");
     63             });
     64 
     65             ui.add_space(16.0);
     66 
     67             let max_content_width = if is_narrow {
     68                 ui.available_width()
     69             } else {
     70                 500.0
     71             };
     72             let available_height = ui.available_height();
     73 
     74             ui.allocate_ui_with_layout(
     75                 egui::vec2(max_content_width, available_height),
     76                 egui::Layout::top_down(egui::Align::LEFT),
     77                 |ui| {
     78                     let button_height = if is_narrow { 44.0 } else { 32.0 };
     79                     let hint_width = if ctrl_held { 24.0 } else { 0.0 };
     80                     let button_width = ui.available_width() - hint_width - 4.0;
     81 
     82                     // Local option
     83                     ui.horizontal(|ui| {
     84                         let button = egui::Button::new(
     85                             RichText::new(format!("{} (local)", local_hostname)).monospace(),
     86                         )
     87                         .min_size(Vec2::new(button_width, button_height))
     88                         .fill(ui.visuals().widgets.inactive.weak_bg_fill);
     89 
     90                         let response = ui.add(button);
     91 
     92                         if ctrl_held {
     93                             let hint_center = response.rect.right_center()
     94                                 + egui::vec2(hint_width / 2.0 + 2.0, 0.0);
     95                             paint_keybind_hint(ui, hint_center, "1", 18.0);
     96                         }
     97 
     98                         if response.clicked() {
     99                             action = Some(HostPickerAction::HostSelected(None));
    100                         }
    101                     });
    102 
    103                     ui.add_space(4.0);
    104 
    105                     // Remote hosts
    106                     for (idx, host) in known_hosts.iter().enumerate() {
    107                         ui.horizontal(|ui| {
    108                             let button =
    109                                 egui::Button::new(RichText::new(host.as_str()).monospace())
    110                                     .min_size(Vec2::new(button_width, button_height))
    111                                     .fill(ui.visuals().widgets.inactive.weak_bg_fill);
    112 
    113                             let response = ui.add(button);
    114 
    115                             if ctrl_held && idx < 8 {
    116                                 let hint_text = format!("{}", idx + 2);
    117                                 let hint_center = response.rect.right_center()
    118                                     + egui::vec2(hint_width / 2.0 + 2.0, 0.0);
    119                                 paint_keybind_hint(ui, hint_center, &hint_text, 18.0);
    120                             }
    121 
    122                             if response.clicked() {
    123                                 action = Some(HostPickerAction::HostSelected(Some(host.clone())));
    124                             }
    125                         });
    126 
    127                         ui.add_space(4.0);
    128                     }
    129                 },
    130             );
    131         });
    132 
    133     // Escape to cancel
    134     if has_sessions
    135         && ui
    136             .ctx()
    137             .input_mut(|i| i.consume_key(egui::Modifiers::NONE, egui::Key::Escape))
    138     {
    139         action = Some(HostPickerAction::Cancelled);
    140     }
    141 
    142     action
    143 }