use ratatui::layout::Rect;
use tuiserial_core::FocusedField;
#[derive(Debug, Clone, Copy)]
pub struct UiAreas {
pub menu_bar: Rect,
pub port: Rect,
pub baud_rate: Rect,
pub data_bits: Rect,
pub parity: Rect,
pub stop_bits: Rect,
pub flow_control: Rect,
pub status_panel: Rect,
pub log_area: Rect,
pub tx_area: Rect,
pub control_area: Rect,
pub notification_area: Rect,
pub shortcuts_hint: Rect,
pub tab_bar: Rect,
}
impl Default for UiAreas {
fn default() -> Self {
Self {
menu_bar: Rect::default(),
port: Rect::default(),
baud_rate: Rect::default(),
data_bits: Rect::default(),
parity: Rect::default(),
stop_bits: Rect::default(),
flow_control: Rect::default(),
status_panel: Rect::default(),
log_area: Rect::default(),
tx_area: Rect::default(),
control_area: Rect::default(),
notification_area: Rect::default(),
shortcuts_hint: Rect::default(),
tab_bar: Rect::default(),
}
}
}
static mut UI_AREAS: UiAreas = UiAreas {
menu_bar: Rect {
x: 0,
y: 0,
width: 0,
height: 0,
},
port: Rect {
x: 0,
y: 0,
width: 0,
height: 0,
},
baud_rate: Rect {
x: 0,
y: 0,
width: 0,
height: 0,
},
data_bits: Rect {
x: 0,
y: 0,
width: 0,
height: 0,
},
parity: Rect {
x: 0,
y: 0,
width: 0,
height: 0,
},
stop_bits: Rect {
x: 0,
y: 0,
width: 0,
height: 0,
},
flow_control: Rect {
x: 0,
y: 0,
width: 0,
height: 0,
},
status_panel: Rect {
x: 0,
y: 0,
width: 0,
height: 0,
},
log_area: Rect {
x: 0,
y: 0,
width: 0,
height: 0,
},
tx_area: Rect {
x: 0,
y: 0,
width: 0,
height: 0,
},
control_area: Rect {
x: 0,
y: 0,
width: 0,
height: 0,
},
notification_area: Rect {
x: 0,
y: 0,
width: 0,
height: 0,
},
shortcuts_hint: Rect {
x: 0,
y: 0,
width: 0,
height: 0,
},
tab_bar: Rect {
x: 0,
y: 0,
width: 0,
height: 0,
},
};
pub fn get_ui_areas() -> UiAreas {
unsafe { UI_AREAS }
}
#[allow(dead_code)]
pub fn update_ui_areas(areas: UiAreas) {
unsafe {
UI_AREAS = areas;
}
}
pub fn update_area(field: UiAreaField, rect: Rect) {
unsafe {
match field {
UiAreaField::MenuBar => UI_AREAS.menu_bar = rect,
UiAreaField::Port => UI_AREAS.port = rect,
UiAreaField::BaudRate => UI_AREAS.baud_rate = rect,
UiAreaField::DataBits => UI_AREAS.data_bits = rect,
UiAreaField::Parity => UI_AREAS.parity = rect,
UiAreaField::StopBits => UI_AREAS.stop_bits = rect,
UiAreaField::FlowControl => UI_AREAS.flow_control = rect,
UiAreaField::StatusPanel => UI_AREAS.status_panel = rect,
UiAreaField::LogArea => UI_AREAS.log_area = rect,
UiAreaField::TxArea => UI_AREAS.tx_area = rect,
UiAreaField::ControlArea => UI_AREAS.control_area = rect,
UiAreaField::NotificationArea => UI_AREAS.notification_area = rect,
UiAreaField::ShortcutsHint => UI_AREAS.shortcuts_hint = rect,
UiAreaField::TabBar => UI_AREAS.tab_bar = rect,
}
}
}
pub enum UiAreaField {
MenuBar,
Port,
BaudRate,
DataBits,
Parity,
StopBits,
FlowControl,
StatusPanel,
LogArea,
TxArea,
ControlArea,
NotificationArea,
ShortcutsHint,
#[allow(dead_code)]
TabBar,
}
pub fn is_inside(rect: Rect, x: u16, y: u16) -> bool {
x >= rect.x && x < rect.x + rect.width && y >= rect.y && y < rect.y + rect.height
}
pub fn get_clicked_field(x: u16, y: u16) -> Option<FocusedField> {
let areas = get_ui_areas();
if is_inside(areas.port, x, y) {
Some(FocusedField::Port)
} else if is_inside(areas.baud_rate, x, y) {
Some(FocusedField::BaudRate)
} else if is_inside(areas.data_bits, x, y) {
Some(FocusedField::DataBits)
} else if is_inside(areas.parity, x, y) {
Some(FocusedField::Parity)
} else if is_inside(areas.stop_bits, x, y) {
Some(FocusedField::StopBits)
} else if is_inside(areas.flow_control, x, y) {
Some(FocusedField::FlowControl)
} else if is_inside(areas.log_area, x, y) {
Some(FocusedField::LogArea)
} else if is_inside(areas.tx_area, x, y) {
Some(FocusedField::TxInput)
} else {
None
}
}
pub fn get_clicked_menu(x: u16, y: u16) -> Option<usize> {
let areas = get_ui_areas();
if !is_inside(areas.menu_bar, x, y) {
return None;
}
let relative_x = x.saturating_sub(areas.menu_bar.x);
if relative_x < 7 {
Some(0) } else if relative_x >= 8 && relative_x < 17 {
Some(1) } else if relative_x >= 18 && relative_x < 25 {
Some(2) } else if relative_x >= 26 && relative_x < 36 {
Some(3) } else if relative_x >= 37 && relative_x < 43 {
Some(4) } else {
None
}
}
pub fn is_shortcuts_hint_clicked(x: u16, y: u16) -> bool {
let areas = get_ui_areas();
is_inside(areas.shortcuts_hint, x, y)
}
pub fn get_clicked_tab(x: u16, y: u16, tab_count: usize) -> Option<usize> {
let areas = get_ui_areas();
if !is_inside(areas.tab_bar, x, y) || tab_count == 0 {
return None;
}
let width = areas.tab_bar.width;
if width == 0 {
return None;
}
let relative_x = x.saturating_sub(areas.tab_bar.x);
let mut tab_index = (relative_x as usize * tab_count) / width as usize;
if tab_index >= tab_count {
tab_index = tab_count - 1;
}
Some(tab_index)
}