#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(dead_code)]
use crate::ported::colorspanel::ColorsPanel_new;
use crate::ported::crt::{KEY_CTRL, KEY_DOWN, KEY_END, KEY_HOME, KEY_NPAGE, KEY_PPAGE, KEY_UP};
use crate::ported::displayoptionspanel::DisplayOptionsPanel_new;
use crate::ported::functionbar::FunctionBar_new;
use crate::ported::header::Header;
use crate::ported::headeroptionspanel::HeaderOptionsPanel_new;
use crate::ported::listitem::ListItem_new;
use crate::ported::machine::Machine;
use crate::ported::panel::{
HandlerResult, Panel, PanelClass, Panel_add, Panel_getSelectedIndex, Panel_new, Panel_onKey,
Panel_selectByTyping, Panel_setHeader, EVENT_SET_SELECTED,
};
use crate::ported::screenmanager::{
ScreenManager, ScreenManager_add, ScreenManager_remove, ScreenManager_size,
};
use crate::ported::screenspanel::ScreensPanel_new;
use crate::ported::settings::Settings;
const CTRL_P: i32 = KEY_CTRL(b'P' as i32);
const CTRL_N: i32 = KEY_CTRL(b'N' as i32);
static CategoriesFunctions: [&str; 10] = [
" ", " ", " ", " ", " ", " ", " ", " ", " ",
"Done ",
];
pub struct CategoriesPanel {
pub super_: Panel,
pub scr: *mut ScreenManager,
pub host: *mut Machine,
pub header: *mut Header,
}
impl PanelClass for CategoriesPanel {
fn as_panel(&self) -> &Panel {
&self.super_
}
fn as_panel_mut(&mut self) -> &mut Panel {
&mut self.super_
}
fn event_handler(&mut self, ev: i32) -> HandlerResult {
CategoriesPanel_eventHandler(self, ev)
}
}
type CategoriesPanel_makePageFunc = fn(&mut CategoriesPanel);
struct CategoriesPanelPage {
name: &'static str,
ctor: CategoriesPanel_makePageFunc,
}
static categoriesPanelPages: [CategoriesPanelPage; 5] = [
CategoriesPanelPage {
name: "Display options",
ctor: CategoriesPanel_makeDisplayOptionsPage,
},
CategoriesPanelPage {
name: "Header layout",
ctor: CategoriesPanel_makeHeaderOptionsPage,
},
CategoriesPanelPage {
name: "Meters",
ctor: CategoriesPanel_makeMetersPage,
},
CategoriesPanelPage {
name: "Screens",
ctor: CategoriesPanel_makeScreensPage,
},
CategoriesPanelPage {
name: "Colors",
ctor: CategoriesPanel_makeColorsPage,
},
];
pub fn CategoriesPanel_delete(this: CategoriesPanel) {
let CategoriesPanel { super_, .. } = this;
crate::ported::panel::Panel_done(super_);
}
impl CategoriesPanel {
fn host_settings(&self) -> *mut Settings {
unsafe {
let h = &mut *self.host;
h.settings
.as_mut()
.expect("CategoriesPanel: host->settings is NULL") as *mut Settings
}
}
}
pub fn CategoriesPanel_makeMetersPage(this: &mut CategoriesPanel) {
let _ = this;
todo!("port of CategoriesPanel.c:43 — Header.columns is Vec<Vec<Meter>> (owned) but MetersPanel_new needs the shared Vector* meter store the header and panel co-own; no shared-ownership bridge")
}
pub fn CategoriesPanel_makeDisplayOptionsPage(this: &mut CategoriesPanel) {
let settings = this.host_settings();
let scr = this.scr;
let displayOptions = DisplayOptionsPanel_new(settings, scr);
ScreenManager_add(unsafe { &mut *scr }, Box::new(displayOptions), -1);
}
pub fn CategoriesPanel_makeColorsPage(this: &mut CategoriesPanel) {
let settings = this.host_settings();
let scr = this.scr;
let colors = ColorsPanel_new(settings);
ScreenManager_add(unsafe { &mut *scr }, Box::new(colors), -1);
}
pub fn CategoriesPanel_makeScreenTabsPage(this: &mut CategoriesPanel) {
let _ = this;
todo!("port of CategoriesPanel.c:78 — PCP-only; also needs to split the ScreenTabsPanel's owned `names` sub-panel into a separately ScreenManager_add-able panel (owned-sub-panel model can't)")
}
pub fn CategoriesPanel_makeScreensPage(this: &mut CategoriesPanel) {
let settings = this.host_settings();
let scr = this.scr;
let screens = ScreensPanel_new(settings, scr);
ScreenManager_add(unsafe { &mut *scr }, Box::new(screens), 20);
}
pub fn CategoriesPanel_makeHeaderOptionsPage(this: &mut CategoriesPanel) {
let settings = this.host_settings();
let scr = this.scr;
let headerOptions = HeaderOptionsPanel_new(settings, scr);
ScreenManager_add(unsafe { &mut *scr }, Box::new(headerOptions), -1);
}
pub fn CategoriesPanel_eventHandler(this: &mut CategoriesPanel, ch: i32) -> HandlerResult {
let mut result = HandlerResult::IGNORED;
let mut selected = Panel_getSelectedIndex(&this.super_);
match ch {
EVENT_SET_SELECTED => {
result = HandlerResult::HANDLED;
}
KEY_UP | CTRL_P | KEY_DOWN | CTRL_N | KEY_NPAGE | KEY_PPAGE | KEY_HOME | KEY_END => {
let previous = selected;
Panel_onKey(&mut this.super_, ch);
selected = Panel_getSelectedIndex(&this.super_);
if previous != selected {
result = HandlerResult::HANDLED;
}
}
_ => {
if 0 < ch && ch < 255 && (ch as u8).is_ascii_graphic() {
result = Panel_selectByTyping(&mut this.super_, ch);
}
if result == HandlerResult::BREAK_LOOP {
result = HandlerResult::IGNORED;
}
}
}
if result == HandlerResult::HANDLED {
{
let scr = unsafe { &mut *this.scr };
let size = ScreenManager_size(scr);
for _ in 1..size {
let _ = ScreenManager_remove(scr, 1);
}
}
if selected >= 0 && (selected as usize) < categoriesPanelPages.len() {
(categoriesPanelPages[selected as usize].ctor)(this);
}
}
result
}
pub fn CategoriesPanel_new(scr: *mut ScreenManager, header: *mut Header, host: *mut Machine) {
let fu_bar = FunctionBar_new(Some(&CategoriesFunctions[..]), None, None);
let super_ = Panel_new(1, 1, 1, 1, Some(fu_bar));
let mut this = Box::new(CategoriesPanel {
super_,
scr,
host,
header,
});
Panel_setHeader(&mut this.super_, "Categories");
for page in categoriesPanelPages.iter() {
Panel_add(&mut this.super_, Box::new(ListItem_new(page.name, 0)));
}
let self_ptr: *mut CategoriesPanel = this.as_mut();
ScreenManager_add(unsafe { &mut *scr }, this, 16);
(categoriesPanelPages[0].ctor)(unsafe { &mut *self_ptr });
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ported::action::State;
use crate::ported::listitem::ListItem;
use crate::ported::object::Object;
use crate::ported::panel::{Panel_add, Panel_new};
use crate::ported::screenmanager::ScreenManager_new;
use crate::ported::settings::{HeaderLayout, ScreenSettings};
fn categories_panel() -> Panel {
let mut p = Panel_new(1, 1, 20, 10, None);
for page in categoriesPanelPages.iter() {
let li: Box<dyn Object> = Box::new(ListItem::new_row(page.name));
Panel_add(&mut p, li);
}
p
}
impl ListItem {
fn new_row(value: &str) -> ListItem {
ListItem {
value: value.to_string(),
key: 0,
moving: false,
}
}
}
fn state() -> State {
State {
pauseUpdate: false,
hideSelection: false,
hideMeters: false,
host: core::ptr::null_mut(),
mainPanel: core::ptr::null_mut(),
header: core::ptr::null_mut(),
failedUpdate: None,
}
}
fn scr_wired() -> ScreenManager {
let header = crate::ported::header::Header {
host: core::ptr::null(),
columns: vec![Vec::new()],
headerLayout: HeaderLayout::HF_ONE_100,
pad: 0,
height: 0,
headerMargin: false,
screenTabs: false,
};
let header_raw = Box::into_raw(Box::new(header));
let state_raw = Box::into_raw(Box::new(state()));
let host_raw = Box::into_raw(Box::new(Machine::default()));
let mut scr = ScreenManager_new(header_raw, host_raw, state_raw);
scr.panelCount = 1;
scr.panels.push(Box::new(Panel_new(0, 0, 10, 5, None)));
scr
}
fn host_wired() -> Machine {
Machine {
existingCPUs: 1,
settings: Some(Settings {
hLayout: HeaderLayout::HF_ONE_100,
screens: vec![ScreenSettings {
heading: Some("Main".to_string()),
..Default::default()
}],
ssIndex: 0,
..Default::default()
}),
..Default::default()
}
}
fn cat_with(super_: Panel, scr: *mut ScreenManager, host: *mut Machine) -> CategoriesPanel {
CategoriesPanel {
super_,
scr,
host,
header: core::ptr::null_mut(),
}
}
#[test]
fn navigation_that_does_not_move_selection_is_ignored() {
let mut c = cat_with(
categories_panel(),
core::ptr::null_mut(),
core::ptr::null_mut(),
);
let r = CategoriesPanel_eventHandler(&mut c, KEY_UP);
assert_eq!(r, HandlerResult::IGNORED);
assert_eq!(Panel_getSelectedIndex(&c.super_), 0);
}
#[test]
fn q_on_empty_buffer_break_loop_is_downgraded_to_ignored() {
let mut c = cat_with(
categories_panel(),
core::ptr::null_mut(),
core::ptr::null_mut(),
);
let r = CategoriesPanel_eventHandler(&mut c, 'q' as i32);
assert_eq!(r, HandlerResult::IGNORED);
}
#[test]
fn nongraphic_non_navigation_char_is_ignored() {
let mut c = cat_with(
categories_panel(),
core::ptr::null_mut(),
core::ptr::null_mut(),
);
let r = CategoriesPanel_eventHandler(&mut c, KEY_CTRL(b'B' as i32));
assert_eq!(r, HandlerResult::IGNORED);
assert_eq!(Panel_getSelectedIndex(&c.super_), 0);
}
#[test]
fn event_set_selected_is_handled_and_builds_display_page() {
let mut scr = scr_wired();
let mut host = host_wired();
let mut c = cat_with(categories_panel(), &mut scr, &mut host);
let r = CategoriesPanel_eventHandler(&mut c, EVENT_SET_SELECTED);
assert_eq!(r, HandlerResult::HANDLED);
assert_eq!(scr.panelCount, 2, "the Display page was added");
}
#[test]
fn key_down_builds_header_page() {
let mut scr = scr_wired();
let mut host = host_wired();
let mut c = cat_with(categories_panel(), &mut scr, &mut host);
let r = CategoriesPanel_eventHandler(&mut c, KEY_DOWN);
assert_eq!(r, HandlerResult::HANDLED);
assert_eq!(Panel_getSelectedIndex(&c.super_), 1); assert_eq!(scr.panelCount, 2, "the Header page was added");
}
#[test]
fn ctrl_n_moves_selection_like_key_down() {
let mut scr = scr_wired();
let mut host = host_wired();
let mut c = cat_with(categories_panel(), &mut scr, &mut host);
let r = CategoriesPanel_eventHandler(&mut c, CTRL_N);
assert_eq!(r, HandlerResult::HANDLED);
assert_eq!(Panel_getSelectedIndex(&c.super_), 1);
}
#[test]
fn key_end_then_home_rebuilds_and_removes_prior_page() {
let mut scr = scr_wired();
let mut host = host_wired();
let mut c = cat_with(categories_panel(), &mut scr, &mut host);
let r = CategoriesPanel_eventHandler(&mut c, KEY_END);
assert_eq!(r, HandlerResult::HANDLED);
assert_eq!(Panel_getSelectedIndex(&c.super_), 4);
assert_eq!(scr.panelCount, 2);
let r = CategoriesPanel_eventHandler(&mut c, KEY_HOME);
assert_eq!(r, HandlerResult::HANDLED);
assert_eq!(Panel_getSelectedIndex(&c.super_), 0);
assert_eq!(scr.panelCount, 2);
}
#[test]
fn graphic_char_type_selects_header_and_builds_it() {
let mut scr = scr_wired();
let mut host = host_wired();
let mut c = cat_with(categories_panel(), &mut scr, &mut host);
let r = CategoriesPanel_eventHandler(&mut c, 'H' as i32);
assert_eq!(r, HandlerResult::HANDLED);
assert_eq!(Panel_getSelectedIndex(&c.super_), 1);
assert_eq!(scr.panelCount, 2);
}
#[test]
fn graphic_char_with_no_match_is_still_handled_and_rebuilds() {
let mut scr = scr_wired();
let mut host = host_wired();
let mut c = cat_with(categories_panel(), &mut scr, &mut host);
let r = CategoriesPanel_eventHandler(&mut c, 'z' as i32);
assert_eq!(r, HandlerResult::HANDLED);
assert_eq!(Panel_getSelectedIndex(&c.super_), 0);
assert_eq!(scr.panelCount, 2);
}
}