Add CornerFlags and draw_partially_rounded_rect()

This commit is contained in:
mars 2022-07-12 16:16:52 -06:00
parent bfe8ca07a0
commit f7c2a24572
3 changed files with 107 additions and 18 deletions

View File

@ -7,10 +7,11 @@ edition = "2021"
crate-type = ["cdylib", "rlib"]
[dependencies]
bitflags = "^1"
glam = "^0.21"
keyframe = "1"
wee_alloc = "^0.4"
[profile.release]
opt-level = "s"
opt-level = 3
lto = "fat"

View File

@ -1,5 +1,6 @@
use crate::abi::UiPanel;
use crate::{Color, Vec2};
use bitflags::bitflags;
pub enum Corner {
TopRight,
@ -8,6 +9,20 @@ pub enum Corner {
TopLeft,
}
bitflags! {
pub struct CornerFlags: u8 {
const TOP_RIGHT = 0x01;
const BOTTOM_RIGHT = 0x02;
const BOTTOM_LEFT = 0x04;
const TOP_LEFT = 0x08;
const TOP = 0x09;
const RIGHT = 0x03;
const BOTTOM = 0x06;
const LEFT = 0x0C;
const ALL = 0x0F;
}
}
pub struct DrawContext {
panel: UiPanel,
offset: Vec2,
@ -108,30 +123,85 @@ impl DrawContext {
}
pub fn draw_rounded_rect(&self, xy: Vec2, size: Vec2, radius: f32, color: Color) {
self.draw_partially_rounded_rect(CornerFlags::ALL, xy, size, radius, color);
}
pub fn draw_partially_rounded_rect(
&self,
corners: CornerFlags,
xy: Vec2,
size: Vec2,
radius: f32,
color: Color,
) {
if corners.is_empty() {
self.draw_rect(xy, size, color);
return;
}
let has_top = corners.intersects(CornerFlags::TOP);
let has_bottom = corners.intersects(CornerFlags::BOTTOM);
let edge_size = Vec2::new(size.x, radius);
let xoff = Vec2::new(radius, 0.0);
let yoff = Vec2::new(0.0, radius);
let sizex = Vec2::new(size.x, 0.0);
let sizey = Vec2::new(0.0, size.y);
let inner_size = size - Vec2::new(radius, radius) * 2.0;
let lr_edge_size = Vec2::new(radius, inner_size.y);
let tb_edge_size = Vec2::new(inner_size.x, radius);
self.draw_rect(xy + yoff, lr_edge_size, color); // left edge
self.draw_rect(xy + yoff + sizex - xoff, lr_edge_size, color); // right edge
self.draw_rect(xy + xoff, tb_edge_size, color); // bottom edge
self.draw_rect(xy + xoff + sizey - yoff, tb_edge_size, color); // top edge
let tr = xy + size - xoff - yoff;
let br = xy + sizex - xoff + yoff;
let bl = xy + xoff + yoff;
let tl = xy + sizey + xoff - yoff;
self.draw_quarter_circle(Corner::TopRight, tr, radius, color);
self.draw_quarter_circle(Corner::BottomRight, br, radius, color);
self.draw_quarter_circle(Corner::BottomLeft, bl, radius, color);
self.draw_quarter_circle(Corner::TopLeft, tl, radius, color);
if has_bottom {
let mut bottom_xy = xy;
let mut bottom_size = edge_size;
self.draw_rect(bl, inner_size, color);
if corners.contains(CornerFlags::BOTTOM_LEFT) {
bottom_xy.x += radius;
bottom_size.x -= radius;
self.draw_quarter_circle(Corner::BottomLeft, bl, radius, color);
}
if corners.contains(CornerFlags::BOTTOM_RIGHT) {
bottom_size.x -= radius;
self.draw_quarter_circle(Corner::BottomRight, br, radius, color);
}
self.draw_rect(bottom_xy, bottom_size, color);
}
if has_top {
let mut top_xy = Vec2::new(xy.x, xy.y + size.y - radius);
let mut top_size = edge_size;
if corners.contains(CornerFlags::TOP_LEFT) {
top_xy.x += radius;
top_size.x -= radius;
self.draw_quarter_circle(Corner::TopLeft, tl, radius, color);
}
if corners.contains(CornerFlags::TOP_RIGHT) {
top_size.x -= radius;
self.draw_quarter_circle(Corner::TopRight, tr, radius, color);
}
self.draw_rect(top_xy, top_size, color);
}
let mut inner_xy = xy;
let mut inner_size = size;
if has_bottom {
inner_xy.y += radius;
inner_size.y -= radius;
}
if has_top {
inner_size.y -= radius;
}
self.draw_rect(inner_xy, inner_size, color);
}
pub fn with_offset(&self, offset: Vec2) -> Self {

View File

@ -1,5 +1,5 @@
use crate::anim::Animation;
use crate::draw::{Corner, DrawContext};
use crate::draw::{Corner, CornerFlags, DrawContext};
use crate::{Color, CursorEventKind, Vec2};
use keyframe::functions::*;
@ -93,6 +93,8 @@ impl Widget for RoundButton {
pub struct RectButton {
pub pos: Vec2,
pub size: Vec2,
pub rounded_corners: CornerFlags,
pub radius: f32,
pub was_clicked: bool,
pub is_selected: bool,
pub is_hovering: bool,
@ -110,10 +112,12 @@ impl RectButton {
pub const HOVER_COLOR: Color = Color::new(1., 1., 1., 0.8);
pub const SELECTED_COLOR: Color = Color::new(1., 1., 0., 1.);
pub fn new(pos: Vec2, size: Vec2) -> Self {
pub fn new(pos: Vec2, size: Vec2, rounded_corners: CornerFlags, radius: f32) -> Self {
Self {
pos,
size,
rounded_corners,
radius,
was_clicked: false,
is_selected: false,
is_hovering: false,
@ -134,7 +138,13 @@ impl Widget for RectButton {
}
fn draw(&mut self, ctx: &DrawContext) {
ctx.draw_rect(self.pos, self.size, self.color_anim.get());
ctx.draw_partially_rounded_rect(
self.rounded_corners,
self.pos,
self.size,
self.radius,
self.color_anim.get(),
);
}
fn on_cursor_event(&mut self, kind: CursorEventKind, at: Vec2) {
@ -555,7 +565,15 @@ impl TabMenu {
for i in 0..Self::TAB_NUM {
let y = (i + 1) as f32 * Self::TAB_HEIGHT;
let pos = Vec2::new(0.0, -y);
tabs.push(RectButton::new(pos, tab_size));
let radius = Self::HEAD_RADIUS;
let corners = if i == Self::TAB_NUM - 1 {
CornerFlags::BOTTOM_LEFT
} else {
CornerFlags::empty()
};
tabs.push(RectButton::new(pos, tab_size, corners, radius));
}
Self { tabs }