use crate::{fill_rect, font};
pub const CONFIRM_PROMPT_HEIGHT: u32 = 60;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ConfirmPrompt {
pub message: String,
pub yes_label: String,
pub no_label: String,
}
pub type ConfirmRect = (i32, i32, i32, i32);
impl ConfirmPrompt {
pub fn button_rects_at(
&self,
content_x: u32,
content_y: u32,
content_w: u32,
) -> (ConfirmRect, ConfirmRect) {
let right = (content_x + content_w) as i32;
let btn_h = BUTTON_H;
let btn_y = content_y as i32 + (CONFIRM_PROMPT_HEIGHT as i32 - btn_h) / 2;
let yes_w = (font::text_width(&self.yes_label) as i32 + BUTTON_PAD_X * 2).max(40);
let no_w = (font::text_width(&self.no_label) as i32 + BUTTON_PAD_X * 2).max(40);
let gap = 12;
let right_pad = 16;
let no_x = right - right_pad - no_w;
let yes_x = no_x - gap - yes_w;
((yes_x, btn_y, yes_w, btn_h), (no_x, btn_y, no_w, btn_h))
}
pub fn paint_at(
&self,
buffer: &mut [u32],
width: usize,
height: usize,
content_x: u32,
content_y: u32,
content_w: u32,
) -> u32 {
if width == 0 || height == 0 || content_w == 0 {
return CONFIRM_PROMPT_HEIGHT;
}
if buffer.len() < width * height {
return CONFIRM_PROMPT_HEIGHT;
}
let top = content_y as i32;
if top >= height as i32 {
return CONFIRM_PROMPT_HEIGHT;
}
let text_x = content_x as i32 + 8;
let text_y = top + (CONFIRM_PROMPT_HEIGHT as i32 - font::glyph_h() as i32) / 2;
font::draw_text(
buffer,
width,
height,
text_x,
text_y,
&self.message,
COLOUR_FG,
);
let (yes, no) = self.button_rects_at(content_x, content_y, content_w);
paint_button(buffer, width, height, yes, &self.yes_label, COLOUR_BTN_YES);
paint_button(buffer, width, height, no, &self.no_label, COLOUR_BTN_NO);
CONFIRM_PROMPT_HEIGHT
}
}
fn paint_button(
buffer: &mut [u32],
width: usize,
height: usize,
rect: ConfirmRect,
label: &str,
bg: u32,
) {
let (x, y, w, h) = rect;
if w <= 0 || h <= 0 {
return;
}
fill_rect(buffer, width, height, x, y, w as usize, h as usize, bg);
let label_w = font::text_width(label) as i32;
let label_x = x + (w - label_w) / 2;
let label_y = y + (h - font::glyph_h() as i32) / 2;
font::draw_text(buffer, width, height, label_x, label_y, label, COLOUR_FG);
}
pub fn rect_contains(rect: ConfirmRect, px: i32, py: i32) -> bool {
let (x, y, w, h) = rect;
px >= x && px < x + w && py >= y && py < y + h
}
const BUTTON_H: i32 = 28;
const BUTTON_PAD_X: i32 = 14;
const COLOUR_FG: u32 = 0xFF_F0_E8_D8;
const COLOUR_BTN_YES: u32 = 0xFF_40_28_28;
const COLOUR_BTN_NO: u32 = 0xFF_28_28_28;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn button_rects_no_to_right_of_yes() {
let p = ConfirmPrompt {
message: "Close pinned tab?".into(),
yes_label: "Yes".into(),
no_label: "No".into(),
};
let content_x = 100u32;
let content_w = 600u32;
let (yes, no) = p.button_rects_at(content_x, 100, content_w);
assert!(yes.0 < no.0, "Yes should sit left of No");
assert!(
no.0 + no.2 <= (content_x + content_w) as i32,
"No must fit inside content width"
);
}
#[test]
fn rect_contains_works() {
let r = (10, 20, 50, 30);
assert!(rect_contains(r, 12, 22));
assert!(rect_contains(r, 59, 49));
assert!(!rect_contains(r, 60, 22));
assert!(!rect_contains(r, 12, 50));
}
}