use super::{img_ids::Imgs, TEXT_COLOR, UI_HIGHLIGHT_0}; use crate::{ game_input::GameInput, hud::{Event, PromptDialogSettings}, settings::Settings, ui::fonts::Fonts, }; use conrod_core::{ widget::{self, Button, Image, Text}, widget_ids, Colorable, Labelable, Positionable, Sizeable, Widget, WidgetCommon, }; use i18n::LocalizationHandle; use keyboard_keynames::key_layout::KeyLayout; widget_ids! { struct Ids { top, mid, bot, text, accept_txt, // optional timer accept_key, //button with label decline_txt, decline_key, prompt_txt, } } #[derive(WidgetCommon)] pub struct PromptDialog<'a> { imgs: &'a Imgs, fonts: &'a Fonts, #[conrod(common_builder)] common: widget::CommonBuilder, localized_strings: &'a LocalizationHandle, settings: &'a Settings, prompt_dialog_settings: &'a PromptDialogSettings, key_layout: &'a Option, } impl<'a> PromptDialog<'a> { pub fn new( imgs: &'a Imgs, fonts: &'a Fonts, localized_strings: &'a LocalizationHandle, settings: &'a Settings, prompt_dialog_settings: &'a PromptDialogSettings, key_layout: &'a Option, ) -> Self { Self { imgs, fonts, localized_strings, common: widget::CommonBuilder::default(), settings, prompt_dialog_settings, key_layout, } } } pub struct State { ids: Ids, } pub enum DialogOutcomeEvent { Affirmative(Event), Negative(Option), } impl<'a> Widget for PromptDialog<'a> { type Event = Option; type State = State; type Style = (); fn init_state(&self, id_gen: widget::id::Generator) -> Self::State { State { ids: Ids::new(id_gen), } } fn style(&self) -> Self::Style {} fn update(self, args: widget::UpdateArgs) -> Self::Event { common_base::prof_span!("PromptDialog::update"); let widget::UpdateArgs { state, ui, .. } = args; let _localized_strings = &self.localized_strings; let mut event: Option = None; let accept_key = self .settings .controls .get_binding(GameInput::AcceptGroupInvite) .map_or_else(|| "".into(), |key| key.display_string(self.key_layout)); let decline_key = self .settings .controls .get_binding(GameInput::DeclineGroupInvite) .map_or_else(|| "".into(), |key| key.display_string(self.key_layout)); // Window Image::new(self.imgs.prompt_top) .w_h(276.0, 24.0) .mid_top_with_margin_on(ui.window, 100.0) .color(Some(UI_HIGHLIGHT_0)) .set(state.ids.top, ui); if !self.prompt_dialog_settings.message.is_empty() { Image::new(self.imgs.prompt_mid) .w(276.0) .h_of(state.ids.prompt_txt) // height relative to content, max height 150 .down_from(state.ids.top, 0.0) .color(Some(UI_HIGHLIGHT_0)) .scroll_kids_vertically() .set(state.ids.mid, ui); } Image::new(self.imgs.prompt_bot) .w_h(276.0, 35.0) .down_from(state.ids.mid, 0.0) .color(Some(UI_HIGHLIGHT_0)) .set(state.ids.bot, ui); // Accept/Decline Buttons if Button::image(self.imgs.key_button) .w_h(20.0, 20.0) .hover_image(self.imgs.close_btn_hover) .press_image(self.imgs.close_btn_press) .label(&accept_key) .image_color(UI_HIGHLIGHT_0) .label_color(TEXT_COLOR) .label_font_size(self.fonts.cyri.scale(16)) .label_font_id(self.fonts.cyri.conrod_id) .label_y(conrod_core::position::Relative::Scalar(2.5)) .label_x(conrod_core::position::Relative::Scalar(0.5)) .bottom_left_with_margins_on(state.ids.bot, 4.0, 6.0) .set(state.ids.accept_key, ui) .was_clicked() || self .prompt_dialog_settings .outcome_via_keypress .map_or(false, |outcome| outcome) { // Primary use should be through pressing the key instead of clicking this event = Some(DialogOutcomeEvent::Affirmative( self.prompt_dialog_settings.affirmative_event.clone(), )); } let accept_txt = if self.prompt_dialog_settings.negative_option { "Accept" } else { "Ok" }; Text::new(accept_txt) .bottom_left_with_margins_on(state.ids.accept_key, 4.0, 28.0) .font_id(self.fonts.cyri.conrod_id) .font_size(self.fonts.cyri.scale(18)) .color(TEXT_COLOR) .set(state.ids.accept_txt, ui); if self.prompt_dialog_settings.negative_option { if Button::image(self.imgs.key_button) .w_h(20.0, 20.0) .hover_image(self.imgs.close_btn_hover) .press_image(self.imgs.close_btn_press) .label(&decline_key) .image_color(UI_HIGHLIGHT_0) .label_color(TEXT_COLOR) .label_font_size(self.fonts.cyri.scale(16)) .label_font_id(self.fonts.cyri.conrod_id) .label_y(conrod_core::position::Relative::Scalar(2.5)) .label_x(conrod_core::position::Relative::Scalar(0.5)) .bottom_right_with_margins_on(state.ids.bot, 4.0, 6.0) .set(state.ids.decline_key, ui) .was_clicked() || self .prompt_dialog_settings .outcome_via_keypress .map_or(false, |outcome| !outcome) { event = Some(DialogOutcomeEvent::Negative( self.prompt_dialog_settings.negative_event.as_ref().cloned(), )); } Text::new("Decline") .bottom_left_with_margins_on(state.ids.decline_key, 4.0, -65.0) .font_id(self.fonts.cyri.conrod_id) .font_size(self.fonts.cyri.scale(18)) .color(TEXT_COLOR) .set(state.ids.decline_txt, ui); } // Prompt Description Text::new(&self.prompt_dialog_settings.message) .mid_top_with_margin_on(state.ids.mid,0.0) .font_id(self.fonts.cyri.conrod_id) .font_size(self.fonts.cyri.scale(18)) .color(TEXT_COLOR) .w(260.0) // Text stays within frame .set(state.ids.prompt_txt, ui); event } }