rounded corners and bug fixes
This commit is contained in:
+16
-14
@@ -5,19 +5,30 @@ use crate::{
|
|||||||
widget::{Element, Widget},
|
widget::{Element, Widget},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
pub struct DivStyle {
|
pub struct DivStyle {
|
||||||
background_color: u32,
|
pub background_color: u32,
|
||||||
|
pub corner_radius: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
pub struct Div {
|
pub struct Div {
|
||||||
children: Vec<Arc<Widget>>,
|
pub children: Vec<Arc<Widget>>,
|
||||||
style: DivStyle,
|
pub style: DivStyle,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Element for Div {
|
impl Element for Div {
|
||||||
fn render(&mut self, scope_parent: &mut crate::render::RenderScope) {
|
fn render(&mut self, scope_parent: &mut crate::render::RenderScope) {
|
||||||
let (w, h) = scope_parent.get_size_or_parent();
|
let (w, h) = scope_parent.get_size_or_parent();
|
||||||
scope_parent.draw_rect(0, 0, w, h, self.style.background_color);
|
scope_parent.draw_rect_rounded(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
w,
|
||||||
|
h,
|
||||||
|
self.style.corner_radius,
|
||||||
|
self.style.background_color,
|
||||||
|
);
|
||||||
|
|
||||||
let mut scope = RenderScope::new(w, h);
|
let mut scope = RenderScope::new(w, h);
|
||||||
|
|
||||||
for elem in &self.children {
|
for elem in &self.children {
|
||||||
@@ -31,7 +42,7 @@ impl Element for Div {
|
|||||||
if let Some(t) = elem.get() {
|
if let Some(t) = elem.get() {
|
||||||
scope.set_transform(&t);
|
scope.set_transform(&t);
|
||||||
}
|
}
|
||||||
scope_parent.merge(scope.clone(), 0, 0);
|
scope_parent.merge(scope.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,15 +56,6 @@ impl Element for Div {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Div {
|
impl Div {
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
children: Vec::new(),
|
|
||||||
style: DivStyle {
|
|
||||||
background_color: 0xF00000,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn draw<E: Element + 'static>(&mut self, element: E) -> &Arc<Widget> {
|
pub fn draw<E: Element + 'static>(&mut self, element: E) -> &Arc<Widget> {
|
||||||
self.children.push(Arc::new(Widget::new(Box::new(element))));
|
self.children.push(Arc::new(Widget::new(Box::new(element))));
|
||||||
self.children.last().unwrap()
|
self.children.last().unwrap()
|
||||||
|
|||||||
@@ -10,5 +10,12 @@ use crate::{style::RawTransform, widget::Widget};
|
|||||||
|
|
||||||
pub trait Extension {
|
pub trait Extension {
|
||||||
fn init(&mut self, _widgets: &Vec<Arc<Widget>>) {}
|
fn init(&mut self, _widgets: &Vec<Arc<Widget>>) {}
|
||||||
fn render(&mut self, _widgets: &Arc<Widget>, _transform: RawTransform, _win: &Window) {}
|
fn before_render(
|
||||||
|
&mut self,
|
||||||
|
_widgets: &Vec<Arc<Widget>>,
|
||||||
|
_transform: RawTransform,
|
||||||
|
_win: &Window,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
fn render(&mut self, _widget: &Arc<Widget>, _transform: RawTransform, _win: &Window) {}
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-9
@@ -7,16 +7,31 @@ use crate::{component, extensions::Extension, style::RawTransform, widget::Widge
|
|||||||
pub struct MouseExtension(bool);
|
pub struct MouseExtension(bool);
|
||||||
|
|
||||||
impl Extension for MouseExtension {
|
impl Extension for MouseExtension {
|
||||||
fn render(&mut self, widget: &Arc<Widget>, transform: RawTransform, win: &Window) {
|
fn before_render(
|
||||||
|
&mut self,
|
||||||
|
_widgets: &Vec<Arc<Widget>>,
|
||||||
|
_transform: RawTransform,
|
||||||
|
win: &Window,
|
||||||
|
) {
|
||||||
if win.get_mouse_down(MouseButton::Left) {
|
if win.get_mouse_down(MouseButton::Left) {
|
||||||
if !self.0 {
|
if !self.0 {
|
||||||
self.0 = true;
|
self.0 = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.0 = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render(&mut self, widget: &Arc<Widget>, transform: RawTransform, win: &Window) {
|
||||||
|
if !self.0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if let Some((mx, my)) = win.get_mouse_pos(minifb::MouseMode::Discard) {
|
if let Some((mx, my)) = win.get_mouse_pos(minifb::MouseMode::Discard) {
|
||||||
let (mx, my) = (mx as usize, my as usize);
|
let (mx, my) = (mx as usize, my as usize);
|
||||||
if mx >= transform.x
|
if my >= transform.y
|
||||||
&& my >= transform.y
|
&& mx < transform.x + transform.width
|
||||||
&& mx <= transform.x + transform.width
|
&& my < transform.y + transform.height
|
||||||
&& mx <= transform.y + transform.height
|
|
||||||
{
|
{
|
||||||
std::thread::spawn({
|
std::thread::spawn({
|
||||||
let widget = widget.clone();
|
let widget = widget.clone();
|
||||||
@@ -29,10 +44,6 @@ impl Extension for MouseExtension {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
self.0 = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MouseExtension {
|
impl MouseExtension {
|
||||||
|
|||||||
@@ -62,6 +62,12 @@ impl Screen {
|
|||||||
let (w, h) = self.window.get_size();
|
let (w, h) = self.window.get_size();
|
||||||
let mut scope = RenderScope::new(w, h);
|
let mut scope = RenderScope::new(w, h);
|
||||||
|
|
||||||
|
for ext in &self.extensions {
|
||||||
|
ext.lock()
|
||||||
|
.unwrap()
|
||||||
|
.before_render(&self.widgets, scope.get_transform(), &self.window);
|
||||||
|
}
|
||||||
|
|
||||||
for elem in &self.widgets {
|
for elem in &self.widgets {
|
||||||
scope.clear();
|
scope.clear();
|
||||||
if let Some(t) = elem.get() {
|
if let Some(t) = elem.get() {
|
||||||
|
|||||||
+29
-13
@@ -1,7 +1,7 @@
|
|||||||
use minifb::{Window, WindowOptions};
|
use minifb::{Window, WindowOptions};
|
||||||
use osgui::{
|
use osgui::{
|
||||||
elements::div::Div,
|
elements::div::{Div, DivStyle},
|
||||||
extensions::{mouse::MouseExtension, velocity::VelocityExtension},
|
extensions::mouse::{MouseExtension, OnClick},
|
||||||
style::Transform,
|
style::Transform,
|
||||||
Screen,
|
Screen,
|
||||||
};
|
};
|
||||||
@@ -9,8 +9,8 @@ use osgui::{
|
|||||||
fn main() {
|
fn main() {
|
||||||
let window = Window::new(
|
let window = Window::new(
|
||||||
"minifb example",
|
"minifb example",
|
||||||
200,
|
1920,
|
||||||
200,
|
1080,
|
||||||
WindowOptions {
|
WindowOptions {
|
||||||
resize: false,
|
resize: false,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -19,17 +19,33 @@ fn main() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut app = Screen::new(window);
|
let mut app = Screen::new(window);
|
||||||
app.extension(VelocityExtension);
|
|
||||||
app.extension(MouseExtension::new());
|
app.extension(MouseExtension::new());
|
||||||
|
|
||||||
let mut d = Div::new();
|
milestones(&mut app);
|
||||||
|
|
||||||
d.draw("test".to_string()).component(Transform::center());
|
|
||||||
d.draw("abc".to_string())
|
|
||||||
.component(Transform::center().margin(0, 25));
|
|
||||||
|
|
||||||
app.draw(d)
|
|
||||||
.component(Transform::center().dimensions(150, 150));
|
|
||||||
|
|
||||||
app.run().unwrap();
|
app.run().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn milestones(app: &mut Screen) {
|
||||||
|
for i in 0..4 {
|
||||||
|
let mut milestone = Div {
|
||||||
|
style: DivStyle {
|
||||||
|
background_color: 0x1D1D1D,
|
||||||
|
corner_radius: 24,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
milestone
|
||||||
|
.draw(format!("My Milestone"))
|
||||||
|
.component(Transform::center());
|
||||||
|
|
||||||
|
app.draw(milestone)
|
||||||
|
.component(Transform::new().dimensions(873, 194).pos(
|
||||||
|
osgui::style::Position::Center,
|
||||||
|
osgui::style::Position::Const(145 + ((194 + 30) * i)),
|
||||||
|
))
|
||||||
|
.component(OnClick(|_| println!("Clicked!")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+101
-20
@@ -11,7 +11,8 @@ const FONT: &[u8] = include_bytes!("../assets/DejaVuSans.ttf");
|
|||||||
pub enum RenderMethod {
|
pub enum RenderMethod {
|
||||||
Text(String, usize, usize, f32, u32),
|
Text(String, usize, usize, f32, u32),
|
||||||
Rectangle(usize, usize, usize, usize, u32),
|
Rectangle(usize, usize, usize, usize, u32),
|
||||||
Merge(RenderScope, usize, usize),
|
RoundedRectangle(usize, usize, usize, usize, usize, u32),
|
||||||
|
Merge(RenderScope),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -37,6 +38,9 @@ impl RenderScope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_text(&mut self, x: usize, y: usize, scale: f32, text: &str, color: u32) {
|
pub fn draw_text(&mut self, x: usize, y: usize, scale: f32, text: &str, color: u32) {
|
||||||
|
if color == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
self.render_stack
|
self.render_stack
|
||||||
.push(RenderMethod::Text(text.to_string(), x, y, scale, color));
|
.push(RenderMethod::Text(text.to_string(), x, y, scale, color));
|
||||||
let font = Font::try_from_bytes(FONT).unwrap();
|
let font = Font::try_from_bytes(FONT).unwrap();
|
||||||
@@ -47,6 +51,9 @@ impl RenderScope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_rect(&mut self, x: usize, y: usize, width: usize, height: usize, color: u32) {
|
pub fn draw_rect(&mut self, x: usize, y: usize, width: usize, height: usize, color: u32) {
|
||||||
|
if color == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
self.render_stack
|
self.render_stack
|
||||||
.push(RenderMethod::Rectangle(x, y, width, height, color));
|
.push(RenderMethod::Rectangle(x, y, width, height, color));
|
||||||
self.transform.width = self.transform.width.max(width);
|
self.transform.width = self.transform.width.max(width);
|
||||||
@@ -54,10 +61,33 @@ impl RenderScope {
|
|||||||
self.update_size();
|
self.update_size();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn merge(&mut self, scope: RenderScope, offset_x: usize, offset_y: usize) {
|
pub fn draw_rect_rounded(
|
||||||
|
&mut self,
|
||||||
|
x: usize,
|
||||||
|
y: usize,
|
||||||
|
width: usize,
|
||||||
|
height: usize,
|
||||||
|
radius: usize,
|
||||||
|
color: u32,
|
||||||
|
) {
|
||||||
|
if color == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if radius == 0 {
|
||||||
|
self.draw_rect(x, y, width, height, color);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.render_stack.push(RenderMethod::RoundedRectangle(
|
||||||
|
x, y, width, height, radius, color,
|
||||||
|
));
|
||||||
|
self.transform.width = self.transform.width.max(width);
|
||||||
|
self.transform.height = self.transform.height.max(height);
|
||||||
|
self.update_size();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn merge(&mut self, scope: RenderScope) {
|
||||||
let (w, h) = scope.get_max_size();
|
let (w, h) = scope.get_max_size();
|
||||||
self.render_stack
|
self.render_stack.push(RenderMethod::Merge(scope));
|
||||||
.push(RenderMethod::Merge(scope, offset_x, offset_y));
|
|
||||||
self.transform.width = self.transform.width.max(w as usize);
|
self.transform.width = self.transform.width.max(w as usize);
|
||||||
self.transform.height = self.transform.height.max(h as usize);
|
self.transform.height = self.transform.height.max(h as usize);
|
||||||
self.update_size();
|
self.update_size();
|
||||||
@@ -67,14 +97,14 @@ impl RenderScope {
|
|||||||
// After draw
|
// After draw
|
||||||
impl RenderScope {
|
impl RenderScope {
|
||||||
pub fn draw(&mut self) {
|
pub fn draw(&mut self) {
|
||||||
let mut tmp = self.buffer.clone();
|
let mut tmp = std::mem::take(&mut self.buffer);
|
||||||
self.draw_buf(&mut tmp, 0, 0);
|
self.draw_buf(&mut tmp);
|
||||||
self.buffer = tmp;
|
self.buffer = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_buf(&self, buf: &mut Vec<Vec<u32>>, offset_x: usize, offset_y: usize) {
|
pub fn draw_buf(&self, buf: &mut Vec<Vec<u32>>) {
|
||||||
let offset_x = self.transform.x + offset_x;
|
let offset_x = self.transform.x;
|
||||||
let offset_y = self.transform.y + offset_y;
|
let offset_y = self.transform.y;
|
||||||
|
|
||||||
for m in &self.render_stack {
|
for m in &self.render_stack {
|
||||||
match m {
|
match m {
|
||||||
@@ -86,6 +116,57 @@ impl RenderScope {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&RenderMethod::RoundedRectangle(px, py, width, height, radius, color) => {
|
||||||
|
let radius = radius as i32;
|
||||||
|
let w = width as i32;
|
||||||
|
let h = height as i32;
|
||||||
|
let start_x = offset_x as i32 + px as i32;
|
||||||
|
let start_y = offset_y as i32 + py as i32;
|
||||||
|
|
||||||
|
for y in 0..h {
|
||||||
|
for x in 0..w {
|
||||||
|
let dx = x;
|
||||||
|
let dy = y;
|
||||||
|
|
||||||
|
let in_top_left = dx < radius && dy < radius;
|
||||||
|
let in_top_right = dx >= w - radius && dy < radius;
|
||||||
|
let in_bottom_left = dx < radius && dy >= h - radius;
|
||||||
|
let in_bottom_right = dx >= w - radius && dy >= h - radius;
|
||||||
|
|
||||||
|
let dist = |cx: i32, cy: i32| -> bool {
|
||||||
|
let dx = dx - cx;
|
||||||
|
let dy = dy - cy;
|
||||||
|
dx * dx + dy * dy <= radius * radius
|
||||||
|
};
|
||||||
|
|
||||||
|
let draw = match (
|
||||||
|
in_top_left,
|
||||||
|
in_top_right,
|
||||||
|
in_bottom_left,
|
||||||
|
in_bottom_right,
|
||||||
|
) {
|
||||||
|
(true, _, _, _) => dist(radius - 1, radius - 1),
|
||||||
|
(_, true, _, _) => dist(w - radius, radius - 1),
|
||||||
|
(_, _, true, _) => dist(radius - 1, h - radius),
|
||||||
|
(_, _, _, true) => dist(w - radius, h - radius),
|
||||||
|
_ => true, // middle or edges outside corner
|
||||||
|
};
|
||||||
|
|
||||||
|
if draw {
|
||||||
|
let global_x = start_x + x;
|
||||||
|
let global_y = start_y + y;
|
||||||
|
if global_x >= 0
|
||||||
|
&& global_x < self.parent_width as i32
|
||||||
|
&& global_y >= 0
|
||||||
|
&& global_y < self.parent_height as i32
|
||||||
|
{
|
||||||
|
buf[global_y as usize][global_x as usize] = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RenderMethod::Text(text, px, py, scale, base_color) => {
|
RenderMethod::Text(text, px, py, scale, base_color) => {
|
||||||
let font = Font::try_from_bytes(FONT).unwrap();
|
let font = Font::try_from_bytes(FONT).unwrap();
|
||||||
let scale = Scale::uniform(*scale);
|
let scale = Scale::uniform(*scale);
|
||||||
@@ -113,26 +194,26 @@ impl RenderScope {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let x = gx as i32 + bb.min.x + *px as i32;
|
let x = (gx as i32 + bb.min.x + *px as i32) as usize;
|
||||||
let y = gy as i32 + bb.min.y + *py as i32;
|
let y = (gy as i32 + bb.min.y + *py as i32) as usize;
|
||||||
|
|
||||||
if (0..self.parent_width as i32).contains(&x)
|
|
||||||
&& (0..self.parent_height as i32).contains(&y)
|
|
||||||
{
|
|
||||||
let (x, y) = (x as usize, y as usize);
|
|
||||||
|
|
||||||
|
if let Some(row) = buf.get_mut(y) {
|
||||||
|
if let Some(col) = row.get_mut(x) {
|
||||||
let r = (r_base * v) as u32;
|
let r = (r_base * v) as u32;
|
||||||
let g = (g_base * v) as u32;
|
let g = (g_base * v) as u32;
|
||||||
let b = (b_base * v) as u32;
|
let b = (b_base * v) as u32;
|
||||||
|
*col = (r << 16) | (g << 8) | b;
|
||||||
buf[y][x] = (r << 16) | (g << 8) | b;
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RenderMethod::Merge(scope, ox, oy) => {
|
RenderMethod::Merge(scope) => {
|
||||||
scope.draw_buf(buf, *ox + self.transform.x, *oy + self.transform.y);
|
let mut scope = scope.clone();
|
||||||
|
scope.transform.x += self.transform.x;
|
||||||
|
scope.transform.y += self.transform.y;
|
||||||
|
scope.draw_buf(buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,6 +64,12 @@ impl Transform {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn pos(mut self, x: Position, y: Position) -> Self {
|
||||||
|
self.x = x;
|
||||||
|
self.y = y;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn dimensions(mut self, width: usize, height: usize) -> Self {
|
pub fn dimensions(mut self, width: usize, height: usize) -> Self {
|
||||||
self.width = Dimension::Const(width);
|
self.width = Dimension::Const(width);
|
||||||
self.height = Dimension::Const(height);
|
self.height = Dimension::Const(height);
|
||||||
|
|||||||
Reference in New Issue
Block a user