Main menu + deref draw function args
This commit is contained in:
parent
dd34f5110c
commit
1a9b1fd9c3
|
@ -94,7 +94,7 @@ impl UiPanel {
|
|||
unsafe { UiPanel_setColor(self.0, color.r, color.g, color.b, color.a) }
|
||||
}
|
||||
|
||||
pub fn draw_triangle(&self, v1: &Vec2, v2: &Vec2, v3: &Vec2, color: &Color) {
|
||||
pub fn draw_triangle(&self, v1: Vec2, v2: Vec2, v3: Vec2, color: Color) {
|
||||
unsafe {
|
||||
UiPanel_drawTriangle(
|
||||
self.0, v1.x, v1.y, v2.x, v2.y, v3.x, v3.y, color.r, color.g, color.b, color.a,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use keyframe::EasingFunction;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Animation<F> {
|
||||
time: f32,
|
||||
duration: f32,
|
||||
|
@ -42,11 +43,10 @@ impl<F: EasingFunction> Animation<F> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn ease_to(&mut self, duration: f32, to: f32) {
|
||||
pub fn ease_to(&mut self, to: f32) {
|
||||
self.from = self.get();
|
||||
self.to = to;
|
||||
self.time = 0.0;
|
||||
self.duration = duration;
|
||||
self.direction = true;
|
||||
}
|
||||
|
||||
|
|
46
src/draw.rs
46
src/draw.rs
|
@ -1,20 +1,27 @@
|
|||
use crate::{Color, Vec2};
|
||||
use crate::abi::UiPanel;
|
||||
use crate::{Color, Vec2};
|
||||
|
||||
pub struct DrawContext {
|
||||
panel: UiPanel,
|
||||
offset: Vec2,
|
||||
}
|
||||
|
||||
impl DrawContext {
|
||||
pub fn new(panel: UiPanel) -> Self {
|
||||
Self { panel }
|
||||
Self {
|
||||
panel,
|
||||
offset: Vec2::ZERO,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_triangle(&self, v1: &Vec2, v2: &Vec2, v3: &Vec2, color: &Color) {
|
||||
self.panel.draw_triangle(v1, v2, v3, color)
|
||||
pub fn draw_triangle(&self, v1: Vec2, v2: Vec2, v3: Vec2, color: Color) {
|
||||
let v1 = v1 + self.offset;
|
||||
let v2 = v2 + self.offset;
|
||||
let v3 = v3 + self.offset;
|
||||
self.panel.draw_triangle(v1, v2, v3, color);
|
||||
}
|
||||
|
||||
pub fn draw_circle(&self, center: &Vec2, radius: f32, color: &Color) {
|
||||
pub fn draw_circle(&self, center: Vec2, radius: f32, color: Color) {
|
||||
use std::f32::consts::PI;
|
||||
|
||||
let delta = PI / 16.0;
|
||||
|
@ -23,14 +30,14 @@ impl DrawContext {
|
|||
let mut last_spoke = Vec2::new(radius + center.x, center.y);
|
||||
let mut theta = delta;
|
||||
while theta < limit {
|
||||
let new_spoke = Vec2::from_angle(theta) * radius + *center;
|
||||
self.draw_triangle(¢er, &last_spoke, &new_spoke, &color);
|
||||
let new_spoke = Vec2::from_angle(theta) * radius + center;
|
||||
self.draw_triangle(center, last_spoke, new_spoke, color);
|
||||
last_spoke = new_spoke;
|
||||
theta += delta;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_ring(&self, center: &Vec2, radius: f32, thickness: f32, color: &Color) {
|
||||
pub fn draw_ring(&self, center: Vec2, radius: f32, thickness: f32, color: Color) {
|
||||
use std::f32::consts::PI;
|
||||
|
||||
let delta = PI / 64.0;
|
||||
|
@ -41,12 +48,12 @@ impl DrawContext {
|
|||
let mut theta = delta;
|
||||
while theta < limit {
|
||||
let angle = Vec2::from_angle(theta);
|
||||
let new_spoke = angle * radius + *center;
|
||||
let new_spoke2 = angle * (radius + thickness) + *center;
|
||||
let last_spoke2 = Vec2::from_angle(last_theta) * (radius + thickness) + *center;
|
||||
let new_spoke = angle * radius + center;
|
||||
let new_spoke2 = angle * (radius + thickness) + center;
|
||||
let last_spoke2 = Vec2::from_angle(last_theta) * (radius + thickness) + center;
|
||||
|
||||
self.draw_triangle(&new_spoke2, &last_spoke, &new_spoke, &color);
|
||||
self.draw_triangle(&new_spoke2, &last_spoke2, &last_spoke, &color);
|
||||
self.draw_triangle(new_spoke2, last_spoke, new_spoke, color);
|
||||
self.draw_triangle(new_spoke2, last_spoke2, last_spoke, color);
|
||||
|
||||
last_spoke = new_spoke;
|
||||
last_theta = theta;
|
||||
|
@ -54,13 +61,20 @@ impl DrawContext {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn draw_rect(&self, xy: &Vec2, size: &Vec2, color: &Color) {
|
||||
pub fn draw_rect(&self, xy: &Vec2, size: &Vec2, color: Color) {
|
||||
let v1 = *xy;
|
||||
let v2 = v1 + Vec2::new(size.x, 0.0);
|
||||
let v3 = v1 + Vec2::new(0.0, size.y);
|
||||
let v4 = v1 + *size;
|
||||
|
||||
self.draw_triangle(&v1, &v2, &v3, &color);
|
||||
self.draw_triangle(&v2, &v3, &v4, &color);
|
||||
self.draw_triangle(v1, v2, v3, color);
|
||||
self.draw_triangle(v2, v3, v4, color);
|
||||
}
|
||||
|
||||
pub fn with_offset(&self, offset: Vec2) -> Self {
|
||||
Self {
|
||||
panel: self.panel,
|
||||
offset: self.offset + offset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
24
src/lib.rs
24
src/lib.rs
|
@ -14,36 +14,28 @@ use widgets::Widget;
|
|||
|
||||
pub struct DummyPanel {
|
||||
panel: UiPanel,
|
||||
buttons: Vec<widgets::RoundButton>,
|
||||
menu: widgets::MainMenu,
|
||||
}
|
||||
|
||||
impl DummyPanel {
|
||||
fn bind(panel: UiPanel) -> Self {
|
||||
let mut buttons = Vec::new();
|
||||
|
||||
for i in 0..6 {
|
||||
let mut button = widgets::RoundButton::default();
|
||||
button.pos.y = i as f32 * 0.2;
|
||||
buttons.push(button);
|
||||
Self {
|
||||
panel,
|
||||
menu: widgets::MainMenu::default(),
|
||||
}
|
||||
|
||||
Self { panel, buttons }
|
||||
}
|
||||
}
|
||||
|
||||
impl abi::PanelImpl for DummyPanel {
|
||||
fn update(&mut self, dt: f32) {
|
||||
self.menu.update(dt);
|
||||
|
||||
let ctx = draw::DrawContext::new(self.panel);
|
||||
for button in self.buttons.iter_mut() {
|
||||
button.update(dt);
|
||||
button.draw(&ctx);
|
||||
}
|
||||
self.menu.draw(&ctx);
|
||||
}
|
||||
|
||||
fn on_cursor_event(&mut self, kind: CursorEventKind, at: Vec2) {
|
||||
for button in self.buttons.iter_mut() {
|
||||
button.on_cursor_event(kind, at);
|
||||
}
|
||||
self.menu.on_cursor_event(kind, at);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
118
src/widgets.rs
118
src/widgets.rs
|
@ -1,7 +1,7 @@
|
|||
use crate::anim::Animation;
|
||||
use keyframe::functions::*;
|
||||
use crate::draw::DrawContext;
|
||||
use crate::{Color, CursorEventKind, Vec2};
|
||||
use keyframe::functions::*;
|
||||
|
||||
pub trait Widget {
|
||||
fn update(&mut self, dt: f32);
|
||||
|
@ -9,12 +9,22 @@ pub trait Widget {
|
|||
fn on_cursor_event(&mut self, kind: CursorEventKind, at: Vec2);
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum ButtonState {
|
||||
Idle,
|
||||
Clicking,
|
||||
Clicked,
|
||||
Releasing,
|
||||
}
|
||||
|
||||
pub struct RoundButton {
|
||||
pub pos: Vec2,
|
||||
pub radius: f32,
|
||||
pub spacing: f32,
|
||||
pub thickness: f32,
|
||||
pub shrink_anim: Animation<EaseInQuint>,
|
||||
pub shrink_anim: Animation<EaseOutQuint>,
|
||||
pub was_clicked: bool,
|
||||
pub state: ButtonState,
|
||||
}
|
||||
|
||||
impl Default for RoundButton {
|
||||
|
@ -24,14 +34,23 @@ impl Default for RoundButton {
|
|||
radius: 0.05,
|
||||
spacing: 0.01,
|
||||
thickness: 0.005,
|
||||
shrink_anim: Animation::new(EaseInQuint, 0.1, 1.0, 0.0),
|
||||
shrink_anim: Animation::new(EaseOutQuint, 0.1, 1.0, 0.0),
|
||||
was_clicked: false,
|
||||
state: ButtonState::Idle,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RoundButton {
|
||||
pub fn was_clicked(&self) -> bool {
|
||||
self.was_clicked
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for RoundButton {
|
||||
fn update(&mut self, dt: f32) {
|
||||
self.shrink_anim.update(dt);
|
||||
self.was_clicked = false;
|
||||
}
|
||||
|
||||
fn draw(&mut self, ctx: &DrawContext) {
|
||||
|
@ -43,19 +62,100 @@ impl Widget for RoundButton {
|
|||
};
|
||||
|
||||
let spacing = self.shrink_anim.get() * self.spacing;
|
||||
ctx.draw_circle(&self.pos, self.radius, &color);
|
||||
ctx.draw_ring(&self.pos, self.radius + spacing, self.thickness, &color);
|
||||
ctx.draw_circle(self.pos, self.radius, color);
|
||||
ctx.draw_ring(self.pos, self.radius + spacing, self.thickness, color);
|
||||
}
|
||||
|
||||
fn on_cursor_event(&mut self, kind: CursorEventKind, at: Vec2) {
|
||||
match kind {
|
||||
CursorEventKind::Select => if self.pos.distance(at) < self.radius {
|
||||
self.shrink_anim.ease_in();
|
||||
},
|
||||
CursorEventKind::Deselect => {
|
||||
CursorEventKind::Select => {
|
||||
if self.pos.distance(at) < self.radius {
|
||||
self.shrink_anim.ease_in();
|
||||
self.state = ButtonState::Clicked;
|
||||
}
|
||||
}
|
||||
CursorEventKind::Deselect => if self.state == ButtonState::Clicked {
|
||||
self.shrink_anim.ease_out();
|
||||
self.was_clicked = true;
|
||||
self.state = ButtonState::Idle;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MainMenu {
|
||||
pub buttons: Vec<RoundButton>,
|
||||
pub spacing: f32,
|
||||
pub scroll_anim: Animation<EaseInOutQuint>,
|
||||
}
|
||||
|
||||
impl Default for MainMenu {
|
||||
fn default() -> Self {
|
||||
let mut buttons = Vec::new();
|
||||
for _ in 0..5 {
|
||||
buttons.push(RoundButton::default());
|
||||
}
|
||||
|
||||
Self {
|
||||
buttons,
|
||||
spacing: 0.2,
|
||||
scroll_anim: Animation::new(EaseInOutQuint, 0.2, 0.0, 0.0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MainMenu {
|
||||
pub fn for_buttons(&mut self, mut cb: impl FnMut(&mut RoundButton, usize, f32)) {
|
||||
for (i, button) in self.buttons.iter_mut().enumerate() {
|
||||
let y = (i as f32 - self.scroll_anim.get()) * self.spacing;
|
||||
cb(button, i, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for MainMenu {
|
||||
fn update(&mut self, dt: f32) {
|
||||
self.scroll_anim.update(dt);
|
||||
|
||||
let mut scroll_to = None;
|
||||
|
||||
self.for_buttons(|button, i, _y| {
|
||||
if button.was_clicked() {
|
||||
scroll_to = Some(i);
|
||||
}
|
||||
|
||||
button.update(dt);
|
||||
});
|
||||
|
||||
if let Some(to) = scroll_to {
|
||||
self.scroll_anim.ease_to(to as f32);
|
||||
}
|
||||
}
|
||||
|
||||
fn draw(&mut self, ctx: &DrawContext) {
|
||||
ctx.draw_triangle(
|
||||
Vec2::new(self.spacing, 0.0),
|
||||
Vec2::new(self.spacing + 0.05, 0.05),
|
||||
Vec2::new(self.spacing + 0.05, -0.05),
|
||||
Color {
|
||||
r: 1.0,
|
||||
g: 1.0,
|
||||
b: 1.0,
|
||||
a: 1.0,
|
||||
},
|
||||
);
|
||||
|
||||
self.for_buttons(|button, _i, y| {
|
||||
let ctx = ctx.with_offset(Vec2::new(0.0, y));
|
||||
button.draw(&ctx);
|
||||
})
|
||||
}
|
||||
|
||||
fn on_cursor_event(&mut self, kind: CursorEventKind, at: Vec2) {
|
||||
self.for_buttons(|button, _i, y| {
|
||||
let at = at - Vec2::new(0.0, y);
|
||||
button.on_cursor_event(kind, at);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue