Add drawing functionality to new ui

This commit is contained in:
2024-04-28 17:57:40 -05:00
parent f7490d00c3
commit b9f1424b54
2 changed files with 311 additions and 81 deletions

View File

@@ -5,7 +5,10 @@ use smithay_client_toolkit::{
output::{OutputHandler, OutputState}, output::{OutputHandler, OutputState},
registry::{RegistryState, ProvidesRegistryState}, registry::{RegistryState, ProvidesRegistryState},
registry_handlers, registry_handlers,
seat::{SeatState, SeatHandler, Capability}, seat::{
pointer::{PointerEvent, PointerEventKind, PointerHandler},
SeatState, SeatHandler, Capability
},
shell::{ shell::{
xdg::{ xdg::{
window::{WindowHandler, Window, WindowConfigure, WindowDecorations}, window::{WindowHandler, Window, WindowConfigure, WindowDecorations},
@@ -17,13 +20,14 @@ use smithay_client_toolkit::{
Shm, ShmHandler Shm, ShmHandler
}, },
delegate_registry, delegate_compositor, delegate_seat, delegate_output, delegate_registry, delegate_compositor, delegate_seat, delegate_output,
delegate_xdg_shell, delegate_shm, delegate_activation, delegate_xdg_window delegate_xdg_shell, delegate_shm, delegate_activation, delegate_xdg_window,
delegate_pointer,
}; };
use wayland_client::{ use wayland_client::{
Connection, QueueHandle, Connection, QueueHandle,
globals::registry_queue_init, globals::registry_queue_init,
protocol::{wl_surface, wl_output, wl_seat, wl_shm}, protocol::{wl_surface, wl_output, wl_seat, wl_shm, wl_pointer},
}; };
use std::time::Duration; use std::time::Duration;
@@ -31,10 +35,9 @@ use std::time::Duration;
use anyhow::Result; use anyhow::Result;
mod ui; mod ui;
mod pixel;
mod app; mod app;
use ui::{ButtonBuilder, DrawAreaBuilder, TextAreaBuilder}; use ui::{ButtonBuilder, DrawAreaBuilder, TextAreaBuilder, DrawPath, Position};
const WINDOW_HEIGHT: u32 = 256; const WINDOW_HEIGHT: u32 = 256;
@@ -83,15 +86,21 @@ pub(super) fn run() -> Result<()> {
registry_state: RegistryState::new(&globals), registry_state: RegistryState::new(&globals),
seat_state: SeatState::new(&globals, &qh), seat_state: SeatState::new(&globals, &qh),
output_state: OutputState::new(&globals, &qh), output_state: OutputState::new(&globals, &qh),
xdg_activation,
shm, shm,
buffer: None, buffer: None,
pool, pool,
window, window,
width: WINDOW_WIDTH, width: WINDOW_WIDTH,
height: WINDOW_HEIGHT, height: WINDOW_HEIGHT,
cursor_down: false,
exit: false, exit: false,
first_configure: true, first_configure: true,
pointer: None,
_loop_handle: event_loop.handle(), _loop_handle: event_loop.handle(),
draw_path: DrawPath::new(),
}; };
loop { loop {
@@ -112,14 +121,20 @@ struct SimpleWindow {
seat_state: SeatState, seat_state: SeatState,
output_state: OutputState, output_state: OutputState,
shm: Shm, shm: Shm,
xdg_activation: Option<ActivationState>,
buffer: Option<Buffer>, buffer: Option<Buffer>,
pool: SlotPool, pool: SlotPool,
window: Window, window: Window,
width: u32, width: u32,
height: u32, height: u32,
cursor_down: bool,
exit: bool, exit: bool,
first_configure: bool, first_configure: bool,
_loop_handle: LoopHandle<'static, SimpleWindow> pointer: Option<wl_pointer::WlPointer>,
_loop_handle: LoopHandle<'static, SimpleWindow>,
draw_path: DrawPath,
} }
impl CompositorHandler for SimpleWindow { impl CompositorHandler for SimpleWindow {
@@ -142,14 +157,15 @@ impl CompositorHandler for SimpleWindow {
_: &wl_surface::WlSurface, _: &wl_surface::WlSurface,
_: u32 _: u32
) { ) {
self.draw(conn, qh); self.draw(conn, qh);
} }
} }
impl SeatHandler for SimpleWindow { impl SeatHandler for SimpleWindow {
fn seat_state(&mut self) -> &mut SeatState { fn seat_state(&mut self) -> &mut SeatState {
&mut self.seat_state &mut self.seat_state
} }
fn new_seat( fn new_seat(
&mut self, &mut self,
_: &Connection, _: &Connection,
@@ -159,17 +175,28 @@ impl SeatHandler for SimpleWindow {
fn new_capability( fn new_capability(
&mut self, &mut self,
_: &Connection, _: &Connection,
_: &QueueHandle<Self>, qh: &QueueHandle<Self>,
_: wl_seat::WlSeat, seat: wl_seat::WlSeat,
_: Capability, capability: Capability,
) {} ) {
if capability == Capability::Pointer && self.pointer.is_none() {
println!("Set pointer capability");
let pointer = self.seat_state.get_pointer(qh, &seat).expect("Failed to create pointer");
self.pointer = Some(pointer);
}
}
fn remove_capability( fn remove_capability(
&mut self, &mut self,
_: &Connection, _: &Connection,
_: &QueueHandle<Self>, _: &QueueHandle<Self>,
_: wl_seat::WlSeat, _: wl_seat::WlSeat,
_: Capability, capability: Capability,
) {} ) {
if capability == Capability::Pointer && self.pointer.is_some() {
println!("Unset pointer capability");
self.pointer.take().unwrap().release();
}
}
fn remove_seat( fn remove_seat(
&mut self, &mut self,
_: &Connection, _: &Connection,
@@ -236,7 +263,57 @@ impl ShmHandler for SimpleWindow {
impl ActivationHandler for SimpleWindow { impl ActivationHandler for SimpleWindow {
type RequestData = RequestData; type RequestData = RequestData;
fn new_token(&mut self, _: String, _: &Self::RequestData) {} fn new_token(&mut self, token: String, _: &Self::RequestData) {
self.xdg_activation
.as_ref()
.unwrap()
.activate::<SimpleWindow>(self.window.wl_surface(), token);
}
}
impl PointerHandler for SimpleWindow {
fn pointer_frame(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_pointer: &wl_pointer::WlPointer,
events: &[PointerEvent],
) {
use PointerEventKind::*;
for event in events {
// Ignore events for other surfaces
if &event.surface != self.window.wl_surface() {
continue;
}
match event.kind {
Enter { .. } => {
println!("Pointer entered @{:?}", event.position);
}
Leave { .. } => {
println!("Pointer left");
}
Motion { .. } => {
if self.cursor_down {
self.draw_path.add_point(Position::new(event.position.0 as f32, event.position.1 as f32), false);
}
}
Press { button, .. } => {
println!("Press {:x} @ {:?}", button, event.position);
self.cursor_down = true;
self.draw_path.add_point(Position::new(event.position.0 as f32, event.position.1 as f32), true)
}
Release { button, .. } => {
println!("Release {:x} @ {:?}", button, event.position);
self.cursor_down = false;
self.draw_path.add_point(Position::new(event.position.0 as f32, event.position.1 as f32), false)
}
Axis { horizontal, vertical, .. } => {
println!("Scroll H:{horizontal:?}, V:{vertical:?}");
}
}
}
}
} }
impl SimpleWindow { impl SimpleWindow {
@@ -280,13 +357,12 @@ impl SimpleWindow {
button.position(self.width as f32 - 100.0, 50.0); button.position(self.width as f32 - 100.0, 50.0);
button.width(100.0); button.width(100.0);
button.height(50.0); button.height(50.0);
button.color(0x33, 0x33, 0x33);
let button = button.finish(); let button = button.finish();
draw_area.position(0.0, 50.0); draw_area.position(0.0, 50.0);
draw_area.width(self.width as f32 - 100.0); draw_area.width(self.width as f32 - 100.0);
draw_area.height(self.height as f32 - 50.0); draw_area.height(self.height as f32 - 50.0);
draw_area.color(0x15, 0x15, 0x15); draw_area.path(&self.draw_path);
let draw_area = draw_area.finish(); let draw_area = draw_area.finish();
@@ -294,7 +370,6 @@ impl SimpleWindow {
text_area.position(0.0, 0.0); text_area.position(0.0, 0.0);
text_area.width(self.width as f32); text_area.width(self.width as f32);
text_area.height(50.0); text_area.height(50.0);
text_area.color(0x22, 0x22, 0x22);
let text_area = text_area.finish(); let text_area = text_area.finish();
window.add_widget(button); window.add_widget(button);
@@ -322,6 +397,8 @@ delegate_xdg_shell!(SimpleWindow);
delegate_xdg_window!(SimpleWindow); delegate_xdg_window!(SimpleWindow);
delegate_activation!(SimpleWindow); delegate_activation!(SimpleWindow);
delegate_pointer!(SimpleWindow);
delegate_registry!(SimpleWindow); delegate_registry!(SimpleWindow);
impl ProvidesRegistryState for SimpleWindow { impl ProvidesRegistryState for SimpleWindow {

View File

@@ -1,4 +1,3 @@
use crate::wayland::pixel::{Pixel, Box, BoxMut, PixelEncoding};
use raqote::{DrawTarget, PathBuilder, Source, StrokeStyle, DrawOptions, SolidSource, Color}; use raqote::{DrawTarget, PathBuilder, Source, StrokeStyle, DrawOptions, SolidSource, Color};
struct UIColor { struct UIColor {
@@ -72,11 +71,77 @@ impl<'a, 'b> Window<'a, 'b> {
} }
} }
#[derive(Clone, Copy, Debug)]
pub(super) struct Position { pub(super) struct Position {
pub(super) x: f32, pub(super) x: f32,
pub(super) y: f32, pub(super) y: f32,
} }
pub(super) struct Path(Vec<Position>);
impl IntoIterator for Path {
type Item = Position;
type IntoIter = std::vec::IntoIter<Position>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<'a> IntoIterator for &'a Path {
type Item = &'a Position;
type IntoIter = std::slice::Iter<'a, Position>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
pub(super) struct DrawPath {
pub(super) paths: Vec<Path>,
pub(super) newline: bool,
}
impl DrawPath {
pub(super) fn new() -> Self {
Self {
paths: Vec::new(),
newline: false,
}
}
pub(super) fn add_point(&mut self, point: Position, newline: bool) {
if newline {
self.paths.push(Path(vec![point]))
} else if self.paths.len() > 0 {
self.paths
.last_mut()
.unwrap()
.0
.push(point);
}
}
}
impl IntoIterator for DrawPath {
type Item = Path;
type IntoIter = std::vec::IntoIter<Path>;
fn into_iter(self) -> Self::IntoIter {
self.paths.into_iter()
}
}
impl<'a> IntoIterator for &'a DrawPath {
type Item = &'a Path;
type IntoIter = std::slice::Iter<'a, Path>;
fn into_iter(self) -> Self::IntoIter {
self.paths.iter()
}
}
impl Position { impl Position {
pub(super) fn new(x: f32, y: f32) -> Self { pub(super) fn new(x: f32, y: f32) -> Self {
Position { x, y } Position { x, y }
@@ -84,40 +149,60 @@ impl Position {
} }
pub(super) enum Widget<'a> { pub(super) enum Widget<'a> {
Button(Button<'a>), Button(Button),
DrawArea(DrawArea<'a>), DrawArea(DrawArea<'a>),
TextArea(TextArea<'a>) TextArea(TextArea)
} }
pub(super) trait Draw { pub(super) trait Draw {
fn render(&self, area: &mut DrawTarget<&mut [u32]>); fn render(&self, area: &mut DrawTarget<&mut [u32]>);
} }
pub(super) struct Button<'a> { pub(super) struct ButtonColors {
background: Color,
border: Color,
glyph: Color,
}
impl Default for ButtonColors {
fn default() -> Self {
Self {
background: Color::new(0xff, 0x25, 0x2c, 0x33),
border: Color::new(0xff, 0x77, 0x7f, 0x97),
glyph: Color::new(0xff, 0xea, 0xea, 0xe6),
}
}
}
pub(super) struct Button {
pub(super) width: f32, pub(super) width: f32,
pub(super) height: f32, pub(super) height: f32,
pub(super) position: Position, pub(super) position: Position,
pub(super) source: Source<'a>, pub(super) colors: ButtonColors,
pub(super) options: DrawOptions, pub(super) options: DrawOptions,
} }
pub(super) struct ButtonBuilder<'a> { impl Button {
fn background_source(&self) -> Source {
Source::Solid(self.colors.background.into())
}
}
pub(super) struct ButtonBuilder {
pub(super) width: Option<f32>, pub(super) width: Option<f32>,
pub(super) height: Option<f32>, pub(super) height: Option<f32>,
pub(super) position: Option<Position>, pub(super) position: Option<Position>,
pub(super) source: Option<Source<'a>>, pub(super) colors: Option<ButtonColors>,
pub(super) color: Option<Color>,
pub(super) options: Option<DrawOptions>, pub(super) options: Option<DrawOptions>,
} }
impl<'a> ButtonBuilder<'a> { impl<'a> ButtonBuilder {
pub(super) fn new() -> Self { pub(super) fn new() -> Self {
Self { Self {
width: None, width: None,
height: None, height: None,
position: None, position: None,
source: None, colors: None,
color: None,
options: None, options: None,
} }
} }
@@ -134,12 +219,8 @@ impl<'a> ButtonBuilder<'a> {
self.position = Some(Position::new(x, y)) self.position = Some(Position::new(x, y))
} }
pub(super) fn source(&mut self, source: Source<'a>) { pub(super) fn colors(&mut self, colors: ButtonColors) {
self.source = Some(source); self.colors = Some(colors)
}
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> { pub(super) fn finish(self) -> Widget<'a> {
@@ -148,18 +229,14 @@ impl<'a> ButtonBuilder<'a> {
width: self.width.expect("Button must have width"), width: self.width.expect("Button must have width"),
height: self.height.expect("Button must have height"), height: self.height.expect("Button must have height"),
position: self.position.expect("Button must have a position"), position: self.position.expect("Button must have a position"),
source: self.source.unwrap_or( colors: self.colors.unwrap_or_default(),
Source::Solid(
self.color.unwrap_or(Color::new(0xff, 0x00, 0x00, 0x00)).into()
)
),
options: self.options.unwrap_or(DrawOptions::new()), options: self.options.unwrap_or(DrawOptions::new()),
} }
) )
} }
} }
impl<'a> Draw for Button<'a> { impl Draw for Button {
fn render(&self, area: &mut DrawTarget<&mut [u32]>) { fn render(&self, area: &mut DrawTarget<&mut [u32]>) {
(*area).fill_rect( (*area).fill_rect(
@@ -167,26 +244,58 @@ impl<'a> Draw for Button<'a> {
self.position.y, self.position.y,
self.width, self.width,
self.height, self.height,
&self.source, &self.background_source(),
&self.options, &self.options,
) )
} }
} }
pub(super) struct DrawAreaColors {
background_color: Color,
drawing_color: Color,
border_color: Color,
}
impl Default for DrawAreaColors {
fn default() -> Self {
Self {
background_color: Color::new(0xff, 0x4a, 0x4e, 0x64),
drawing_color: Color::new(0xff, 0xea, 0xea, 0xe6),
border_color: Color::new(0xff, 0x77, 0x7f, 0x97),
}
}
}
pub(super) struct DrawArea<'a> { pub(super) struct DrawArea<'a> {
pub(super) width: f32, pub(super) width: f32,
pub(super) height: f32, pub(super) height: f32,
pub(super) position: Position, pub(super) position: Position,
pub(super) source: Source<'a>, pub(super) path: &'a DrawPath,
pub(super) colors: DrawAreaColors,
pub(super) options: DrawOptions, pub(super) options: DrawOptions,
} }
impl DrawArea<'_> {
fn background_source(&self) -> Source {
Source::Solid(self.colors.background_color.into())
}
fn drawing_source(&self) -> Source {
Source::Solid(self.colors.drawing_color.into())
}
fn border_source(&self) -> Source {
Source::Solid(self.colors.border_color.into())
}
}
pub(super) struct DrawAreaBuilder<'a> { pub(super) struct DrawAreaBuilder<'a> {
pub(super) width: Option<f32>, pub(super) width: Option<f32>,
pub(super) height: Option<f32>, pub(super) height: Option<f32>,
pub(super) position: Option<Position>, pub(super) position: Option<Position>,
pub(super) source: Option<Source<'a>>, pub(super) path: Option<&'a DrawPath>,
pub(super) color: Option<Color>, pub(super) colors: Option<DrawAreaColors>,
pub(super) options: Option<DrawOptions>, pub(super) options: Option<DrawOptions>,
} }
@@ -196,8 +305,8 @@ impl<'a> DrawAreaBuilder<'a> {
width: None, width: None,
height: None, height: None,
position: None, position: None,
source: None, path: None,
color: None, colors: None,
options: None, options: None,
} }
} }
@@ -214,12 +323,12 @@ impl<'a> DrawAreaBuilder<'a> {
self.position = Some(Position::new(x, y)) self.position = Some(Position::new(x, y))
} }
pub(super) fn source(&mut self, source: Source<'a>) { pub(super) fn colors(&mut self, colors: DrawAreaColors) {
self.source = Some(source); self.colors = Some(colors)
} }
pub(super) fn color(&mut self, r: u8, g: u8, b: u8) { pub(super) fn path(&mut self, path: &'a DrawPath) {
self.color = Some(Color::new(0xff, r, g, b)) self.path = Some(path);
} }
pub(super) fn finish(self) -> Widget<'a> { pub(super) fn finish(self) -> Widget<'a> {
@@ -228,56 +337,104 @@ impl<'a> DrawAreaBuilder<'a> {
width: self.width.expect("Draw area must have width"), width: self.width.expect("Draw area must have width"),
height: self.height.expect("Draw area must have height"), height: self.height.expect("Draw area must have height"),
position: self.position.expect("Draw area must have a position"), position: self.position.expect("Draw area must have a position"),
source: self.source.unwrap_or( path: self.path.expect("Draw must have a path"),
Source::Solid( colors: self.colors.unwrap_or_default(),
self.color.unwrap_or(Color::new(0xff, 0x00, 0x00, 0x00)).into()
)
),
options: self.options.unwrap_or(DrawOptions::new()), options: self.options.unwrap_or(DrawOptions::new()),
} }
) )
} }
} }
impl<'a> Draw for DrawArea<'a> { impl Draw for DrawArea<'_> {
fn render(&self, area: &mut DrawTarget<&mut [u32]>) { fn render(&self, area: &mut DrawTarget<&mut [u32]>) {
let mut draw_path = PathBuilder::new();
for path in self.path.into_iter() {
if path.0.len() > 1 {
let mut path = path.into_iter();
let first_point = path
.by_ref()
.next();
draw_path.move_to(first_point.unwrap().x, first_point.unwrap().y);
for point in path {
draw_path.line_to(point.x, point.y);
}
}
}
let path = draw_path.finish();
area.fill_rect( area.fill_rect(
self.position.x, self.position.x,
self.position.y, self.position.y,
self.width, self.width,
self.height, self.height,
&self.source, &self.background_source(),
&self.options, &self.options,
) );
area.stroke(
&path,
&self.drawing_source(),
&StrokeStyle {width: 3.0, ..StrokeStyle::default()},
&self.options,
);
} }
} }
pub(super) struct TextArea<'a> { pub(super) struct TextAreaColors {
pub(super) background: Color,
pub(super) text: Color,
}
impl Default for TextAreaColors {
fn default() -> Self {
Self {
background: Color::new(0xff, 0x25, 0x2c, 0x33),
text: Color::new(0xff, 0xfc, 0xf8, 0xef),
}
}
}
pub(super) struct TextArea {
pub(super) width: f32, pub(super) width: f32,
pub(super) height: f32, pub(super) height: f32,
pub(super) position: Position, pub(super) position: Position,
pub(super) source: Source<'a>, pub(super) colors: TextAreaColors,
pub(super) options: DrawOptions, pub(super) options: DrawOptions,
} }
pub(super) struct TextAreaBuilder<'a> { impl TextArea {
pub(super) fn text_source(&self) -> Source {
Source::Solid(self.colors.text.into())
}
pub(super) fn background_source(&self) -> Source {
Source::Solid(self.colors.background.into())
}
}
pub(super) struct TextAreaBuilder {
pub(super) width: Option<f32>, pub(super) width: Option<f32>,
pub(super) height: Option<f32>, pub(super) height: Option<f32>,
pub(super) position: Option<Position>, pub(super) position: Option<Position>,
pub(super) source: Option<Source<'a>>, pub(super) colors: Option<TextAreaColors>,
pub(super) color: Option<Color>,
pub(super) options: Option<DrawOptions>, pub(super) options: Option<DrawOptions>,
} }
impl<'a> TextAreaBuilder<'a> { impl<'a> TextAreaBuilder {
pub(super) fn new() -> Self { pub(super) fn new() -> Self {
Self { Self {
width: None, width: None,
height: None, height: None,
position: None, position: None,
source: None, colors: None,
color: None,
options: None, options: None,
} }
} }
@@ -294,12 +451,9 @@ impl<'a> TextAreaBuilder<'a> {
self.position = Some(Position::new(x, y)) 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) { pub(super) fn colors(&mut self, colors: TextAreaColors) {
self.color = Some(Color::new(0xff, r, g, b)) self.colors = Some(colors);
} }
pub(super) fn finish(self) -> Widget<'a> { pub(super) fn finish(self) -> Widget<'a> {
@@ -308,28 +462,27 @@ impl<'a> TextAreaBuilder<'a> {
width: self.width.expect("Button must have width"), width: self.width.expect("Button must have width"),
height: self.height.expect("Button must have height"), height: self.height.expect("Button must have height"),
position: self.position.expect("Button must have a position"), position: self.position.expect("Button must have a position"),
source: self.source.unwrap_or( colors: self.colors.unwrap_or_default(),
Source::Solid(
self.color.unwrap_or(Color::new(0xff, 0x00, 0x00, 0x00)).into()
)
),
options: self.options.unwrap_or(DrawOptions::new()), options: self.options.unwrap_or(DrawOptions::new()),
} }
) )
} }
} }
impl<'a> Draw for TextArea<'a> { impl Draw for TextArea {
fn render(&self, area: &mut DrawTarget<&mut [u32]>) { fn render(&self, area: &mut DrawTarget<&mut [u32]>) {
(*area).fill_rect( area.fill_rect(
self.position.x, self.position.x,
self.position.y, self.position.y,
self.width, self.width,
self.height, self.height,
&self.source, &self.background_source(),
&self.options, &self.options,
) );
} }
} }