Move to raqote for rendering
This commit is contained in:
@@ -1 +0,0 @@
|
||||
|
||||
@@ -31,8 +31,11 @@ use std::time::Duration;
|
||||
use anyhow::Result;
|
||||
|
||||
mod ui;
|
||||
mod pixel;
|
||||
mod app;
|
||||
|
||||
use ui::{ButtonBuilder, DrawAreaBuilder, TextAreaBuilder};
|
||||
|
||||
use ui::{Pixel, PixelEncoding};
|
||||
|
||||
const WINDOW_HEIGHT: u32 = 256;
|
||||
const WINDOW_WIDTH: u32 = 512;
|
||||
@@ -51,7 +54,7 @@ pub(super) fn run() -> Result<()> {
|
||||
let compositor = CompositorState::bind(&globals, &qh)?;
|
||||
let xdg_shell = XdgShell::bind(&globals, &qh)?;
|
||||
let shm = Shm::bind(&globals, &qh)?;
|
||||
let _xdg_activation = ActivationState::bind(&globals, &qh).ok();
|
||||
let xdg_activation = ActivationState::bind(&globals, &qh).ok();
|
||||
|
||||
let surface = compositor.create_surface(&qh);
|
||||
let window = xdg_shell.create_window(surface, WindowDecorations::RequestServer, &qh);
|
||||
@@ -63,6 +66,17 @@ pub(super) fn run() -> Result<()> {
|
||||
|
||||
window.commit();
|
||||
|
||||
if let Some(activation) = xdg_activation.as_ref() {
|
||||
activation.request_token(
|
||||
&qh,
|
||||
RequestData {
|
||||
seat_and_serial: None,
|
||||
surface: Some(window.wl_surface().clone()),
|
||||
app_id: Some(String::from("simmer.waywrite")),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
let pool = SlotPool::new((WINDOW_WIDTH as usize) * (WINDOW_HEIGHT as usize) * 4, &shm)?;
|
||||
|
||||
let mut simple_window = SimpleWindow {
|
||||
@@ -251,16 +265,44 @@ impl SimpleWindow {
|
||||
}
|
||||
};
|
||||
|
||||
for pix in canvas.chunks_exact_mut(4) {
|
||||
let draw_buffer: &mut [u32] = unsafe {canvas.align_to_mut::<u32>().1};
|
||||
|
||||
|
||||
let mut window = ui::Window::new(
|
||||
draw_buffer,
|
||||
self.width.try_into().unwrap(),
|
||||
self.height.try_into().unwrap()
|
||||
);
|
||||
|
||||
let mut button = ButtonBuilder::new();
|
||||
let mut draw_area = DrawAreaBuilder::new();
|
||||
|
||||
button.position(self.width as f32 - 100.0, 50.0);
|
||||
button.width(100.0);
|
||||
button.height(50.0);
|
||||
button.color(0x33, 0x33, 0x33);
|
||||
let button = button.finish();
|
||||
|
||||
draw_area.position(0.0, 50.0);
|
||||
draw_area.width(self.width as f32 - 100.0);
|
||||
draw_area.height(self.height as f32 - 50.0);
|
||||
draw_area.color(0x15, 0x15, 0x15);
|
||||
let draw_area = draw_area.finish();
|
||||
|
||||
|
||||
let mut text_area = TextAreaBuilder::new();
|
||||
text_area.position(0.0, 0.0);
|
||||
text_area.width(self.width as f32);
|
||||
text_area.height(50.0);
|
||||
text_area.color(0x22, 0x22, 0x22);
|
||||
let text_area = text_area.finish();
|
||||
|
||||
window.add_widget(button);
|
||||
window.add_widget(draw_area);
|
||||
window.add_widget(text_area);
|
||||
|
||||
window.render();
|
||||
|
||||
let pixel_color: &[u8; 4] = &Pixel::new(0.5, 0.5, 0.5, 1.0)
|
||||
.as_u32(PixelEncoding::ARGB)
|
||||
.to_le_bytes();
|
||||
|
||||
let pix: &mut [u8; 4] = pix.try_into().unwrap();
|
||||
|
||||
*pix = *pixel_color;
|
||||
}
|
||||
|
||||
self.window.wl_surface().damage_buffer(0, 0, self.width as i32, self.height as i32);
|
||||
self.window.wl_surface().frame(qh, self.window.wl_surface().clone());
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
|
||||
pub(super) enum PixelEncoding {
|
||||
ARGB,
|
||||
RGBA,
|
||||
}
|
||||
|
||||
struct ColorValue {
|
||||
value: u8,
|
||||
}
|
||||
|
||||
impl ColorValue {
|
||||
fn new(value: u8) -> Self {
|
||||
Self { value }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u8> for ColorValue {
|
||||
fn from(value: u8) -> Self {
|
||||
Self { value }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f32> for ColorValue {
|
||||
fn from(value: f32) -> Self {
|
||||
assert!(value <= 1.0);
|
||||
Self { value: (value * 255.0) as u8 }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for ColorValue {
|
||||
fn from(value: f64) -> Self {
|
||||
assert!(value <= 1.0);
|
||||
Self { value: (value * 255.0) as u8 }
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct Pixel {
|
||||
r: ColorValue,
|
||||
g: ColorValue,
|
||||
b: ColorValue,
|
||||
a: ColorValue,
|
||||
}
|
||||
|
||||
impl Pixel {
|
||||
pub(super) fn new<T: Into<ColorValue>>(r: T, g: T, b: T, a: T) -> Self {
|
||||
Self {
|
||||
r: r.into(),
|
||||
g: g.into(),
|
||||
b: b.into(),
|
||||
a: a.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn as_u32(&self, encoding: PixelEncoding) -> u32 {
|
||||
match encoding {
|
||||
PixelEncoding::ARGB => {
|
||||
let color = [self.a.value, self.r.value, self.g.value, self.b.value];
|
||||
u32::from_be_bytes(color)
|
||||
},
|
||||
PixelEncoding::RGBA => {
|
||||
let color = [self.r.value, self.g.value, self.b.value, self.a.value];
|
||||
u32::from_be_bytes(color)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{ColorValue, Pixel, PixelEncoding};
|
||||
|
||||
#[test]
|
||||
fn test_max_u8() {
|
||||
assert_eq!(ColorValue::from(1.0).value, 255);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_min_u8() {
|
||||
assert_eq!(ColorValue::from(0.0).value, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_argb_u32() {
|
||||
let pixel = Pixel::new(0x00, 0x00, 0x00, 0x00);
|
||||
assert_eq!(pixel.as_u32(PixelEncoding::ARGB), 0x00);
|
||||
|
||||
let pixel = Pixel::new(0xff, 0xff, 0xff, 0xff);
|
||||
assert_eq!(pixel.as_u32(PixelEncoding::ARGB), u32::MAX);
|
||||
|
||||
let pixel = Pixel::new(0xaa, 0xaa, 0xaa, 0xaa);
|
||||
assert_eq!(pixel.as_u32(PixelEncoding::ARGB), 0xaaaaaaaa);
|
||||
|
||||
let pixel = Pixel::new(0xfd, 0xcb, 0xa9, 0x87);
|
||||
println!("{:x?}", pixel.as_u32(PixelEncoding::ARGB));
|
||||
assert_eq!(pixel.as_u32(PixelEncoding::ARGB), 0x87fdcba9);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rgba_u32() {
|
||||
let pixel = Pixel::new(0x00, 0x00, 0x00, 0x00);
|
||||
assert_eq!(pixel.as_u32(PixelEncoding::RGBA), 0x00);
|
||||
|
||||
let pixel = Pixel::new(0xff, 0xff, 0xff, 0xff);
|
||||
assert_eq!(pixel.as_u32(PixelEncoding::RGBA), u32::MAX);
|
||||
|
||||
let pixel = Pixel::new(0xaa, 0xaa, 0xaa, 0xaa);
|
||||
assert_eq!(pixel.as_u32(PixelEncoding::RGBA), 0xaaaaaaaa);
|
||||
|
||||
let pixel = Pixel::new(0xfd, 0xcb, 0xa9, 0x87);
|
||||
println!("{:x?}", pixel.as_u32(PixelEncoding::RGBA));
|
||||
assert_eq!(pixel.as_u32(PixelEncoding::RGBA), 0xfdcba987);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,335 @@
|
||||
use crate::wayland::pixel::{Pixel, Box, BoxMut, PixelEncoding};
|
||||
use raqote::{DrawTarget, PathBuilder, Source, StrokeStyle, DrawOptions, SolidSource, Color};
|
||||
|
||||
struct UIColor {
|
||||
draw_area: Color,
|
||||
button: Color,
|
||||
button_accent: Color,
|
||||
background: Color,
|
||||
_text_area: Color,
|
||||
_symbol: Color,
|
||||
_text: Color,
|
||||
}
|
||||
|
||||
impl Default for UIColor {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
draw_area: Color::new(0xff, 0x15, 0x15, 0x15),
|
||||
button: Color::new(0xff, 0x22, 0x22, 0x22),
|
||||
button_accent: Color::new(0xff, 0x33, 0x33, 0x33),
|
||||
background: Color::new(0xff, 0x11, 0x11, 0x11),
|
||||
_text_area: Color::new(0xff, 0x33, 0x33, 0x33),
|
||||
_symbol: Color::new(0xff, 0xcc, 0xcc, 0xcc),
|
||||
_text: Color::new(0xff, 0xdd, 0xdd, 0xdd),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct Window<'a, 'b> {
|
||||
pub(super) draw: DrawTarget<&'a mut [u32]>,
|
||||
pub(super) options: DrawOptions,
|
||||
pub(super) colors: UIColor,
|
||||
pub(super) widgets: Vec<Widget<'b>>,
|
||||
pub(super) width: usize,
|
||||
pub(super) height: usize,
|
||||
|
||||
}
|
||||
|
||||
impl<'a, 'b> Window<'a, 'b> {
|
||||
pub(super) fn new(buffer: &'a mut [u32], width: usize, height: usize) -> Self {
|
||||
Self {
|
||||
draw: DrawTarget::from_backing(width.try_into().unwrap(), height.try_into().unwrap(), buffer),
|
||||
options: DrawOptions::new(),
|
||||
colors: UIColor::default(),
|
||||
widgets: Vec::new(),
|
||||
width,
|
||||
height,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn add_widget(&mut self, widget: Widget<'b>) {
|
||||
self.widgets.push(widget);
|
||||
}
|
||||
|
||||
pub(super) fn render(&mut self) {
|
||||
|
||||
self.draw.fill_rect(
|
||||
0.0,
|
||||
0.0,
|
||||
self.width as f32,
|
||||
self.height as f32,
|
||||
&Source::Solid(self.colors.background.into()),
|
||||
&self.options
|
||||
);
|
||||
|
||||
for widget in self.widgets.iter() {
|
||||
match widget {
|
||||
Widget::Button(button) => button.render(&mut self.draw),
|
||||
Widget::DrawArea(draw_area) => draw_area.render(&mut self.draw),
|
||||
Widget::TextArea(text_area) => text_area.render(&mut self.draw),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct Position {
|
||||
pub(super) x: f32,
|
||||
pub(super) y: f32,
|
||||
}
|
||||
|
||||
impl Position {
|
||||
pub(super) fn new(x: f32, y: f32) -> Self {
|
||||
Position { x, y }
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) enum Widget<'a> {
|
||||
Button(Button<'a>),
|
||||
DrawArea(DrawArea<'a>),
|
||||
TextArea(TextArea<'a>)
|
||||
}
|
||||
|
||||
pub(super) trait Draw {
|
||||
fn render(&self, area: &mut DrawTarget<&mut [u32]>);
|
||||
}
|
||||
|
||||
pub(super) struct Button<'a> {
|
||||
pub(super) width: f32,
|
||||
pub(super) height: f32,
|
||||
pub(super) position: Position,
|
||||
pub(super) source: Source<'a>,
|
||||
pub(super) options: DrawOptions,
|
||||
}
|
||||
|
||||
pub(super) struct ButtonBuilder<'a> {
|
||||
pub(super) width: Option<f32>,
|
||||
pub(super) height: Option<f32>,
|
||||
pub(super) position: Option<Position>,
|
||||
pub(super) source: Option<Source<'a>>,
|
||||
pub(super) color: Option<Color>,
|
||||
pub(super) options: Option<DrawOptions>,
|
||||
}
|
||||
|
||||
impl<'a> ButtonBuilder<'a> {
|
||||
pub(super) fn new() -> Self {
|
||||
Self {
|
||||
width: None,
|
||||
height: None,
|
||||
position: None,
|
||||
source: None,
|
||||
color: None,
|
||||
options: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn width(&mut self, width: f32) {
|
||||
self.width = Some(width)
|
||||
}
|
||||
|
||||
pub(super) fn height(&mut self, height: f32) {
|
||||
self.height = Some(height)
|
||||
}
|
||||
|
||||
pub(super) fn position(&mut self, x: f32, y: f32) {
|
||||
self.position = Some(Position::new(x, y))
|
||||
}
|
||||
|
||||
pub(super) fn source(&mut self, source: Source<'a>) {
|
||||
self.source = Some(source);
|
||||
}
|
||||
|
||||
pub(super) fn color(&mut self, r: u8, g: u8, b: u8) {
|
||||
self.color = Some(Color::new(0xff, r, g, b))
|
||||
}
|
||||
|
||||
pub(super) fn finish(self) -> Widget<'a> {
|
||||
Widget::Button(
|
||||
Button {
|
||||
width: self.width.expect("Button must have width"),
|
||||
height: self.height.expect("Button must have height"),
|
||||
position: self.position.expect("Button must have a position"),
|
||||
source: self.source.unwrap_or(
|
||||
Source::Solid(
|
||||
self.color.unwrap_or(Color::new(0xff, 0x00, 0x00, 0x00)).into()
|
||||
)
|
||||
),
|
||||
options: self.options.unwrap_or(DrawOptions::new()),
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Draw for Button<'a> {
|
||||
fn render(&self, area: &mut DrawTarget<&mut [u32]>) {
|
||||
|
||||
(*area).fill_rect(
|
||||
self.position.x,
|
||||
self.position.y,
|
||||
self.width,
|
||||
self.height,
|
||||
&self.source,
|
||||
&self.options,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct DrawArea<'a> {
|
||||
pub(super) width: f32,
|
||||
pub(super) height: f32,
|
||||
pub(super) position: Position,
|
||||
pub(super) source: Source<'a>,
|
||||
pub(super) options: DrawOptions,
|
||||
}
|
||||
|
||||
pub(super) struct DrawAreaBuilder<'a> {
|
||||
pub(super) width: Option<f32>,
|
||||
pub(super) height: Option<f32>,
|
||||
pub(super) position: Option<Position>,
|
||||
pub(super) source: Option<Source<'a>>,
|
||||
pub(super) color: Option<Color>,
|
||||
pub(super) options: Option<DrawOptions>,
|
||||
}
|
||||
|
||||
impl<'a> DrawAreaBuilder<'a> {
|
||||
pub(super) fn new() -> Self {
|
||||
Self {
|
||||
width: None,
|
||||
height: None,
|
||||
position: None,
|
||||
source: None,
|
||||
color: None,
|
||||
options: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn width(&mut self, width: f32) {
|
||||
self.width = Some(width)
|
||||
}
|
||||
|
||||
pub(super) fn height(&mut self, height: f32) {
|
||||
self.height = Some(height)
|
||||
}
|
||||
|
||||
pub(super) fn position(&mut self, x: f32, y: f32) {
|
||||
self.position = Some(Position::new(x, y))
|
||||
}
|
||||
|
||||
pub(super) fn source(&mut self, source: Source<'a>) {
|
||||
self.source = Some(source);
|
||||
}
|
||||
|
||||
pub(super) fn color(&mut self, r: u8, g: u8, b: u8) {
|
||||
self.color = Some(Color::new(0xff, r, g, b))
|
||||
}
|
||||
|
||||
pub(super) fn finish(self) -> Widget<'a> {
|
||||
Widget::DrawArea(
|
||||
DrawArea {
|
||||
width: self.width.expect("Draw area must have width"),
|
||||
height: self.height.expect("Draw area must have height"),
|
||||
position: self.position.expect("Draw area must have a position"),
|
||||
source: self.source.unwrap_or(
|
||||
Source::Solid(
|
||||
self.color.unwrap_or(Color::new(0xff, 0x00, 0x00, 0x00)).into()
|
||||
)
|
||||
),
|
||||
options: self.options.unwrap_or(DrawOptions::new()),
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Draw for DrawArea<'a> {
|
||||
fn render(&self, area: &mut DrawTarget<&mut [u32]>) {
|
||||
area.fill_rect(
|
||||
self.position.x,
|
||||
self.position.y,
|
||||
self.width,
|
||||
self.height,
|
||||
&self.source,
|
||||
&self.options,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub(super) struct TextArea<'a> {
|
||||
pub(super) width: f32,
|
||||
pub(super) height: f32,
|
||||
pub(super) position: Position,
|
||||
pub(super) source: Source<'a>,
|
||||
pub(super) options: DrawOptions,
|
||||
}
|
||||
|
||||
pub(super) struct TextAreaBuilder<'a> {
|
||||
pub(super) width: Option<f32>,
|
||||
pub(super) height: Option<f32>,
|
||||
pub(super) position: Option<Position>,
|
||||
pub(super) source: Option<Source<'a>>,
|
||||
pub(super) color: Option<Color>,
|
||||
pub(super) options: Option<DrawOptions>,
|
||||
}
|
||||
|
||||
impl<'a> TextAreaBuilder<'a> {
|
||||
pub(super) fn new() -> Self {
|
||||
Self {
|
||||
width: None,
|
||||
height: None,
|
||||
position: None,
|
||||
source: None,
|
||||
color: None,
|
||||
options: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn width(&mut self, width: f32) {
|
||||
self.width = Some(width)
|
||||
}
|
||||
|
||||
pub(super) fn height(&mut self, height: f32) {
|
||||
self.height = Some(height)
|
||||
}
|
||||
|
||||
pub(super) fn position(&mut self, x: f32, y: f32) {
|
||||
self.position = Some(Position::new(x, y))
|
||||
}
|
||||
|
||||
pub(super) fn source(&mut self, source: Source<'a>) {
|
||||
self.source = Some(source);
|
||||
}
|
||||
|
||||
pub(super) fn color(&mut self, r: u8, g: u8, b: u8) {
|
||||
self.color = Some(Color::new(0xff, r, g, b))
|
||||
}
|
||||
|
||||
pub(super) fn finish(self) -> Widget<'a> {
|
||||
Widget::TextArea(
|
||||
TextArea {
|
||||
width: self.width.expect("Button must have width"),
|
||||
height: self.height.expect("Button must have height"),
|
||||
position: self.position.expect("Button must have a position"),
|
||||
source: self.source.unwrap_or(
|
||||
Source::Solid(
|
||||
self.color.unwrap_or(Color::new(0xff, 0x00, 0x00, 0x00)).into()
|
||||
)
|
||||
),
|
||||
options: self.options.unwrap_or(DrawOptions::new()),
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Draw for TextArea<'a> {
|
||||
fn render(&self, area: &mut DrawTarget<&mut [u32]>) {
|
||||
|
||||
(*area).fill_rect(
|
||||
self.position.x,
|
||||
self.position.y,
|
||||
self.width,
|
||||
self.height,
|
||||
&self.source,
|
||||
&self.options,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user