RectButton icons

This commit is contained in:
marceline-cramer 2022-07-27 00:08:10 -06:00
parent e070a54bb6
commit a6492622b6
5 changed files with 113 additions and 43 deletions

View File

@ -1,5 +1,7 @@
use super::*;
use text::Icon;
pub trait Button {
fn was_clicked(&self) -> bool;
}
@ -20,36 +22,31 @@ pub struct RoundButton {
shrink_anim: Animation<EaseOutQuint>,
was_clicked: bool,
state: ButtonState,
label: Option<Label>,
icon: Option<Icon>,
}
impl RoundButton {
pub fn new(label: Option<LabelText>) -> Self {
pub fn new(icon: Option<LabelText>) -> Self {
let pos = Vec2::ZERO;
let radius = 0.05;
let label = label.map(|text| {
let icon = icon.map(|text| {
let scale = radius * 1.5;
let alignment = HorizontalAlignment::Center;
let left = -radius;
let right = radius;
let baseline = 0.0;
let center = pos;
let color = Color::BLACK;
let center_y = true;
Label::new(
text, alignment, scale, color, left, right, baseline, center_y,
)
Icon::new(text, scale, color, center)
});
Self {
pos: Default::default(),
pos,
radius,
spacing: 0.01,
thickness: 0.002,
shrink_anim: Animation::new(EaseOutQuint, 0.1, 1.0, 0.0),
was_clicked: false,
state: ButtonState::Idle,
label,
icon,
}
}
}
@ -78,7 +75,7 @@ impl Widget for RoundButton {
ctx.draw_circle(self.pos, self.radius, color);
ctx.draw_ring(self.pos, self.radius + spacing, self.thickness, color);
self.label.draw(ctx);
self.icon.draw(ctx);
}
fn on_cursor_event(&mut self, kind: CursorEventKind, at: Vec2) {
@ -105,6 +102,10 @@ impl Widget for RoundButton {
pub struct RectButtonStyle {
pub rounded_corners: CornerFlags,
pub radius: f32,
pub label_scale_factor: f32,
pub label_baseline: f32,
pub icon_scale_factor: f32,
pub icon_margin_factor: f32,
pub inactive_color: Color,
pub hover_color: Color,
pub selected_color: Color,
@ -115,6 +116,10 @@ impl Default for RectButtonStyle {
Self {
rounded_corners: CornerFlags::empty(),
radius: 0.0,
label_scale_factor: 0.65,
label_baseline: 0.25,
icon_scale_factor: 0.8,
icon_margin_factor: 1.1,
inactive_color: Color::new(1., 1., 1., 0.2),
hover_color: Color::new(1., 1., 1., 0.8),
selected_color: Color::new(1., 1., 0., 1.),
@ -130,6 +135,7 @@ pub struct RectButton {
pub is_hovering: bool,
pub color_anim: Animation<EaseInQuad, Color>,
pub label: Option<Label>,
pub icon: Option<Icon>,
}
impl Button for RectButton {
@ -139,23 +145,32 @@ impl Button for RectButton {
}
impl RectButton {
pub fn new(style: RectButtonStyle, label: Option<LabelText>, rect: Rect) -> Self {
let label_height_scale = 0.7;
let label_baseline_scale = 0.25;
pub fn new(style: RectButtonStyle, rect: Rect, label: Option<LabelText>, icon: Option<LabelText>) -> Self {
let mut label_left = rect.bl.x;
let mut alignment = HorizontalAlignment::Center;
let icon = icon.map(|text| {
let margin = rect.height() * style.icon_margin_factor;
label_left += margin;
alignment = HorizontalAlignment::Left;
let scale = rect.height() * style.icon_scale_factor;
let color = Color::BLACK;
let cx = rect.bl.x + margin / 2.0;
let cy = rect.bl.y + rect.height() / 2.0;
let center = Vec2::new(cx, cy);
Icon::new(text, scale, color, center)
});
let label = label.map(|text| {
let scale = rect.height() * label_height_scale;
let alignment = HorizontalAlignment::Center;
let left = rect.bl.x;
let scale = rect.height() * style.label_scale_factor;
let left = label_left;
let right = rect.tr.x;
let baseline = rect.bl.y;
let baseline = (rect.height() * label_baseline_scale) + baseline;
let baseline = (rect.height() * style.label_baseline) + baseline;
let color = Color::BLACK;
let center_y = false;
Label::new(
text, alignment, scale, color, left, right, baseline, center_y,
)
Label::new(text, alignment, scale, color, left, right, baseline)
});
let color_anim =
@ -169,6 +184,7 @@ impl RectButton {
is_hovering: false,
color_anim,
label,
icon,
}
}
}
@ -188,6 +204,7 @@ impl Widget for RectButton {
);
self.label.draw(ctx);
self.icon.draw(ctx);
}
fn on_cursor_event(&mut self, kind: CursorEventKind, at: Vec2) {

View File

@ -238,7 +238,7 @@ impl TabMenu {
}
let rect = Rect::from_xy_size(pos, tab_size);
tabs.push(RectButton::new(style, None, rect));
tabs.push(RectButton::new(style, rect, None, None));
}
let tab_list_height = Self::TAB_NUM as f32 * Self::TAB_HEIGHT;

View File

@ -173,21 +173,35 @@ pub struct SettingsMenu {
impl SettingsMenu {
pub fn new() -> Self {
let font = Font::new("Leon Sans");
let button_texts = ["Graphics", "Sound", "Interface", "Network", "Account"];
let icon_font = Font::new("Iosevka Nerd Font");
let label_font = Font::new("Leon Sans");
let button_texts = [
("Graphics", ""),
("Sound", ""),
("Interface", ""),
("Network", ""),
("Account", ""),
];
let button_size = Vec2::new(0.4, 0.1);
let button_rect = Rect::from_xy_size(Vec2::new(0.0, -button_size.y / 2.0), button_size);
let mut buttons = Vec::new();
for text in button_texts.iter() {
let text = LabelText {
font,
text: text.to_string(),
for (label, icon) in button_texts.iter() {
let label = LabelText {
font: label_font,
text: label.to_string(),
};
let icon = LabelText {
font: icon_font,
text: icon.to_string(),
};
let style = Default::default();
let button = RectButton::new(style, Some(text), button_rect);
let button = RectButton::new(style, button_rect, Some(label), Some(icon));
buttons.push(button);
}

View File

@ -20,7 +20,6 @@ pub struct Label {
left: f32,
right: f32,
baseline: f32,
center_y: bool,
dirty: bool,
layout: Option<TextLayout>,
bounds: Rect,
@ -36,7 +35,6 @@ impl Label {
left: f32,
right: f32,
baseline: f32,
center_y: bool,
) -> Self {
Self {
text,
@ -46,7 +44,6 @@ impl Label {
left,
right,
baseline,
center_y,
dirty: true,
layout: None,
bounds: Rect::from_xy_size(Vec2::ZERO, Vec2::ZERO),
@ -73,13 +70,51 @@ impl Widget for Label {
}
};
let yoff = if self.center_y {
(bounds.bl.y - bounds.tr.y) / 2.0 - bounds.bl.y
} else {
0.0
};
self.offset = Vec2::new(xoff, yoff + self.baseline);
self.offset = Vec2::new(xoff, self.baseline);
self.dirty = false;
self.layout = Some(layout);
}
if let Some(layout) = self.layout.as_ref() {
ctx.draw_text_layout(layout, self.offset, self.scale, self.color);
}
}
}
pub struct Icon {
text: LabelText,
scale: f32,
color: Color,
center: Vec2,
dirty: bool,
layout: Option<TextLayout>,
bounds: Rect,
offset: Vec2,
}
impl Icon {
pub fn new(text: LabelText, scale: f32, color: Color, center: Vec2) -> Self {
Self {
text,
scale,
color,
center,
dirty: true,
layout: None,
bounds: Rect::from_xy_size(Vec2::ZERO, Vec2::ZERO),
offset: Vec2::ZERO,
}
}
}
impl Widget for Icon {
fn draw(&mut self, ctx: &DrawContext) {
if self.dirty {
let layout = TextLayout::new(&self.text.font, &self.text.text);
let bounds = Rect::from(layout.get_bounds()).scale(self.scale);
self.bounds = bounds;
self.offset = self.center - bounds.size() / 2.0;
self.offset.y -= bounds.bl.y;
self.dirty = false;
self.layout = Some(layout);
}

View File

@ -120,6 +120,10 @@ impl Rect {
self.bl.x < xy.x && self.bl.y < xy.y && self.tr.x > xy.x && self.tr.y > xy.y
}
pub fn size(&self) -> Vec2 {
self.tr - self.bl
}
pub fn width(&self) -> f32 {
self.tr.x - self.bl.x
}