#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(dead_code)]
use core::any::Any;
use std::io::{self, Write};
use crate::ported::cpumeter::CPUMeter_class;
use crate::ported::crt::{KEY_ENTER, KEY_F, KEY_LEFT, KEY_RECLICK};
use crate::ported::functionbar::FunctionBar_new;
use crate::ported::header::{
Header, Header_addMeterByClass, Header_calculateHeight, Header_draw, Header_updateData,
};
use crate::ported::listitem::{ListItem, ListItem_new};
use crate::ported::machine::Machine;
use crate::ported::meter::{MeterClass, Meter_toListItem};
use crate::ported::meterspanel::MetersPanel;
use crate::ported::dynamicmeter::DynamicMeter;
use crate::ported::hashtable::Hashtable_foreach;
use crate::ported::panel::{
HandlerResult, Panel, PanelClass, Panel_add, Panel_done, Panel_getSelected, Panel_new,
Panel_setHeader, Panel_setSelected, Panel_size,
};
use crate::ported::settings::Settings;
use crate::ported::screenmanager::{ScreenManager, ScreenManager_resize};
#[cfg(target_os = "macos")]
use crate::ported::darwin::platform::Platform_meterTypes;
#[cfg(not(target_os = "macos"))]
use crate::ported::linux::platform::Platform_meterTypes;
static AvailableMetersFunctions: [&str; 10] = [
" ", " ", " ", " ", "Add Lt", "Add Rt", " ", " ", " ",
"Done ",
];
pub struct AvailableMetersPanel {
pub super_: Panel,
pub scr: *mut ScreenManager,
pub host: *mut Machine,
pub header: *mut Header,
pub columns: usize,
pub meterPanels: Vec<*mut MetersPanel>,
}
impl PanelClass for AvailableMetersPanel {
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 {
AvailableMetersPanel_eventHandler(self, ev)
}
}
pub fn AvailableMetersPanel_delete(this: AvailableMetersPanel) {
let AvailableMetersPanel {
super_,
meterPanels,
..
} = this;
let _ = meterPanels;
Panel_done(super_);
}
pub fn AvailableMetersPanel_addMeter(
header: &mut Header,
panel: &mut MetersPanel,
type_: &'static MeterClass,
param: u32,
column: usize,
) {
let meter = Header_addMeterByClass(header, type_, param, column);
let item = Meter_toListItem(meter, false);
Panel_add(&mut panel.super_, Box::new(item));
let size = Panel_size(&panel.super_);
Panel_setSelected(&mut panel.super_, size - 1);
}
pub fn AvailableMetersPanel_eventHandler(
this: &mut AvailableMetersPanel,
ch: i32,
) -> HandlerResult {
const KEY_F5: i32 = KEY_F(5);
const KEY_F6: i32 = KEY_F(6);
const L_LOWER: i32 = b'l' as i32;
const L_UPPER: i32 = b'L' as i32;
const R_LOWER: i32 = b'r' as i32;
const R_UPPER: i32 = b'R' as i32;
let key = match Panel_getSelected(&this.super_) {
None => return HandlerResult::IGNORED,
Some(obj) => {
let any: &dyn Any = obj;
any.downcast_ref::<ListItem>()
.expect("AvailableMetersPanel_eventHandler: selected row is not a ListItem")
.key
}
};
let param = (key & 0xffff) as u32;
let type_idx = (key >> 16) as usize;
let mut result = HandlerResult::IGNORED;
let mut update = false;
match ch {
KEY_F5 | L_LOWER | L_UPPER => {
let type_ = Platform_meterTypes[type_idx];
let header = unsafe { &mut *this.header };
let panel = unsafe { &mut *this.meterPanels[0] };
AvailableMetersPanel_addMeter(header, panel, type_, param, 0);
result = HandlerResult::HANDLED;
update = true;
}
0x0a | 0x0d | KEY_ENTER | KEY_F6 | R_LOWER | R_UPPER | KEY_RECLICK => {
let type_ = Platform_meterTypes[type_idx];
let column = this.columns - 1;
let header = unsafe { &mut *this.header };
let panel = unsafe { &mut *this.meterPanels[column] };
AvailableMetersPanel_addMeter(header, panel, type_, param, column);
result = HandlerResult(((KEY_LEFT as u32) << 16) | HandlerResult::SYNTH_KEY.0);
update = true;
}
_ => {}
}
if update {
{
let settings = unsafe { (*this.host).settings.as_mut() }
.expect("AvailableMetersPanel_eventHandler: host->settings is NULL");
settings.changed = true;
settings.lastUpdate += 1;
}
{
let header = unsafe { &mut *this.header };
Header_calculateHeight(header);
Header_updateData(header);
let mut out = io::stdout().lock();
Header_draw(header, &mut out);
let _ = out.flush();
}
let scr = unsafe { &mut *this.scr };
ScreenManager_resize(scr);
}
result
}
pub fn AvailableMetersPanel_addCPUMeters(super_: &mut Panel, type_: &MeterClass, host: &Machine) {
if host.existingCPUs > 1 {
Panel_add(super_, Box::new(ListItem_new("CPU average", 0)));
let count_from_one = host
.settings
.as_ref()
.expect("AvailableMetersPanel_addCPUMeters: Machine.settings is set")
.countCPUsFromOne;
for i in 1..=host.existingCPUs {
let cpu = i - 1;
let cpu_id = if count_from_one { cpu + 1 } else { cpu };
let buffer = format!("{} {}", type_.uiName, cpu_id);
Panel_add(super_, Box::new(ListItem_new(&buffer, i as i32)));
}
} else {
Panel_add(super_, Box::new(ListItem_new(type_.uiName, 1)));
}
}
pub fn AvailableMetersPanel_addDynamicMeter(
meter: &DynamicMeter,
identifier: u32,
super_: &mut Panel,
) {
let label = meter
.description
.as_deref()
.or(meter.caption.as_deref())
.unwrap_or(&meter.name);
Panel_add(super_, Box::new(ListItem_new(label, identifier as i32)));
}
pub fn AvailableMetersPanel_addDynamicMeters(super_: &mut Panel, settings: &Settings, offset: u32) {
let dynamic_meters = settings
.dynamicMeters
.expect("AvailableMetersPanel_addDynamicMeters: dynamicMeters is NULL");
let mut id: u32 = 1;
Hashtable_foreach(unsafe { &*dynamic_meters }, &mut |_key, value| {
let any: &dyn core::any::Any = value;
let meter = any
.downcast_ref::<DynamicMeter>()
.expect("AvailableMetersPanel_addDynamicMeters: hashtable value is not a DynamicMeter");
let identifier = (offset << 16) | id;
AvailableMetersPanel_addDynamicMeter(meter, identifier, super_);
id += 1;
});
}
pub fn AvailableMetersPanel_addPlatformMeter(super_: &mut Panel, type_: &MeterClass, offset: u32) {
let label = type_.description.unwrap_or(type_.uiName);
Panel_add(super_, Box::new(ListItem_new(label, (offset << 16) as i32)));
}
pub fn AvailableMetersPanel_new(
host: *mut Machine,
header: *mut Header,
columns: usize,
meterPanels: Vec<*mut MetersPanel>,
scr: *mut ScreenManager,
) -> AvailableMetersPanel {
let fu_bar = FunctionBar_new(Some(&AvailableMetersFunctions[..]), None, None);
let super_ = Panel_new(1, 1, 1, 1, Some(fu_bar));
let mut this = AvailableMetersPanel {
super_,
scr,
host,
header,
columns,
meterPanels,
};
Panel_setHeader(&mut this.super_, "Available meters");
for i in 1..Platform_meterTypes.len() {
let type_ = Platform_meterTypes[i];
AvailableMetersPanel_addPlatformMeter(&mut this.super_, type_, i as u32);
}
let host_ref = unsafe { &*host };
AvailableMetersPanel_addCPUMeters(&mut this.super_, &CPUMeter_class, host_ref);
this
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ported::listitem::ListItem;
use crate::ported::object::{ObjectClass, Object_class};
use crate::ported::panel::{Panel_get, Panel_new, Panel_size};
fn mk_class(uiName: &'static str, description: Option<&'static str>) -> MeterClass {
MeterClass {
super_: ObjectClass {
extends: Some(&Object_class),
},
display: None,
init: None,
done: None,
updateMode: None,
updateValues: None,
draw: None,
getCaption: None,
getUiName: None,
defaultMode: 0,
supportedModes: 0,
total: 0.0,
attributes: &[],
name: "",
uiName,
caption: "",
description,
maxItems: 0,
isMultiColumn: false,
isPercentChart: false,
}
}
fn row(panel: &Panel, i: i32) -> &ListItem {
let any: &dyn core::any::Any = Panel_get(panel, i);
any.downcast_ref::<ListItem>()
.expect("addPlatformMeter row is not a ListItem")
}
#[test]
fn add_platform_meter_uses_description_when_present() {
let mut panel = Panel_new(1, 1, 1, 1, None);
let class = mk_class("Uptime", Some("System uptime"));
AvailableMetersPanel_addPlatformMeter(&mut panel, &class, 3);
assert_eq!(Panel_size(&panel), 1);
let item = row(&panel, 0);
assert_eq!(item.value, "System uptime");
assert_eq!(item.key, 3 << 16);
}
#[test]
fn add_platform_meter_falls_back_to_ui_name() {
let mut panel = Panel_new(1, 1, 1, 1, None);
let class = mk_class("Hostname", None);
AvailableMetersPanel_addPlatformMeter(&mut panel, &class, 7);
assert_eq!(Panel_size(&panel), 1);
let item = row(&panel, 0);
assert_eq!(item.value, "Hostname");
assert_eq!(item.key, 7 << 16);
}
use crate::ported::settings::Settings;
#[test]
fn add_cpu_meters_single_cpu_adds_one_row() {
let mut panel = Panel_new(1, 1, 1, 1, None);
let class = mk_class("CPU", None);
let host = Machine {
existingCPUs: 1,
..Default::default()
};
AvailableMetersPanel_addCPUMeters(&mut panel, &class, &host);
assert_eq!(Panel_size(&panel), 1);
assert_eq!(row(&panel, 0).value, "CPU");
assert_eq!(row(&panel, 0).key, 1);
}
#[test]
fn add_cpu_meters_multi_cpu_average_plus_per_cpu() {
let mut panel = Panel_new(1, 1, 1, 1, None);
let class = mk_class("CPU", None);
let host = Machine {
existingCPUs: 3,
settings: Some(Settings::default()), ..Default::default()
};
AvailableMetersPanel_addCPUMeters(&mut panel, &class, &host);
assert_eq!(Panel_size(&panel), 4);
assert_eq!(row(&panel, 0).value, "CPU average");
assert_eq!(row(&panel, 0).key, 0);
assert_eq!(row(&panel, 1).value, "CPU 0");
assert_eq!(row(&panel, 1).key, 1);
assert_eq!(row(&panel, 3).value, "CPU 2");
assert_eq!(row(&panel, 3).key, 3);
}
#[test]
fn add_cpu_meters_count_from_one_shifts_labels() {
let mut panel = Panel_new(1, 1, 1, 1, None);
let class = mk_class("CPU", None);
let settings = Settings {
countCPUsFromOne: true,
..Default::default()
};
let host = Machine {
existingCPUs: 2,
settings: Some(settings),
..Default::default()
};
AvailableMetersPanel_addCPUMeters(&mut panel, &class, &host);
assert_eq!(row(&panel, 1).value, "CPU 1"); assert_eq!(row(&panel, 2).value, "CPU 2"); }
#[test]
fn new_builds_platform_rows_then_cpu_rows() {
let mut host = Machine {
existingCPUs: 1,
settings: Some(Settings::default()),
..Default::default()
};
let hptr: *mut Machine = &mut host;
let panel = AvailableMetersPanel_new(
hptr,
core::ptr::null_mut(),
1,
Vec::new(),
core::ptr::null_mut(),
);
let platform_rows = Platform_meterTypes.len() - 1; assert_eq!(Panel_size(&panel.super_), platform_rows as i32 + 1);
let first = Platform_meterTypes[1];
let expected = first.description.unwrap_or(first.uiName);
assert_eq!(row(&panel.super_, 0).value, expected);
assert_eq!(row(&panel.super_, 0).key, 1 << 16);
assert_eq!(panel.columns, 1);
assert!(panel.meterPanels.is_empty());
assert_eq!(panel.host, hptr);
}
}