#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(dead_code)]
use core::any::Any;
use core::sync::atomic::Ordering;
use std::io::{self, Write};
use crossterm::queue;
use crossterm::terminal::{Clear, ClearType};
use crate::ported::crt::{
CRT_colorScheme, CRT_setColors, ColorScheme, KEY_ENTER, KEY_MOUSE, KEY_RECLICK,
};
use crate::ported::functionbar::FunctionBar_new;
use crate::ported::panel::{HandlerResult, Panel_getSelectedIndex};
#[cfg(test)]
use crate::ported::object::Object;
use crate::ported::optionitem::{CheckItem, CheckItem_newByVal, CheckItem_set};
use crate::ported::panel::{Panel, PanelClass, Panel_add, Panel_done, Panel_new, Panel_setHeader};
use crate::ported::settings::Settings;
static ColorsFunctions: [&str; 10] = [
" ", " ", " ", " ", " ", " ", " ", " ", " ",
"Done ",
];
static ColorSchemeNames: [&str; 8] = [
"Default",
"Monochromatic",
"Black on White",
"Light Terminal",
"MC",
"Black Night",
"Broken Gray",
"Nord",
];
pub struct ColorsPanel {
pub super_: Panel,
pub settings: *mut Settings,
}
impl PanelClass for ColorsPanel {
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 {
ColorsPanel_eventHandler(self, ev)
}
}
pub fn ColorsPanel_delete(this: ColorsPanel) {
let ColorsPanel { super_, settings } = this;
Panel_done(super_);
let _ = settings;
}
pub fn ColorsPanel_eventHandler(this: &mut ColorsPanel, ch: i32) -> HandlerResult {
let clear = || {
let mut out = io::stdout().lock();
let _ = queue!(out, Clear(ClearType::All));
let _ = out.flush();
};
let mut result = HandlerResult::IGNORED;
match ch {
0x0a | 0x0d | KEY_ENTER | KEY_MOUSE | KEY_RECLICK | 0x20 => {
let mark = Panel_getSelectedIndex(&this.super_);
debug_assert!(mark >= 0);
debug_assert!((mark as usize) < ColorScheme::LAST_COLORSCHEME as usize);
for i in 0..ColorSchemeNames.len() {
let any: &mut dyn Any = this.super_.items[i].object_mut();
if let Some(item) = any.downcast_mut::<CheckItem>() {
CheckItem_set(item, false);
}
}
let any: &mut dyn Any = this.super_.items[mark as usize].object_mut();
if let Some(item) = any.downcast_mut::<CheckItem>() {
CheckItem_set(item, true);
}
let settings = unsafe { &mut *this.settings };
settings.colorScheme = mark;
settings.changed = true;
settings.lastUpdate += 1;
CRT_setColors(mark);
clear();
result = HandlerResult::HANDLED | HandlerResult::REDRAW;
}
_ => {}
}
result
}
pub fn ColorsPanel_new(settings: *mut Settings) -> ColorsPanel {
let fuBar = FunctionBar_new(Some(&ColorsFunctions[..]), None, None);
let super_ = Panel_new(1, 1, 1, 1, Some(fuBar));
let mut this = ColorsPanel { super_, settings };
debug_assert_eq!(
ColorSchemeNames.len(),
ColorScheme::LAST_COLORSCHEME as usize
);
Panel_setHeader(&mut this.super_, "Colors");
for name in ColorSchemeNames {
Panel_add(&mut this.super_, Box::new(CheckItem_newByVal(name, false)));
}
let idx = CRT_colorScheme.load(Ordering::Relaxed);
let any: &mut dyn Any = this.super_.items[idx].object_mut();
if let Some(item) = any.downcast_mut::<CheckItem>() {
CheckItem_set(item, true);
}
this
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ported::crt::CRT_setColors;
use crate::ported::optionitem::CheckItem_get;
use crate::ported::panel::Panel_size;
use crate::ported::richstring::RichString_sizeVal;
fn item_checked(cp: &ColorsPanel, i: usize) -> bool {
let obj: &dyn Object = cp.super_.items[i].object();
let any: &dyn Any = obj;
CheckItem_get(any.downcast_ref::<CheckItem>().unwrap())
}
fn item_text(cp: &ColorsPanel, i: usize) -> String {
let obj: &dyn Object = cp.super_.items[i].object();
let any: &dyn Any = obj;
any.downcast_ref::<CheckItem>().unwrap().text.clone()
}
#[test]
fn builds_one_checkitem_per_scheme_in_order() {
let cp = ColorsPanel_new(core::ptr::null_mut());
assert_eq!(Panel_size(&cp.super_), ColorSchemeNames.len() as i32);
for (i, name) in ColorSchemeNames.iter().enumerate() {
assert_eq!(item_text(&cp, i), *name);
}
}
#[test]
fn header_is_colors() {
let cp = ColorsPanel_new(core::ptr::null_mut());
assert_eq!(RichString_sizeVal(&cp.super_.header), "Colors".len() as i32);
}
#[test]
fn function_bar_last_label_is_done() {
let cp = ColorsPanel_new(core::ptr::null_mut());
let bar = cp.super_.currentBar.as_ref().expect("currentBar set");
assert_eq!(bar.functions, ColorsFunctions.to_vec());
}
#[test]
fn stores_settings_backpointer() {
let sentinel = 0xdead_beef_usize as *mut Settings;
let cp = ColorsPanel_new(sentinel);
assert_eq!(cp.settings, sentinel);
}
#[test]
fn checks_only_the_active_scheme_row() {
CRT_setColors(ColorScheme::COLORSCHEME_BLACKONWHITE as i32);
let active = CRT_colorScheme.load(Ordering::Relaxed);
let cp = ColorsPanel_new(core::ptr::null_mut());
for i in 0..ColorSchemeNames.len() {
assert_eq!(item_checked(&cp, i), i == active, "row {i} check state");
}
}
}