diff --git a/refbox/src/app/message.rs b/refbox/src/app/message.rs index ff463f59..e44b1fc2 100644 --- a/refbox/src/app/message.rs +++ b/refbox/src/app/message.rs @@ -176,6 +176,7 @@ pub enum CyclingParameter { AlertVolume, AboveWaterVol, UnderWaterVol, + Mode, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] diff --git a/refbox/src/app/mod.rs b/refbox/src/app/mod.rs index 5f5c6b1c..b8d9bdf8 100644 --- a/refbox/src/app/mod.rs +++ b/refbox/src/app/mod.rs @@ -896,6 +896,7 @@ impl Application for RefBoxApp { current_pool: self.current_pool.clone(), games: self.games.clone(), sound: self.config.sound.clone(), + mode: self.config.mode, }; self.edited_settings = Some(edited_settings); @@ -990,6 +991,7 @@ impl Application for RefBoxApp { self.games = edited_settings.games; self.config.sound = edited_settings.sound; self.sound.update_settings(self.config.sound.clone()); + self.config.mode = edited_settings.mode; confy::store(APP_NAME, None, &self.config).unwrap(); AppState::MainPage @@ -1006,6 +1008,7 @@ impl Application for RefBoxApp { self.games = edited_settings.games; self.config.sound = edited_settings.sound; self.sound.update_settings(self.config.sound.clone()); + self.config.mode = edited_settings.mode; confy::store(APP_NAME, None, &self.config).unwrap(); @@ -1047,6 +1050,7 @@ impl Application for RefBoxApp { self.games = edited_settings.games; self.config.sound = edited_settings.sound; self.sound.update_settings(self.config.sound.clone()); + self.config.mode = edited_settings.mode; confy::store(APP_NAME, None, &self.config).unwrap(); AppState::MainPage @@ -1230,13 +1234,16 @@ impl Application for RefBoxApp { } } Message::CycleParameter(param) => { - let sound = &mut self.edited_settings.as_mut().unwrap().sound; + let settings = &mut self.edited_settings.as_mut().unwrap(); match param { - CyclingParameter::BuzzerSound => sound.buzzer_sound.cycle(), - CyclingParameter::RemoteBuzzerSound(idx) => sound.remotes[idx].sound.cycle(), - CyclingParameter::AlertVolume => sound.whistle_vol.cycle(), - CyclingParameter::AboveWaterVol => sound.above_water_vol.cycle(), - CyclingParameter::UnderWaterVol => sound.under_water_vol.cycle(), + CyclingParameter::BuzzerSound => settings.sound.buzzer_sound.cycle(), + CyclingParameter::RemoteBuzzerSound(idx) => { + settings.sound.remotes[idx].sound.cycle() + } + CyclingParameter::AlertVolume => settings.sound.whistle_vol.cycle(), + CyclingParameter::AboveWaterVol => settings.sound.above_water_vol.cycle(), + CyclingParameter::UnderWaterVol => settings.sound.under_water_vol.cycle(), + CyclingParameter::Mode => settings.mode.cycle(), } } Message::RequestRemoteId => { @@ -1325,6 +1332,7 @@ impl Application for RefBoxApp { self.games = edited_settings.games; self.config.sound = edited_settings.sound; self.sound.update_settings(self.config.sound.clone()); + self.config.mode = edited_settings.mode; confy::store(APP_NAME, None, &self.config).unwrap(); let snapshot = tm.generate_snapshot(now).unwrap(); // TODO: Remove this unwrap @@ -1346,6 +1354,7 @@ impl Application for RefBoxApp { self.games = edited_settings.games; self.config.sound = edited_settings.sound; self.sound.update_settings(self.config.sound.clone()); + self.config.mode = edited_settings.mode; confy::store(APP_NAME, None, &self.config).unwrap(); self.apply_snapshot(snapshot); @@ -1573,7 +1582,7 @@ impl Application for RefBoxApp { indices, ), AppState::KeypadPage(page, player_num) => { - build_keypad_page(&self.snapshot, page, player_num) + build_keypad_page(&self.snapshot, page, player_num, self.config.mode) } AppState::EditGameConfig(page) => build_game_config_edit_page( &self.snapshot, diff --git a/refbox/src/app/view_builders/configuration.rs b/refbox/src/app/view_builders/configuration.rs index b6550306..bfd94eb4 100644 --- a/refbox/src/app/view_builders/configuration.rs +++ b/refbox/src/app/view_builders/configuration.rs @@ -3,6 +3,7 @@ use super::{ shared_elements::*, style::{self, MEDIUM_TEXT, MIN_BUTTON_SIZE, PADDING, SMALL_TEXT, SPACING}, }; +use crate::config::Mode; use crate::sound_controller::*; use collect_array::CollectArrayResult; use iced::{ @@ -27,6 +28,7 @@ pub(in super::super) struct EditableSettings { pub current_pool: Option, pub games: Option>, pub sound: SoundSettings, + pub mode: Mode, } pub(in super::super) trait Cyclable @@ -77,6 +79,16 @@ impl Cyclable for Volume { } } +impl Cyclable for Mode { + fn next(&self) -> Self { + match self { + Self::Hockey6V6 => Self::Hockey3V3, + Self::Hockey3V3 => Self::Rugby, + Self::Rugby => Self::Hockey6V6, + } + } +} + pub(in super::super) fn build_game_config_edit_page<'a>( snapshot: &GameSnapshot, settings: &EditableSettings, @@ -170,7 +182,12 @@ fn make_main_config_page<'a>( ) .style(style::Button::LightGray), ) - .push(vertical_space(Length::Fill)) + .push(make_value_button( + "MODE", + settings.mode.to_string().to_uppercase(), + (true, true), + Some(Message::CycleParameter(CyclingParameter::Mode)), + )) .push( row() .spacing(SPACING) diff --git a/refbox/src/app/view_builders/keypad_pages/mod.rs b/refbox/src/app/view_builders/keypad_pages/mod.rs index 83755011..bed2c77d 100644 --- a/refbox/src/app/view_builders/keypad_pages/mod.rs +++ b/refbox/src/app/view_builders/keypad_pages/mod.rs @@ -1,3 +1,5 @@ +use crate::config::Mode; + use super::{ style::{self, LARGE_TEXT, MEDIUM_TEXT, MIN_BUTTON_SIZE, PADDING, SPACING}, *, @@ -27,6 +29,7 @@ pub(in super::super) fn build_keypad_page<'a>( snapshot: &GameSnapshot, page: KeypadPage, player_num: u16, + mode: Mode, ) -> Element<'a, Message> { column() .spacing(SPACING) @@ -159,7 +162,7 @@ pub(in super::super) fn build_keypad_page<'a>( .push(match page { KeypadPage::AddScore(color) => make_score_add_page(color), KeypadPage::Penalty(origin, color, kind) => { - make_penalty_edit_page(origin, color, kind) + make_penalty_edit_page(origin, color, kind, mode) } KeypadPage::GameNumber => make_game_number_edit_page(), KeypadPage::TeamTimeouts(dur) => make_team_timeout_edit_page(dur), diff --git a/refbox/src/app/view_builders/keypad_pages/penalty_edit.rs b/refbox/src/app/view_builders/keypad_pages/penalty_edit.rs index 753bc20b..87aa8a88 100644 --- a/refbox/src/app/view_builders/keypad_pages/penalty_edit.rs +++ b/refbox/src/app/view_builders/keypad_pages/penalty_edit.rs @@ -1,3 +1,5 @@ +use crate::config::Mode; + use super::{ style::{self, SPACING}, *, @@ -14,37 +16,68 @@ pub(super) fn make_penalty_edit_page<'a>( origin: Option<(GameColor, usize)>, color: GameColor, kind: PenaltyKind, + mode: Mode, ) -> Element<'a, Message> { let (black_style, white_style) = match color { GameColor::Black => (style::Button::BlackSelected, style::Button::White), GameColor::White => (style::Button::Black, style::Button::WhiteSelected), }; - let (one_min_style, two_min_style, five_min_style, td_style) = match kind { - PenaltyKind::OneMinute => ( + let (green, yellow, orange) = match mode { + Mode::Hockey6V6 => ( + PenaltyKind::OneMinute, + PenaltyKind::TwoMinute, + PenaltyKind::FiveMinute, + ), + + Mode::Hockey3V3 => ( + PenaltyKind::ThirtySecond, + PenaltyKind::OneMinute, + PenaltyKind::TwoMinute, + ), + + Mode::Rugby => ( + PenaltyKind::TwoMinute, + PenaltyKind::FourMinute, + PenaltyKind::FiveMinute, + ), + }; + + let (green_style, yellow_style, orange_style, td_style) = if kind == green { + ( style::Button::GreenSelected, style::Button::Yellow, style::Button::Orange, style::Button::Red, - ), - PenaltyKind::TwoMinute => ( + ) + } else if kind == yellow { + ( style::Button::Green, style::Button::YellowSelected, style::Button::Orange, style::Button::Red, - ), - PenaltyKind::FiveMinute => ( + ) + } else if kind == orange { + ( style::Button::Green, style::Button::Yellow, style::Button::OrangeSelected, style::Button::Red, - ), - PenaltyKind::TotalDismissal => ( + ) + } else if kind == PenaltyKind::TotalDismissal { + ( style::Button::Green, style::Button::Yellow, style::Button::Orange, style::Button::RedSelected, - ), + ) + } else { + ( + style::Button::Green, + style::Button::Yellow, + style::Button::Orange, + style::Button::Red, + ) }; let mut exit_row = row().spacing(SPACING).push( @@ -79,6 +112,22 @@ pub(super) fn make_penalty_edit_page<'a>( }), ); + let labels: Vec<&str> = [green, yellow, orange] + .iter() + .map(|kind| match kind { + PenaltyKind::ThirtySecond => "30s", + PenaltyKind::OneMinute => "1m", + PenaltyKind::TwoMinute => "2m", + PenaltyKind::FourMinute => "4m", + PenaltyKind::FiveMinute => "5m", + PenaltyKind::TotalDismissal => "TD", + }) + .collect(); + + let green_label = labels[0]; + let yellow_label = labels[1]; + let orange_label = labels[2]; + column() .spacing(SPACING) .push(vertical_space(Length::Fill)) @@ -101,19 +150,19 @@ pub(super) fn make_penalty_edit_page<'a>( row() .spacing(SPACING) .push( - make_button("1m") - .style(one_min_style) - .on_press(Message::ChangeKind(PenaltyKind::OneMinute)), + make_button(green_label) + .style(green_style) + .on_press(Message::ChangeKind(green)), ) .push( - make_button("2m") - .style(two_min_style) - .on_press(Message::ChangeKind(PenaltyKind::TwoMinute)), + make_button(yellow_label) + .style(yellow_style) + .on_press(Message::ChangeKind(yellow)), ) .push( - make_button("5m") - .style(five_min_style) - .on_press(Message::ChangeKind(PenaltyKind::FiveMinute)), + make_button(orange_label) + .style(orange_style) + .on_press(Message::ChangeKind(orange)), ) .push( make_button("TD") diff --git a/refbox/src/config.rs b/refbox/src/config.rs index 3ea27abc..e69218a3 100644 --- a/refbox/src/config.rs +++ b/refbox/src/config.rs @@ -1,4 +1,7 @@ use crate::sound_controller::SoundSettings; +use derivative::Derivative; +use enum_derive_2018::EnumDisplay; +use macro_attr_2018::macro_attr; use serde::{Deserialize, Serialize}; use time::UtcOffset; pub use uwh_common::config::Game; @@ -41,12 +44,24 @@ impl Default for UwhScores { #[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] pub struct Config { + pub mode: Mode, pub game: Game, pub hardware: Hardware, pub uwhscores: UwhScores, pub sound: SoundSettings, } +macro_attr! { + #[derive(Debug, Clone, Copy, Derivative, PartialEq, Eq, Serialize, Deserialize, EnumDisplay!)] + #[derivative(Default)] + pub enum Mode { + #[derivative(Default)] + Hockey6V6, + Hockey3V3, + Rugby, + } +} + #[cfg(test)] mod test { use super::*; diff --git a/refbox/src/penalty_editor.rs b/refbox/src/penalty_editor.rs index 09ef8b1b..8ce208b7 100644 --- a/refbox/src/penalty_editor.rs +++ b/refbox/src/penalty_editor.rs @@ -307,8 +307,10 @@ fn generate_printable_list( EditablePenalty::New(_, _) => FormatHint::New, }; let kind_str = match kind { + PenaltyKind::ThirtySecond => "30s", PenaltyKind::OneMinute => "1m", PenaltyKind::TwoMinute => "2m", + PenaltyKind::FourMinute => "4m", PenaltyKind::FiveMinute => "5m", PenaltyKind::TotalDismissal => "DSMS", }; diff --git a/refbox/src/tournament_manager.rs b/refbox/src/tournament_manager.rs index a719195c..482470d4 100644 --- a/refbox/src/tournament_manager.rs +++ b/refbox/src/tournament_manager.rs @@ -1530,9 +1530,11 @@ impl TimeoutState { #[derive(Derivative)] #[derivative(Debug, Default, Clone, Copy, PartialEq, Eq)] pub enum PenaltyKind { + ThirtySecond, #[derivative(Default)] OneMinute, TwoMinute, + FourMinute, FiveMinute, TotalDismissal, } @@ -1540,8 +1542,10 @@ pub enum PenaltyKind { impl PenaltyKind { pub(crate) fn as_duration(self) -> Option { match self { + Self::ThirtySecond => Some(Duration::from_secs(30)), Self::OneMinute => Some(Duration::from_secs(60)), Self::TwoMinute => Some(Duration::from_secs(120)), + Self::FourMinute => Some(Duration::from_secs(240)), Self::FiveMinute => Some(Duration::from_secs(300)), Self::TotalDismissal => None, } @@ -1640,7 +1644,11 @@ impl Penalty { ) -> PenaltyResult { match self.kind { PenaltyKind::TotalDismissal => Ok(false), - PenaltyKind::OneMinute | PenaltyKind::TwoMinute | PenaltyKind::FiveMinute => self + PenaltyKind::ThirtySecond + | PenaltyKind::OneMinute + | PenaltyKind::TwoMinute + | PenaltyKind::FourMinute + | PenaltyKind::FiveMinute => self .time_remaining(cur_per, cur_time, config) .map(|rem| rem <= SignedDuration::ZERO), }