use crate::prelude::*;
use crate::ui::radiobox::events::EventData;
use super::Type;
#[CustomControl(overwrite=OnPaint+OnDefaultAction+OnKeyPressed+OnMouseEvent+OnSiblingSelected,internal=true)]
pub struct RadioBox {
caption: Caption,
selected: bool,
selected_symbol: Symbol,
unselected_symbol: Symbol,
symbol_width: u8,
}
impl RadioBox {
pub fn new(caption: &str, layout: Layout, selected: bool) -> Self {
Self::inner_create(caption, layout, selected, Type::Standard, StatusFlags::ThemeType)
}
pub fn with_type(caption: &str, layout: Layout, selected: bool, radio_type: Type) -> Self {
Self::inner_create(caption, layout, selected, radio_type, StatusFlags::None)
}
fn inner_create(caption: &str, layout: Layout, selected: bool, radio_type: Type, status: StatusFlags) -> Self {
let ss = Symbol::new(radio_type.selected_symbol());
let us = Symbol::new(radio_type.unselected_symbol());
if ss.width() != us.width() {
panic!("RadioBox: selected and unselected symbols must have the same width (1, 2 or 3 characters)");
}
if ss.width() == 0 {
panic!("RadioBox: selected and unselected symbols must have at least one character");
}
let symbol_width = ss.width() + 1;
let mut rb = RadioBox {
base: ControlBase::with_status_flags(layout, StatusFlags::Visible | StatusFlags::Enabled | StatusFlags::AcceptInput | status),
caption: Caption::new(caption, ExtractHotKeyMethod::AltPlusKey),
selected,
selected_symbol: ss,
unselected_symbol: us,
symbol_width,
};
rb.set_size_bounds(5, 1, u16::MAX, u16::MAX);
let hotkey = rb.caption.hotkey();
rb.set_hotkey(hotkey);
rb
}
#[inline(always)]
pub fn is_selected(&self) -> bool {
self.selected
}
#[inline(always)]
pub fn set_selected(&mut self) {
if self.handle.is_none() {
return;
}
if let Some(parent) = RuntimeManager::get().get_controls_mut().get(self.parent) {
parent.base().notify_children_of_selection(self.handle);
}
}
pub fn set_caption(&mut self, caption: &str) {
self.caption.set_text(caption, ExtractHotKeyMethod::AltPlusKey);
let hotkey = self.caption.hotkey();
self.set_hotkey(hotkey);
}
#[inline(always)]
pub fn caption(&self) -> &str {
self.caption.text()
}
}
impl OnPaint for RadioBox {
fn on_paint(&self, surface: &mut Surface, theme: &Theme) {
let attr_text = match () {
_ if !self.is_enabled() => theme.text.inactive,
_ if self.has_focus() => theme.text.focused,
_ if self.is_mouse_over() => theme.text.hovered,
_ => theme.text.normal,
};
let enabled = self.is_enabled();
let col_hot_key = if enabled { theme.text.hot_key } else { theme.text.inactive };
let sz = self.size();
if sz.width > self.symbol_width as u32 {
let mut format = TextFormatBuilder::new()
.position(self.symbol_width as i32, 0)
.attribute(attr_text)
.align(TextAlignment::Left)
.chars_count(self.caption.chars_count() as u16)
.build();
if sz.height > 1 {
format.set_wrap_type(WrapType::WordWrap(sz.width as u16 - self.symbol_width as u16));
}
if self.caption.has_hotkey() {
format.set_hotkey(col_hot_key, self.caption.hotkey_pos().unwrap() as u32);
}
surface.write_text(self.caption.text(), &format);
}
if self.selected {
let attr_symbol = if enabled { theme.symbol.checked } else { theme.symbol.inactive };
let attr_margin = if self.symbol_width == 4 { attr_text } else { attr_symbol };
self.selected_symbol.paint(surface, 0, 0, attr_margin, attr_symbol, attr_margin);
} else {
let attr_symbol = if enabled { theme.symbol.unchecked } else { theme.symbol.inactive };
let attr_margin = if self.symbol_width == 4 { attr_text } else { attr_symbol };
self.unselected_symbol.paint(surface, 0, 0, attr_margin, attr_symbol, attr_margin);
}
if self.has_focus() {
surface.set_cursor(if self.symbol_width == 4 { 1 } else { 0 }, 0);
}
}
}
impl OnDefaultAction for RadioBox {
fn on_default_action(&mut self) {
self.set_selected();
self.raise_event(ControlEvent {
emitter: self.handle,
receiver: self.event_processor,
data: ControlEventData::RadioBox(EventData {}),
});
}
}
impl OnKeyPressed for RadioBox {
fn on_key_pressed(&mut self, key: Key, _character: char) -> EventProcessStatus {
if (key.modifier == KeyModifier::None) && ((key.code == KeyCode::Space) || (key.code == KeyCode::Enter)) {
self.on_default_action();
return EventProcessStatus::Processed;
}
EventProcessStatus::Ignored
}
}
impl OnMouseEvent for RadioBox {
fn on_mouse_event(&mut self, event: &MouseEvent) -> EventProcessStatus {
match event {
MouseEvent::Enter => {
if self.caption.chars_count() > (self.size().width - 4) as usize {
self.show_tooltip(self.caption.text());
}
EventProcessStatus::Processed
}
MouseEvent::Leave => EventProcessStatus::Processed,
MouseEvent::Released(data) => {
if self.is_coord_in_control(data.x, data.y) {
self.on_default_action();
}
EventProcessStatus::Processed
}
_ => EventProcessStatus::Ignored,
}
}
}
impl OnSiblingSelected for RadioBox {
#[allow(private_interfaces)]
fn on_sibling_selected(&mut self, handle: Handle<()>) {
self.selected = self.handle == handle;
}
}