Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
218
third-party/vendor/orbclient/src/blur.rs
vendored
Normal file
218
third-party/vendor/orbclient/src/blur.rs
vendored
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/*
|
||||
Inspired from http://blog.ivank.net/fastest-gaussian-blur.html the algorithm 4.
|
||||
The struct MathColor is needed for the calculate with bigger numbers, the Color struct save the r,g,b values with a u8.
|
||||
*/
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use core::ops::{Add, AddAssign, Sub};
|
||||
use crate::color::Color;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct MathColor {
|
||||
pub r: isize,
|
||||
pub g: isize,
|
||||
pub b: isize,
|
||||
}
|
||||
|
||||
impl MathColor {
|
||||
pub fn new(color: Color) -> Self {
|
||||
MathColor {
|
||||
r: color.r() as isize,
|
||||
g: color.g() as isize,
|
||||
b: color.b() as isize,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_multiplied_color(&mut self, iarr: f32) -> Color {
|
||||
Color::rgb(
|
||||
(self.r as f32 * iarr).round() as u8,
|
||||
(self.g as f32 * iarr).round() as u8,
|
||||
(self.b as f32 * iarr).round() as u8,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for MathColor {
|
||||
type Output = MathColor;
|
||||
|
||||
#[inline(always)]
|
||||
fn add(self, color: MathColor) -> MathColor {
|
||||
MathColor {
|
||||
r: self.r + color.r,
|
||||
g: self.g + color.g,
|
||||
b: self.b + color.b,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for MathColor {
|
||||
#[inline(always)]
|
||||
fn add_assign(&mut self, color: MathColor) {
|
||||
*self = MathColor {
|
||||
r: self.r + color.r,
|
||||
g: self.g + color.g,
|
||||
b: self.b + color.b,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for MathColor {
|
||||
type Output = MathColor;
|
||||
|
||||
#[inline(always)]
|
||||
fn sub(self, color: MathColor) -> MathColor {
|
||||
MathColor {
|
||||
r: self.r - color.r,
|
||||
g: self.g - color.g,
|
||||
b: self.b - color.b,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gauss_blur(data: &mut [Color], w: u32, h: u32, r: f32) {
|
||||
let bxs = boxes_for_gauss(r, 3);
|
||||
let mut tcl = data.to_owned();
|
||||
|
||||
box_blur(
|
||||
&mut tcl,
|
||||
data,
|
||||
w as usize,
|
||||
h as usize,
|
||||
((bxs[0] - 1) / 2) as usize,
|
||||
);
|
||||
box_blur(
|
||||
&mut tcl,
|
||||
data,
|
||||
w as usize,
|
||||
h as usize,
|
||||
((bxs[1] - 1) / 2) as usize,
|
||||
);
|
||||
box_blur(
|
||||
&mut tcl,
|
||||
data,
|
||||
w as usize,
|
||||
h as usize,
|
||||
((bxs[2] - 1) / 2) as usize,
|
||||
);
|
||||
}
|
||||
|
||||
fn boxes_for_gauss(sigma: f32, n: usize) -> Vec<i32> {
|
||||
let w_ideal: f32 = ((12.0 * sigma * sigma / n as f32) + 1.0).sqrt();
|
||||
let mut wl: i32 = w_ideal.floor() as i32;
|
||||
if wl % 2 == 0 {
|
||||
wl -= 1;
|
||||
};
|
||||
let wu: i32 = wl + 2;
|
||||
|
||||
let m_ideal: f32 = (12.0 * sigma * sigma
|
||||
- n as f32 * wl as f32 * wl as f32
|
||||
- 4.0 * n as f32 * wl as f32
|
||||
- 3.0 * n as f32)
|
||||
/ (-4.0 * wl as f32 - 4.0);
|
||||
let m: usize = m_ideal.round() as usize;
|
||||
|
||||
let mut sizes = Vec::<i32>::new();
|
||||
for i in 0..n {
|
||||
sizes.push(if i < m { wl } else { wu });
|
||||
}
|
||||
sizes
|
||||
}
|
||||
|
||||
fn box_blur(tcl: &mut [Color], scl: &mut [Color], w: usize, h: usize, r: usize) {
|
||||
box_blur_t(scl, tcl, w, h, r);
|
||||
box_blur_h(tcl, scl, w, h, r);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn box_blur_h(tcl: &mut [Color], scl: &mut [Color], w: usize, h: usize, r: usize) {
|
||||
let iarr: f32 = 1.0 / (r + r + 1) as f32;
|
||||
|
||||
for i in 0..h {
|
||||
let mut ti: usize = i * w;
|
||||
let mut li: usize = ti;
|
||||
let mut ri: usize = ti + r;
|
||||
let fv = MathColor::new(tcl[ti]);
|
||||
let lv = MathColor::new(tcl[ti + w - 1]);
|
||||
|
||||
let mut val: MathColor = MathColor {
|
||||
r: (r + 1) as isize * fv.r,
|
||||
g: (r + 1) as isize * fv.g,
|
||||
b: (r + 1) as isize * fv.b,
|
||||
};
|
||||
|
||||
for j in 0..r {
|
||||
val += MathColor::new(tcl[ti + j]);
|
||||
}
|
||||
|
||||
for _ in 0..(r + 1) {
|
||||
val += MathColor::new(tcl[ri]) - fv;
|
||||
scl[ti] = val.get_multiplied_color(iarr);
|
||||
ti += 1;
|
||||
ri += 1;
|
||||
}
|
||||
|
||||
for _ in (r + 1)..(w - r) {
|
||||
val += MathColor::new(tcl[ri]) - MathColor::new(tcl[li]);
|
||||
scl[ti] = val.get_multiplied_color(iarr);
|
||||
ti += 1;
|
||||
ri += 1;
|
||||
li += 1;
|
||||
}
|
||||
|
||||
for _ in (w - r)..w {
|
||||
val += lv - MathColor::new(tcl[li]);
|
||||
scl[ti] = val.get_multiplied_color(iarr);
|
||||
ti += 1;
|
||||
li += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn box_blur_t(tcl: &mut [Color], scl: &mut [Color], w: usize, h: usize, r: usize) {
|
||||
let iarr: f32 = 1.0 / (r + r + 1) as f32;
|
||||
|
||||
for i in 0..w {
|
||||
let mut ti: usize = i;
|
||||
let mut li: usize = ti;
|
||||
let mut ri: usize = ti + r * w;
|
||||
let fv = MathColor::new(tcl[ti]);
|
||||
let lv = MathColor::new(tcl[ti + w * (h - 1)]);
|
||||
|
||||
let mut val: MathColor = MathColor {
|
||||
r: (r + 1) as isize * fv.r,
|
||||
g: (r + 1) as isize * fv.g,
|
||||
b: (r + 1) as isize * fv.b,
|
||||
};
|
||||
|
||||
for j in 0..r {
|
||||
val += MathColor::new(tcl[ti + j * w]);
|
||||
}
|
||||
|
||||
for _ in 0..(r + 1) {
|
||||
val += MathColor::new(tcl[ri]) - fv;
|
||||
scl[ti] = val.get_multiplied_color(iarr);
|
||||
ti += w;
|
||||
ri += w;
|
||||
}
|
||||
|
||||
for _ in (r + 1)..(h - r) {
|
||||
val += MathColor::new(tcl[ri]) - MathColor::new(tcl[li]);
|
||||
scl[ti] = val.get_multiplied_color(iarr);
|
||||
ti += w;
|
||||
ri += w;
|
||||
li += w;
|
||||
}
|
||||
|
||||
for _ in (h - r)..h {
|
||||
val += lv - MathColor::new(tcl[li]);
|
||||
scl[ti] = val.get_multiplied_color(iarr);
|
||||
ti += w;
|
||||
li += w;
|
||||
}
|
||||
}
|
||||
}
|
||||
203
third-party/vendor/orbclient/src/color.rs
vendored
Normal file
203
third-party/vendor/orbclient/src/color.rs
vendored
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use core::fmt;
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::de::{self, Deserializer};
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::Deserialize;
|
||||
|
||||
/// A color
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(transparent)]
|
||||
pub struct Color {
|
||||
pub data: u32,
|
||||
}
|
||||
|
||||
impl Color {
|
||||
/// Create a new color from RGB
|
||||
pub const fn rgb(r: u8, g: u8, b: u8) -> Self {
|
||||
Color {
|
||||
data: 0xFF000000 | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the alpha
|
||||
pub const fn rgba(r: u8, g: u8, b: u8, a: u8) -> Self {
|
||||
Color {
|
||||
data: ((a as u32) << 24) | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the r value
|
||||
pub fn r(&self) -> u8 {
|
||||
((self.data & 0x00FF0000) >> 16) as u8
|
||||
}
|
||||
|
||||
/// Get the g value
|
||||
pub fn g(&self) -> u8 {
|
||||
((self.data & 0x0000FF00) >> 8) as u8
|
||||
}
|
||||
|
||||
/// Get the b value
|
||||
pub fn b(&self) -> u8 {
|
||||
(self.data & 0x000000FF) as u8
|
||||
}
|
||||
|
||||
/// Get the alpha value
|
||||
pub fn a(&self) -> u8 {
|
||||
((self.data & 0xFF000000) >> 24) as u8
|
||||
}
|
||||
|
||||
/// Interpolate between two colors
|
||||
pub fn interpolate(start_color: Color, end_color: Color, scale: f64) -> Color {
|
||||
let r = Color::interp(start_color.r(), end_color.r(), scale);
|
||||
let g = Color::interp(start_color.g(), end_color.g(), scale);
|
||||
let b = Color::interp(start_color.b(), end_color.b(), scale);
|
||||
let a = Color::interp(start_color.a(), end_color.a(), scale);
|
||||
Color::rgba(r, g, b, a)
|
||||
}
|
||||
|
||||
fn interp(start_color: u8, end_color: u8, scale: f64) -> u8 {
|
||||
((end_color as f64 - start_color as f64) * scale + start_color as f64) as u8
|
||||
}
|
||||
}
|
||||
|
||||
/// Compare two colors (Do not take care of alpha)
|
||||
impl PartialEq for Color {
|
||||
fn eq(&self, other: &Color) -> bool {
|
||||
self.r() == other.r() && self.g() == other.g() && self.b() == other.b()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Color {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
write!(f, "{:#010X}", { self.data })
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl<'de> Deserialize<'de> for Color {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Color, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_i32(ColorVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
struct ColorVisitor;
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl<'de> de::Visitor<'de> for ColorVisitor {
|
||||
type Value = Color;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("Color specification in HEX format '#ARGB'")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, color_spec: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
if color_spec.len() != 9 {
|
||||
return Err(E::custom(format!("Color spec must be of format '#AARRGGBB' ('{}')", color_spec)))
|
||||
}
|
||||
|
||||
if &color_spec[0..1] != "#" {
|
||||
return Err(E::custom(format!("Color spec must begin with '#' ('{}')", color_spec)));
|
||||
}
|
||||
|
||||
let a = u8::from_str_radix(&color_spec[1..3], 16)
|
||||
.map_err(|e| E::custom(e))?;
|
||||
let r = u8::from_str_radix(&color_spec[3..5], 16)
|
||||
.map_err(|e| E::custom(e.to_string()))?;
|
||||
let g = u8::from_str_radix(&color_spec[5..7], 16)
|
||||
.map_err(|e| E::custom(e.to_string()))?;
|
||||
let b = u8::from_str_radix(&color_spec[7..9], 16)
|
||||
.map_err(|e| E::custom(e.to_string()))?;
|
||||
|
||||
Ok(Color::rgba(r, g, b, a))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn partial_eq() {
|
||||
assert_eq!(Color::rgb(1, 2, 3), Color::rgba(1, 2, 3, 200));
|
||||
assert_ne!(Color::rgb(1, 2, 3), Color::rgba(11, 2, 3, 200));
|
||||
assert_eq!(Color::rgba(1, 2, 3, 200), Color::rgba(1, 2, 3, 200));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn alignment() {
|
||||
assert_eq!(4, core::mem::size_of::<Color>());
|
||||
assert_eq!(8, core::mem::size_of::<[Color; 2]>());
|
||||
assert_eq!(12, core::mem::size_of::<[Color; 3]>());
|
||||
assert_eq!(16, core::mem::size_of::<[Color; 4]>());
|
||||
assert_eq!(20, core::mem::size_of::<[Color; 5]>());
|
||||
}
|
||||
|
||||
#[cfg(features = "serde")]
|
||||
mod serde {
|
||||
use serde_derive::Deserialize;
|
||||
use toml;
|
||||
use crate::Color;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct TestColor {
|
||||
color: Color,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deserialize_ok() {
|
||||
let color_spec = r##"color = "#00010203""##;
|
||||
let test_color: TestColor = toml::from_str(color_spec).expect("Color spec did not parse correctly");
|
||||
assert_eq!(test_color.color.a(), 0, "Alpha channel incorrect");
|
||||
assert_eq!(test_color.color.r(), 1, "Red channel incorrect");
|
||||
assert_eq!(test_color.color.g(), 2, "Green channel incorrect");
|
||||
assert_eq!(test_color.color.b(), 3, "Blue channel incorrect");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deserialize_hex() {
|
||||
let color_spec = r##"color = "#AABBCCDD""##;
|
||||
let _: TestColor = toml::from_str(color_spec).expect("Color spec did not parse HEX correctly");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deserialize_no_hash() {
|
||||
let color_spec = r##"color = "$00010203""##;
|
||||
let test_color: Result<TestColor, _> = toml::from_str(color_spec);
|
||||
assert!(test_color.is_err(), "Color spec should not parse correctly without leading '#'");
|
||||
assert!(test_color.err().unwrap().to_string().contains("must begin with '#'"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deserialize_not_hex() {
|
||||
let color_spec = r##"color = "#GG010203""##;
|
||||
let test_color: Result<TestColor, _> = toml::from_str(color_spec);
|
||||
assert!(test_color.is_err(), "Color spec should not parse invalid HEX correctly");
|
||||
assert!(test_color.err().unwrap().to_string().contains("invalid digit"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deserialize_str_too_long() {
|
||||
let color_spec = r##"color = "#0001020304""##;
|
||||
let test_color: Result<TestColor, _> = toml::from_str(color_spec);
|
||||
assert!(test_color.is_err(), "Color spec should not parse invalid spec correctly");
|
||||
assert!(test_color.err().unwrap().to_string().contains("must be of format '#AARRGGBB'"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deserialize_str_too_short() {
|
||||
let color_spec = r##"color = "#000102""##;
|
||||
let test_color: Result<TestColor, _> = toml::from_str(color_spec);
|
||||
assert!(test_color.is_err(), "Color spec should not parse invalid spec correctly");
|
||||
assert!(test_color.err().unwrap().to_string().contains("must be of format '#AARRGGBB'"));
|
||||
}
|
||||
}
|
||||
}
|
||||
647
third-party/vendor/orbclient/src/event.rs
vendored
Normal file
647
third-party/vendor/orbclient/src/event.rs
vendored
Normal file
|
|
@ -0,0 +1,647 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use core::{char, mem, slice};
|
||||
|
||||
pub const EVENT_NONE: i64 = 0;
|
||||
pub const EVENT_KEY: i64 = 1;
|
||||
pub const EVENT_MOUSE: i64 = 2;
|
||||
pub const EVENT_BUTTON: i64 = 3;
|
||||
pub const EVENT_SCROLL: i64 = 4;
|
||||
pub const EVENT_QUIT: i64 = 5;
|
||||
pub const EVENT_FOCUS: i64 = 6;
|
||||
pub const EVENT_MOVE: i64 = 7;
|
||||
pub const EVENT_RESIZE: i64 = 8;
|
||||
pub const EVENT_SCREEN: i64 = 9;
|
||||
pub const EVENT_CLIPBOARD: i64 = 10;
|
||||
pub const EVENT_MOUSE_RELATIVE: i64 = 11;
|
||||
pub const EVENT_DROP: i64 = 12;
|
||||
pub const EVENT_TEXT_INPUT: i64 = 13;
|
||||
pub const EVENT_CLIPBOARD_UPDATE: i64 = 14;
|
||||
pub const EVENT_HOVER: i64 = 15;
|
||||
|
||||
/// An optional event
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum EventOption {
|
||||
/// A key event
|
||||
Key(KeyEvent),
|
||||
/// A text input event
|
||||
TextInput(TextInputEvent),
|
||||
/// A mouse event (absolute)
|
||||
Mouse(MouseEvent),
|
||||
/// A mouse event (relative)
|
||||
MouseRelative(MouseRelativeEvent),
|
||||
/// A mouse button event
|
||||
Button(ButtonEvent),
|
||||
/// A mouse scroll event
|
||||
Scroll(ScrollEvent),
|
||||
/// A quit request event
|
||||
Quit(QuitEvent),
|
||||
/// A focus event
|
||||
Focus(FocusEvent),
|
||||
/// A move event
|
||||
Move(MoveEvent),
|
||||
/// A resize event
|
||||
Resize(ResizeEvent),
|
||||
/// A screen report event
|
||||
Screen(ScreenEvent),
|
||||
/// A clipboard event
|
||||
Clipboard(ClipboardEvent),
|
||||
/// A clipboard update event
|
||||
ClipboardUpdate(ClipboardUpdateEvent),
|
||||
/// A drop file / text event (available on linux, windows and macOS)
|
||||
Drop(DropEvent),
|
||||
/// A hover event
|
||||
Hover(HoverEvent),
|
||||
/// An unknown event
|
||||
Unknown(Event),
|
||||
/// No event
|
||||
None,
|
||||
}
|
||||
|
||||
/// An event
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(packed)]
|
||||
pub struct Event {
|
||||
pub code: i64,
|
||||
pub a: i64,
|
||||
pub b: i64,
|
||||
}
|
||||
|
||||
#[allow(clippy::new_without_default)]
|
||||
impl Event {
|
||||
/// Create a null event
|
||||
pub fn new() -> Event {
|
||||
Event {
|
||||
code: 0,
|
||||
a: 0,
|
||||
b: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert the event ot an optional event
|
||||
// TODO: Consider doing this via a From trait.
|
||||
pub fn to_option(self) -> EventOption {
|
||||
match self.code {
|
||||
EVENT_NONE => EventOption::None,
|
||||
EVENT_KEY => EventOption::Key(KeyEvent::from_event(self)),
|
||||
EVENT_TEXT_INPUT => EventOption::TextInput(TextInputEvent::from_event(self)),
|
||||
EVENT_MOUSE => EventOption::Mouse(MouseEvent::from_event(self)),
|
||||
EVENT_MOUSE_RELATIVE => {
|
||||
EventOption::MouseRelative(MouseRelativeEvent::from_event(self))
|
||||
}
|
||||
EVENT_BUTTON => EventOption::Button(ButtonEvent::from_event(self)),
|
||||
EVENT_SCROLL => EventOption::Scroll(ScrollEvent::from_event(self)),
|
||||
EVENT_QUIT => EventOption::Quit(QuitEvent::from_event(self)),
|
||||
EVENT_FOCUS => EventOption::Focus(FocusEvent::from_event(self)),
|
||||
EVENT_MOVE => EventOption::Move(MoveEvent::from_event(self)),
|
||||
EVENT_RESIZE => EventOption::Resize(ResizeEvent::from_event(self)),
|
||||
EVENT_SCREEN => EventOption::Screen(ScreenEvent::from_event(self)),
|
||||
EVENT_CLIPBOARD => EventOption::Clipboard(ClipboardEvent::from_event(self)),
|
||||
EVENT_CLIPBOARD_UPDATE => {
|
||||
EventOption::ClipboardUpdate(ClipboardUpdateEvent::from_event(self))
|
||||
}
|
||||
EVENT_DROP => EventOption::Drop(DropEvent::from_event(self)),
|
||||
EVENT_HOVER => EventOption::Hover(HoverEvent::from_event(self)),
|
||||
_ => EventOption::Unknown(self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Event {
|
||||
type Target = [u8];
|
||||
fn deref(&self) -> &[u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts(self as *const Event as *const u8, mem::size_of::<Event>())
|
||||
as &[u8]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Event {
|
||||
fn deref_mut(&mut self) -> &mut [u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts_mut(self as *mut Event as *mut u8, mem::size_of::<Event>())
|
||||
as &mut [u8]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const K_A: u8 = 0x1E;
|
||||
pub const K_B: u8 = 0x30;
|
||||
pub const K_C: u8 = 0x2E;
|
||||
pub const K_D: u8 = 0x20;
|
||||
pub const K_E: u8 = 0x12;
|
||||
pub const K_F: u8 = 0x21;
|
||||
pub const K_G: u8 = 0x22;
|
||||
pub const K_H: u8 = 0x23;
|
||||
pub const K_I: u8 = 0x17;
|
||||
pub const K_J: u8 = 0x24;
|
||||
pub const K_K: u8 = 0x25;
|
||||
pub const K_L: u8 = 0x26;
|
||||
pub const K_M: u8 = 0x32;
|
||||
pub const K_N: u8 = 0x31;
|
||||
pub const K_O: u8 = 0x18;
|
||||
pub const K_P: u8 = 0x19;
|
||||
pub const K_Q: u8 = 0x10;
|
||||
pub const K_R: u8 = 0x13;
|
||||
pub const K_S: u8 = 0x1F;
|
||||
pub const K_T: u8 = 0x14;
|
||||
pub const K_U: u8 = 0x16;
|
||||
pub const K_V: u8 = 0x2F;
|
||||
pub const K_W: u8 = 0x11;
|
||||
pub const K_X: u8 = 0x2D;
|
||||
pub const K_Y: u8 = 0x15;
|
||||
pub const K_Z: u8 = 0x2C;
|
||||
pub const K_0: u8 = 0x0B;
|
||||
pub const K_1: u8 = 0x02;
|
||||
pub const K_2: u8 = 0x03;
|
||||
pub const K_3: u8 = 0x04;
|
||||
pub const K_4: u8 = 0x05;
|
||||
pub const K_5: u8 = 0x06;
|
||||
pub const K_6: u8 = 0x07;
|
||||
pub const K_7: u8 = 0x08;
|
||||
pub const K_8: u8 = 0x09;
|
||||
pub const K_9: u8 = 0x0A;
|
||||
|
||||
// Numpad keys (codes 0x70-0x79)
|
||||
pub const K_NUM_0: u8 = 0x70;
|
||||
pub const K_NUM_1: u8 = 0x71;
|
||||
pub const K_NUM_2: u8 = 0x72;
|
||||
pub const K_NUM_3: u8 = 0x73;
|
||||
pub const K_NUM_4: u8 = 0x74;
|
||||
pub const K_NUM_5: u8 = 0x75;
|
||||
pub const K_NUM_6: u8 = 0x76;
|
||||
pub const K_NUM_7: u8 = 0x77;
|
||||
pub const K_NUM_8: u8 = 0x78;
|
||||
pub const K_NUM_9: u8 = 0x79;
|
||||
|
||||
/// Tick/tilde key
|
||||
pub const K_TICK: u8 = 0x29;
|
||||
/// Minus/underline key
|
||||
pub const K_MINUS: u8 = 0x0C;
|
||||
/// Equals/plus key
|
||||
pub const K_EQUALS: u8 = 0x0D;
|
||||
/// Backslash/pipe key
|
||||
pub const K_BACKSLASH: u8 = 0x2B;
|
||||
/// Bracket open key
|
||||
pub const K_BRACE_OPEN: u8 = 0x1A;
|
||||
/// Bracket close key
|
||||
pub const K_BRACE_CLOSE: u8 = 0x1B;
|
||||
/// Semicolon key
|
||||
pub const K_SEMICOLON: u8 = 0x27;
|
||||
/// Quote key
|
||||
pub const K_QUOTE: u8 = 0x28;
|
||||
/// Comma key
|
||||
pub const K_COMMA: u8 = 0x33;
|
||||
/// Period key
|
||||
pub const K_PERIOD: u8 = 0x34;
|
||||
/// Slash key
|
||||
pub const K_SLASH: u8 = 0x35;
|
||||
/// Backspace key
|
||||
pub const K_BKSP: u8 = 0x0E;
|
||||
/// Space key
|
||||
pub const K_SPACE: u8 = 0x39;
|
||||
/// Tab key
|
||||
pub const K_TAB: u8 = 0x0F;
|
||||
/// Capslock
|
||||
pub const K_CAPS: u8 = 0x3A;
|
||||
/// Left shift
|
||||
pub const K_LEFT_SHIFT: u8 = 0x2A;
|
||||
/// Right shift
|
||||
pub const K_RIGHT_SHIFT: u8 = 0x36;
|
||||
/// Control key
|
||||
pub const K_CTRL: u8 = 0x1D;
|
||||
/// Alt key
|
||||
pub const K_ALT: u8 = 0x38;
|
||||
/// AltGr key
|
||||
pub const K_ALT_GR: u8 = 0x64;
|
||||
/// Enter key
|
||||
pub const K_ENTER: u8 = 0x1C;
|
||||
/// Escape key
|
||||
pub const K_ESC: u8 = 0x01;
|
||||
/// F1 key
|
||||
pub const K_F1: u8 = 0x3B;
|
||||
/// F2 key
|
||||
pub const K_F2: u8 = 0x3C;
|
||||
/// F3 key
|
||||
pub const K_F3: u8 = 0x3D;
|
||||
/// F4 key
|
||||
pub const K_F4: u8 = 0x3E;
|
||||
/// F5 key
|
||||
pub const K_F5: u8 = 0x3F;
|
||||
/// F6 key
|
||||
pub const K_F6: u8 = 0x40;
|
||||
/// F7 key
|
||||
pub const K_F7: u8 = 0x41;
|
||||
/// F8 key
|
||||
pub const K_F8: u8 = 0x42;
|
||||
/// F9 key
|
||||
pub const K_F9: u8 = 0x43;
|
||||
/// F10 key
|
||||
pub const K_F10: u8 = 0x44;
|
||||
/// Home key
|
||||
pub const K_HOME: u8 = 0x47;
|
||||
/// Up key
|
||||
pub const K_UP: u8 = 0x48;
|
||||
/// Page up key
|
||||
pub const K_PGUP: u8 = 0x49;
|
||||
/// Left key
|
||||
pub const K_LEFT: u8 = 0x4B;
|
||||
/// Right key
|
||||
pub const K_RIGHT: u8 = 0x4D;
|
||||
/// End key
|
||||
pub const K_END: u8 = 0x4F;
|
||||
/// Down key
|
||||
pub const K_DOWN: u8 = 0x50;
|
||||
/// Page down key
|
||||
pub const K_PGDN: u8 = 0x51;
|
||||
/// Delete key
|
||||
pub const K_DEL: u8 = 0x53;
|
||||
/// F11 key
|
||||
pub const K_F11: u8 = 0x57;
|
||||
/// F12 key
|
||||
pub const K_F12: u8 = 0x58;
|
||||
/// SUPER/META/WIN Key
|
||||
pub const K_SUPER : u8 = 0x5B;
|
||||
/// Media Key for Volume toggle (mute/unmute)
|
||||
pub const K_VOLUME_TOGGLE : u8 = 0x80 + 0x20;
|
||||
/// Media Key for Volume Down
|
||||
pub const K_VOLUME_DOWN : u8 = 0x80 + 0x2E;
|
||||
/// Media Key for Volume Up
|
||||
pub const K_VOLUME_UP : u8 = 0x80 + 0x30;
|
||||
|
||||
/// A key event (such as a pressed key)
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct KeyEvent {
|
||||
/// The character of the key
|
||||
pub character: char,
|
||||
/// The scancode of the key
|
||||
pub scancode: u8,
|
||||
/// Was it pressed?
|
||||
pub pressed: bool,
|
||||
}
|
||||
|
||||
impl KeyEvent {
|
||||
/// Convert to an `Event`
|
||||
pub fn to_event(&self) -> Event {
|
||||
Event {
|
||||
code: EVENT_KEY,
|
||||
a: self.character as i64,
|
||||
b: self.scancode as i64 | (self.pressed as i64) << 8,
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert from an `Event`
|
||||
pub fn from_event(event: Event) -> KeyEvent {
|
||||
KeyEvent {
|
||||
character: char::from_u32(event.a as u32).unwrap_or('\0'),
|
||||
scancode: event.b as u8,
|
||||
pressed: event.b & 1 << 8 == 1 << 8,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct TextInputEvent {
|
||||
pub character: char,
|
||||
}
|
||||
|
||||
impl TextInputEvent {
|
||||
/// Convert to an `Event`
|
||||
pub fn to_event(&self) -> Event {
|
||||
Event {
|
||||
code: EVENT_TEXT_INPUT,
|
||||
a: self.character as i64,
|
||||
b: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert from an `Event`
|
||||
pub fn from_event(event: Event) -> TextInputEvent {
|
||||
TextInputEvent {
|
||||
character: char::from_u32(event.a as u32).unwrap_or('\0'),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A event related to the mouse (absolute position)
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct MouseEvent {
|
||||
/// The x coordinate of the mouse
|
||||
pub x: i32,
|
||||
/// The y coordinate of the mouse
|
||||
pub y: i32,
|
||||
}
|
||||
|
||||
impl MouseEvent {
|
||||
/// Convert to an `Event`
|
||||
pub fn to_event(&self) -> Event {
|
||||
Event {
|
||||
code: EVENT_MOUSE,
|
||||
a: self.x as i64,
|
||||
b: self.y as i64,
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert an `Event` to a `MouseEvent`
|
||||
pub fn from_event(event: Event) -> MouseEvent {
|
||||
MouseEvent {
|
||||
x: event.a as i32,
|
||||
y: event.b as i32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A event related to the mouse (relative position)
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct MouseRelativeEvent {
|
||||
/// The x coordinate of the mouse
|
||||
pub dx: i32,
|
||||
/// The y coordinate of the mouse
|
||||
pub dy: i32,
|
||||
}
|
||||
|
||||
impl MouseRelativeEvent {
|
||||
/// Convert to an `Event`
|
||||
pub fn to_event(&self) -> Event {
|
||||
Event {
|
||||
code: EVENT_MOUSE_RELATIVE,
|
||||
a: self.dx as i64,
|
||||
b: self.dy as i64,
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert an `Event` to a `MouseRelativeEvent`
|
||||
pub fn from_event(event: Event) -> MouseRelativeEvent {
|
||||
MouseRelativeEvent {
|
||||
dx: event.a as i32,
|
||||
dy: event.b as i32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A event for clicking the mouse
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct ButtonEvent {
|
||||
/// Was the left button pressed?
|
||||
pub left: bool,
|
||||
/// Was the middle button pressed?
|
||||
pub middle: bool,
|
||||
/// Was the right button pressed?
|
||||
pub right: bool,
|
||||
}
|
||||
|
||||
impl ButtonEvent {
|
||||
/// Convert to an `Event`
|
||||
pub fn to_event(&self) -> Event {
|
||||
Event {
|
||||
code: EVENT_BUTTON,
|
||||
a: self.left as i64 | (self.middle as i64) << 1 | (self.right as i64) << 2,
|
||||
b: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert an `Event` to a `ButtonEvent`
|
||||
pub fn from_event(event: Event) -> ButtonEvent {
|
||||
ButtonEvent {
|
||||
left: event.a & 1 == 1,
|
||||
middle: event.a & 2 == 2,
|
||||
right: event.a & 4 == 4,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A event for scrolling the mouse
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct ScrollEvent {
|
||||
/// The x distance of the scroll
|
||||
pub x: i32,
|
||||
/// The y distance of the scroll
|
||||
pub y: i32,
|
||||
}
|
||||
|
||||
impl ScrollEvent {
|
||||
/// Convert to an `Event`
|
||||
pub fn to_event(&self) -> Event {
|
||||
Event {
|
||||
code: EVENT_SCROLL,
|
||||
a: self.x as i64,
|
||||
b: self.y as i64,
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert an `Event` to a `ScrollEvent`
|
||||
pub fn from_event(event: Event) -> ScrollEvent {
|
||||
ScrollEvent {
|
||||
x: event.a as i32,
|
||||
y: event.b as i32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct QuitEvent;
|
||||
|
||||
impl QuitEvent {
|
||||
pub fn to_event(&self) -> Event {
|
||||
Event {
|
||||
code: EVENT_QUIT,
|
||||
a: 0,
|
||||
b: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_event(_: Event) -> QuitEvent {
|
||||
QuitEvent
|
||||
}
|
||||
}
|
||||
|
||||
/// A focus event
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct FocusEvent {
|
||||
/// True if window has been focused, false if not
|
||||
pub focused: bool,
|
||||
}
|
||||
|
||||
impl FocusEvent {
|
||||
pub fn to_event(&self) -> Event {
|
||||
Event {
|
||||
code: EVENT_FOCUS,
|
||||
a: self.focused as i64,
|
||||
b: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_event(event: Event) -> FocusEvent {
|
||||
FocusEvent {
|
||||
focused: event.a > 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A move event
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct MoveEvent {
|
||||
pub x: i32,
|
||||
pub y: i32,
|
||||
}
|
||||
|
||||
impl MoveEvent {
|
||||
pub fn to_event(&self) -> Event {
|
||||
Event {
|
||||
code: EVENT_MOVE,
|
||||
a: self.x as i64,
|
||||
b: self.y as i64,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_event(event: Event) -> MoveEvent {
|
||||
MoveEvent {
|
||||
x: event.a as i32,
|
||||
y: event.b as i32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A resize event
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct ResizeEvent {
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
}
|
||||
|
||||
impl ResizeEvent {
|
||||
pub fn to_event(&self) -> Event {
|
||||
Event {
|
||||
code: EVENT_RESIZE,
|
||||
a: self.width as i64,
|
||||
b: self.height as i64,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_event(event: Event) -> ResizeEvent {
|
||||
ResizeEvent {
|
||||
width: event.a as u32,
|
||||
height: event.b as u32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A screen report event
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct ScreenEvent {
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
}
|
||||
|
||||
impl ScreenEvent {
|
||||
pub fn to_event(&self) -> Event {
|
||||
Event {
|
||||
code: EVENT_SCREEN,
|
||||
a: self.width as i64,
|
||||
b: self.height as i64,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_event(event: Event) -> ScreenEvent {
|
||||
ScreenEvent {
|
||||
width: event.a as u32,
|
||||
height: event.b as u32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const CLIPBOARD_COPY: u8 = 0;
|
||||
pub const CLIPBOARD_CUT: u8 = 1;
|
||||
pub const CLIPBOARD_PASTE: u8 = 2;
|
||||
|
||||
/// A clipboard event
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct ClipboardUpdateEvent;
|
||||
|
||||
impl ClipboardUpdateEvent {
|
||||
pub fn to_event(&self) -> Event {
|
||||
Event {
|
||||
code: EVENT_CLIPBOARD_UPDATE,
|
||||
a: 0,
|
||||
b: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_event(_: Event) -> ClipboardUpdateEvent {
|
||||
ClipboardUpdateEvent
|
||||
}
|
||||
}
|
||||
|
||||
/// A clipboard event
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct ClipboardEvent {
|
||||
pub kind: u8,
|
||||
pub size: usize,
|
||||
}
|
||||
|
||||
impl ClipboardEvent {
|
||||
pub fn to_event(&self) -> Event {
|
||||
Event {
|
||||
code: EVENT_CLIPBOARD,
|
||||
a: self.kind as i64,
|
||||
b: self.size as i64,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_event(event: Event) -> ClipboardEvent {
|
||||
ClipboardEvent {
|
||||
kind: event.a as u8,
|
||||
size: event.b as usize,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const DROP_FILE: u8 = 0;
|
||||
pub const DROP_TEXT: u8 = 1;
|
||||
|
||||
/// A drop file event.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct DropEvent {
|
||||
pub kind: u8,
|
||||
}
|
||||
|
||||
impl DropEvent {
|
||||
pub fn to_event(&self) -> Event {
|
||||
Event {
|
||||
code: EVENT_DROP,
|
||||
a: self.kind as i64,
|
||||
b: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_event(event: Event) -> DropEvent {
|
||||
DropEvent {
|
||||
kind: event.a as u8,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A hover event
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct HoverEvent {
|
||||
/// True if window has been entered, false if exited
|
||||
pub entered: bool,
|
||||
}
|
||||
|
||||
impl HoverEvent {
|
||||
pub fn to_event(&self) -> Event {
|
||||
Event {
|
||||
code: EVENT_HOVER,
|
||||
a: self.entered as i64,
|
||||
b: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_event(event: Event) -> HoverEvent {
|
||||
HoverEvent {
|
||||
entered: event.a > 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
120
third-party/vendor/orbclient/src/graphicspath.rs
vendored
Normal file
120
third-party/vendor/orbclient/src/graphicspath.rs
vendored
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
use alloc::vec::Vec;
|
||||
|
||||
/// point type (is the point a new position or a connection point)
|
||||
pub enum PointType {
|
||||
Move,
|
||||
Connect,
|
||||
None,
|
||||
}
|
||||
|
||||
/// graphic path with similar functions like html canvas
|
||||
pub struct GraphicsPath {
|
||||
x: i32,
|
||||
y: i32,
|
||||
pub points: Vec<(i32, i32, PointType)>,
|
||||
}
|
||||
|
||||
#[allow(clippy::new_without_default)]
|
||||
impl GraphicsPath {
|
||||
pub fn new() -> GraphicsPath {
|
||||
GraphicsPath {
|
||||
x: 0,
|
||||
y: 0,
|
||||
points: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// move to position
|
||||
pub fn move_to(&mut self, x: i32, y: i32) {
|
||||
self.points.push((x, y, PointType::Move));
|
||||
self.x = x;
|
||||
self.y = y;
|
||||
}
|
||||
|
||||
/// create a line between the last and new point
|
||||
pub fn line_to(&mut self, x: i32, y: i32) {
|
||||
self.points.push((x, y, PointType::Connect));
|
||||
self.x = x;
|
||||
self.y = y;
|
||||
}
|
||||
|
||||
/// quadratic bezier curve
|
||||
pub fn quadratic_curve_to(&mut self, argx1: i32, argy1: i32, argx2: i32, argy2: i32) {
|
||||
let mut t: f32 = 0.0;
|
||||
let mut u: f32;
|
||||
let mut tt: f32;
|
||||
let mut uu: f32;
|
||||
let mut x: f32;
|
||||
let mut y: f32;
|
||||
|
||||
while t < 1.0 {
|
||||
u = 1.0 - t;
|
||||
uu = u * u;
|
||||
tt = t * t;
|
||||
|
||||
x = (self.x as f32) * uu;
|
||||
y = (self.y as f32) * uu;
|
||||
|
||||
x += 2.0 * u * t * (argx1 as f32);
|
||||
y += 2.0 * u * t * (argy1 as f32);
|
||||
|
||||
x += tt * (argx2 as f32);
|
||||
y += tt * (argy2 as f32);
|
||||
|
||||
t += 0.01;
|
||||
self.points.push((x as i32, y as i32, PointType::Connect));
|
||||
}
|
||||
|
||||
self.x = argx2;
|
||||
self.y = argy2;
|
||||
}
|
||||
|
||||
/// cubic bezier curve
|
||||
pub fn bezier_curve_to(
|
||||
&mut self,
|
||||
argx1: i32,
|
||||
argy1: i32,
|
||||
argx2: i32,
|
||||
argy2: i32,
|
||||
argx3: i32,
|
||||
argy3: i32,
|
||||
) {
|
||||
let mut t: f32 = 0.0;
|
||||
let mut u: f32;
|
||||
let mut tt: f32;
|
||||
let mut uu: f32;
|
||||
let mut uuu: f32;
|
||||
let mut ttt: f32;
|
||||
let mut x: f32;
|
||||
let mut y: f32;
|
||||
|
||||
while t < 1.0 {
|
||||
u = 1.0 - t;
|
||||
tt = t * t;
|
||||
uu = u * u;
|
||||
uuu = uu * u;
|
||||
ttt = tt * t;
|
||||
|
||||
x = (self.x as f32) * uuu;
|
||||
y = (self.y as f32) * uuu;
|
||||
|
||||
x += 3.0 * uu * t * (argx1 as f32);
|
||||
y += 3.0 * uu * t * (argy1 as f32);
|
||||
|
||||
x += 3.0 * u * tt * (argx2 as f32);
|
||||
y += 3.0 * u * tt * (argy2 as f32);
|
||||
|
||||
x += ttt * (argx3 as f32);
|
||||
y += ttt * (argy3 as f32);
|
||||
|
||||
t += 0.01;
|
||||
self.points.push((x as i32, y as i32, PointType::Connect));
|
||||
}
|
||||
|
||||
self.x = argx3;
|
||||
self.y = argy3;
|
||||
}
|
||||
}
|
||||
49
third-party/vendor/orbclient/src/lib.rs
vendored
Normal file
49
third-party/vendor/orbclient/src/lib.rs
vendored
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
extern crate alloc;
|
||||
|
||||
#[cfg(all(feature = "std", not(target_os = "redox")))]
|
||||
#[path = "sys/sdl2.rs"]
|
||||
mod sys;
|
||||
|
||||
#[cfg(all(feature = "std", target_os = "redox"))]
|
||||
#[path = "sys/orbital.rs"]
|
||||
mod sys;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use sys::{get_display_size, EventIter, Window};
|
||||
|
||||
#[cfg(feature = "unifont")]
|
||||
pub static FONT: &[u8] = include_bytes!("../res/unifont.font");
|
||||
|
||||
pub use color::Color;
|
||||
pub use event::*;
|
||||
pub use graphicspath::GraphicsPath;
|
||||
pub use renderer::Renderer;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
mod blur;
|
||||
pub mod color;
|
||||
pub mod event;
|
||||
pub mod graphicspath;
|
||||
pub mod renderer;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum WindowFlag {
|
||||
Async,
|
||||
Back,
|
||||
Front,
|
||||
Borderless,
|
||||
Resizable,
|
||||
Transparent,
|
||||
Unclosable,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum Mode {
|
||||
Blend, //Composite
|
||||
Overwrite, //Replace
|
||||
}
|
||||
886
third-party/vendor/orbclient/src/renderer.rs
vendored
Normal file
886
third-party/vendor/orbclient/src/renderer.rs
vendored
Normal file
|
|
@ -0,0 +1,886 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use core::cell::Cell;
|
||||
use core::cmp;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use crate::blur;
|
||||
use crate::color::Color;
|
||||
use crate::graphicspath::GraphicsPath;
|
||||
use crate::graphicspath::PointType;
|
||||
use crate::Mode;
|
||||
|
||||
pub trait Renderer {
|
||||
/// Get width
|
||||
fn width(&self) -> u32;
|
||||
|
||||
/// Get height
|
||||
fn height(&self) -> u32;
|
||||
|
||||
/// Access the pixel buffer
|
||||
fn data(&self) -> &[Color];
|
||||
|
||||
/// Access the pixel buffer mutably
|
||||
fn data_mut(&mut self) -> &mut [Color];
|
||||
|
||||
/// Flip the buffer
|
||||
fn sync(&mut self) -> bool;
|
||||
|
||||
/// Set/get drawing mode
|
||||
fn mode(&self) -> &Cell<Mode>;
|
||||
|
||||
///Draw a pixel
|
||||
//faster pixel implementation (multiplexing)
|
||||
fn pixel(&mut self, x: i32, y: i32, color: Color) {
|
||||
let replace = match self.mode().get() {
|
||||
Mode::Blend => false,
|
||||
Mode::Overwrite => true,
|
||||
};
|
||||
let w = self.width();
|
||||
let h = self.height();
|
||||
let data = self.data_mut();
|
||||
|
||||
if x >= 0 && y >= 0 && x < w as i32 && y < h as i32 {
|
||||
let new = color.data;
|
||||
let alpha = (new >> 24) & 0xFF;
|
||||
let old = &mut data[y as usize * w as usize + x as usize].data;
|
||||
|
||||
if alpha >= 255 || replace {
|
||||
*old = new;
|
||||
} else if alpha > 0 {
|
||||
let n_alpha = 255 - alpha;
|
||||
let rb = ((n_alpha * (*old & 0x00FF00FF)) + (alpha * (new & 0x00FF00FF))) >> 8;
|
||||
let ag = (n_alpha * ((*old & 0xFF00FF00) >> 8))
|
||||
+ (alpha * (0x01000000 | ((new & 0x0000FF00) >> 8)));
|
||||
|
||||
*old = (rb & 0x00FF00FF) | (ag & 0xFF00FF00);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Draw a piece of an arc. Negative radius will fill in the inside
|
||||
fn arc(&mut self, x0: i32, y0: i32, radius: i32, parts: u8, color: Color) {
|
||||
let mut x = radius.abs();
|
||||
let mut y = 0;
|
||||
let mut err = 0;
|
||||
|
||||
// https://github.com/rust-lang/rust-clippy/issues/5354
|
||||
#[allow(clippy::comparison_chain)]
|
||||
while x >= y {
|
||||
if radius < 0 {
|
||||
if parts & 1 << 0 != 0 {
|
||||
self.rect(x0 - x, y0 + y, x as u32, 1, color);
|
||||
}
|
||||
if parts & 1 << 1 != 0 {
|
||||
self.rect(x0, y0 + y, x as u32 + 1, 1, color);
|
||||
}
|
||||
if parts & 1 << 2 != 0 {
|
||||
self.rect(x0 - y, y0 + x, y as u32, 1, color);
|
||||
}
|
||||
if parts & 1 << 3 != 0 {
|
||||
self.rect(x0, y0 + x, y as u32 + 1, 1, color);
|
||||
}
|
||||
if parts & 1 << 4 != 0 {
|
||||
self.rect(x0 - x, y0 - y, x as u32, 1, color);
|
||||
}
|
||||
if parts & 1 << 5 != 0 {
|
||||
self.rect(x0, y0 - y, x as u32 + 1, 1, color);
|
||||
}
|
||||
if parts & 1 << 6 != 0 {
|
||||
self.rect(x0 - y, y0 - x, y as u32, 1, color);
|
||||
}
|
||||
if parts & 1 << 7 != 0 {
|
||||
self.rect(x0, y0 - x, y as u32 + 1, 1, color);
|
||||
}
|
||||
} else if radius == 0 {
|
||||
self.pixel(x0, y0, color);
|
||||
} else {
|
||||
if parts & 1 << 0 != 0 {
|
||||
self.pixel(x0 - x, y0 + y, color);
|
||||
}
|
||||
if parts & 1 << 1 != 0 {
|
||||
self.pixel(x0 + x, y0 + y, color);
|
||||
}
|
||||
if parts & 1 << 2 != 0 {
|
||||
self.pixel(x0 - y, y0 + x, color);
|
||||
}
|
||||
if parts & 1 << 3 != 0 {
|
||||
self.pixel(x0 + y, y0 + x, color);
|
||||
}
|
||||
if parts & 1 << 4 != 0 {
|
||||
self.pixel(x0 - x, y0 - y, color);
|
||||
}
|
||||
if parts & 1 << 5 != 0 {
|
||||
self.pixel(x0 + x, y0 - y, color);
|
||||
}
|
||||
if parts & 1 << 6 != 0 {
|
||||
self.pixel(x0 - y, y0 - x, color);
|
||||
}
|
||||
if parts & 1 << 7 != 0 {
|
||||
self.pixel(x0 + y, y0 - x, color);
|
||||
}
|
||||
}
|
||||
|
||||
y += 1;
|
||||
err += 1 + 2 * y;
|
||||
if 2 * (err - x) + 1 > 0 {
|
||||
x -= 1;
|
||||
err += 1 - 2 * x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Draw a circle. Negative radius will fill in the inside
|
||||
fn circle(&mut self, x0: i32, y0: i32, radius: i32, color: Color) {
|
||||
let mut x = radius.abs();
|
||||
let mut y = 0;
|
||||
let mut err = -radius.abs();
|
||||
|
||||
match radius {
|
||||
radius if radius > 0 => {
|
||||
err = 0;
|
||||
while x >= y {
|
||||
self.pixel(x0 - x, y0 + y, color);
|
||||
self.pixel(x0 + x, y0 + y, color);
|
||||
self.pixel(x0 - y, y0 + x, color);
|
||||
self.pixel(x0 + y, y0 + x, color);
|
||||
self.pixel(x0 - x, y0 - y, color);
|
||||
self.pixel(x0 + x, y0 - y, color);
|
||||
self.pixel(x0 - y, y0 - x, color);
|
||||
self.pixel(x0 + y, y0 - x, color);
|
||||
|
||||
y += 1;
|
||||
err += 1 + 2 * y;
|
||||
if 2 * (err - x) + 1 > 0 {
|
||||
x -= 1;
|
||||
err += 1 - 2 * x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
radius if radius < 0 => {
|
||||
while x >= y {
|
||||
let lasty = y;
|
||||
err += y;
|
||||
y += 1;
|
||||
err += y;
|
||||
self.line4points(x0, y0, x, lasty, color);
|
||||
if err >= 0 {
|
||||
if x != lasty {
|
||||
self.line4points(x0, y0, lasty, x, color);
|
||||
}
|
||||
err -= x;
|
||||
x -= 1;
|
||||
err -= x;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
self.pixel(x0, y0, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn line4points(&mut self, x0: i32, y0: i32, x: i32, y: i32, color: Color) {
|
||||
//self.line(x0 - x, y0 + y, (x+x0), y0 + y, color);
|
||||
self.rect(x0 - x, y0 + y, x as u32 * 2 + 1, 1, color);
|
||||
if y != 0 {
|
||||
//self.line(x0 - x, y0 - y, (x+x0), y0-y , color);
|
||||
self.rect(x0 - x, y0 - y, x as u32 * 2 + 1, 1, color);
|
||||
}
|
||||
}
|
||||
|
||||
/// Draw a line
|
||||
fn line(&mut self, argx1: i32, argy1: i32, argx2: i32, argy2: i32, color: Color) {
|
||||
let mut x = argx1;
|
||||
let mut y = argy1;
|
||||
|
||||
let dx = if argx1 > argx2 {
|
||||
argx1 - argx2
|
||||
} else {
|
||||
argx2 - argx1
|
||||
};
|
||||
let dy = if argy1 > argy2 {
|
||||
argy1 - argy2
|
||||
} else {
|
||||
argy2 - argy1
|
||||
};
|
||||
|
||||
let sx = if argx1 < argx2 { 1 } else { -1 };
|
||||
let sy = if argy1 < argy2 { 1 } else { -1 };
|
||||
|
||||
let mut err = if dx > dy { dx } else { -dy } / 2;
|
||||
let mut err_tolerance;
|
||||
|
||||
loop {
|
||||
self.pixel(x, y, color);
|
||||
|
||||
if x == argx2 && y == argy2 {
|
||||
break;
|
||||
};
|
||||
|
||||
err_tolerance = 2 * err;
|
||||
|
||||
if err_tolerance > -dx {
|
||||
err -= dy;
|
||||
x += sx;
|
||||
}
|
||||
if err_tolerance < dy {
|
||||
err += dx;
|
||||
y += sy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn lines(&mut self, points: &[[i32; 2]], color: Color) {
|
||||
if points.is_empty() {
|
||||
// when no points given, do nothing
|
||||
} else if points.len() == 1 {
|
||||
self.pixel(points[0][0], points[0][1], color);
|
||||
} else {
|
||||
for i in 0..points.len() - 1 {
|
||||
self.line(
|
||||
points[i][0],
|
||||
points[i][1],
|
||||
points[i + 1][0],
|
||||
points[i + 1][1],
|
||||
color,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Draw a path (GraphicsPath)
|
||||
fn draw_path_stroke(&mut self, graphicspath: GraphicsPath, color: Color) {
|
||||
let mut x: i32 = 0;
|
||||
let mut y: i32 = 0;
|
||||
|
||||
for point in graphicspath.points {
|
||||
if let PointType::Connect = point.2 {
|
||||
self.line(x, y, point.0, point.1, color)
|
||||
}
|
||||
x = point.0;
|
||||
y = point.1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Draw a character, using the loaded font
|
||||
#[cfg(feature = "unifont")]
|
||||
fn char(&mut self, x: i32, y: i32, c: char, color: Color) {
|
||||
let mut offset = (c as usize) * 16;
|
||||
for row in 0..16 {
|
||||
let row_data = if offset < crate::FONT.len() {
|
||||
crate::FONT[offset]
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
for col in 0..8 {
|
||||
let pixel = (row_data >> (7 - col)) & 1;
|
||||
if pixel > 0 {
|
||||
self.pixel(x + col, y + row, color);
|
||||
}
|
||||
}
|
||||
offset += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Set entire window to a color
|
||||
fn set(&mut self, color: Color) {
|
||||
let data = self.data_mut();
|
||||
let data_ptr = data.as_mut_ptr();
|
||||
for i in 0..data.len() as isize {
|
||||
unsafe { *data_ptr.offset(i) = color }
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the whole window to black
|
||||
fn clear(&mut self) {
|
||||
self.set(Color::rgb(0, 0, 0));
|
||||
}
|
||||
|
||||
fn rect(&mut self, x: i32, y: i32, w: u32, h: u32, color: Color) {
|
||||
let replace = match self.mode().get() {
|
||||
Mode::Blend => false,
|
||||
Mode::Overwrite => true,
|
||||
};
|
||||
let self_w = self.width();
|
||||
let self_h = self.height();
|
||||
|
||||
let start_y = cmp::max(0, cmp::min(self_h as i32 - 1, y));
|
||||
let end_y = cmp::max(start_y, cmp::min(self_h as i32, y + h as i32));
|
||||
|
||||
let start_x = cmp::max(0, cmp::min(self_w as i32 - 1, x));
|
||||
let len = cmp::max(start_x, cmp::min(self_w as i32, x + w as i32)) - start_x;
|
||||
|
||||
let alpha = (color.data >> 24) & 0xFF;
|
||||
//if alpha > 0 {
|
||||
if alpha >= 255 || replace {
|
||||
let data = self.data_mut();
|
||||
let data_ptr = data.as_mut_ptr();
|
||||
for y in start_y..end_y {
|
||||
let start = (y * self_w as i32 + start_x) as isize;
|
||||
let end = start + len as isize;
|
||||
for i in start..end {
|
||||
unsafe {
|
||||
*data_ptr.offset(i) = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for y in start_y..end_y {
|
||||
for x in start_x..start_x + len {
|
||||
self.pixel(x, y, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
//}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
fn box_blur(&mut self, x: i32, y: i32, w: u32, h: u32, r: i32) {
|
||||
let self_w = self.width();
|
||||
let self_h = self.height();
|
||||
|
||||
let start_y = cmp::max(0, cmp::min(self_h as i32 - 1, y));
|
||||
let end_y = cmp::max(start_y, cmp::min(self_h as i32, y + h as i32));
|
||||
|
||||
let start_x = cmp::max(0, cmp::min(self_w as i32 - 1, x));
|
||||
let end_x = cmp::max(start_x, cmp::min(self_w as i32, x + w as i32));
|
||||
|
||||
let data = self.data_mut();
|
||||
let mut blur_data: Vec<Color> = Vec::new();
|
||||
for y in start_y..end_y {
|
||||
for x in start_x..end_x {
|
||||
let old = data[y as usize * self_w as usize + x as usize];
|
||||
blur_data.push(old);
|
||||
}
|
||||
}
|
||||
let real_w = end_x - start_x;
|
||||
let real_h = end_y - start_y;
|
||||
blur::gauss_blur(&mut blur_data, real_w as u32, real_h as u32, r as f32);
|
||||
|
||||
let mut counter: u32 = 0;
|
||||
for y in start_y..end_y {
|
||||
for x in start_x..end_x {
|
||||
let a = blur_data[counter as usize];
|
||||
let old = &mut data[y as usize * self_w as usize + x as usize].data;
|
||||
|
||||
*old = a.data;
|
||||
counter += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
#[cfg(feature = "std")]
|
||||
fn box_shadow(
|
||||
&mut self,
|
||||
x: i32,
|
||||
y: i32,
|
||||
w: u32,
|
||||
h: u32,
|
||||
offset_x: i32,
|
||||
offset_y: i32,
|
||||
r: i32,
|
||||
color: Color,
|
||||
) {
|
||||
let real_w = w + (2 * r as u32);
|
||||
let real_h = h + (2 * r as u32);
|
||||
|
||||
let mut blur_data: Vec<Color> = Vec::new();
|
||||
for new_x in x..x + real_w as i32 {
|
||||
for new_y in y..y + real_h as i32 {
|
||||
if new_x < x + r
|
||||
|| new_y < y + r
|
||||
|| new_y >= y + h as i32 + r
|
||||
|| new_x >= x + w as i32 + r
|
||||
{
|
||||
blur_data.push(Color::rgb(255, 0, 255));
|
||||
} else {
|
||||
blur_data.push(Color::rgb(0, 0, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
blur::gauss_blur(&mut blur_data, real_w, real_h, r as f32 / 3.0);
|
||||
|
||||
let mut counter: u32 = 0;
|
||||
for new_x in (x - r)..(x + real_w as i32 - r) {
|
||||
for new_y in (y - r)..(y + real_h as i32 - r) {
|
||||
let c = blur_data[counter as usize];
|
||||
|
||||
let alpha: u8 = if color.a() < 255 - c.r() {
|
||||
color.a()
|
||||
} else {
|
||||
255 - c.r()
|
||||
};
|
||||
let col = Color::rgba(color.r(), color.g(), color.b(), alpha);
|
||||
|
||||
let new_x_b = new_x + offset_x;
|
||||
let new_y_b = new_y + offset_y;
|
||||
if new_x_b < x
|
||||
|| new_x_b > x + w as i32 - 1
|
||||
|| new_y_b < y
|
||||
|| new_y_b > y + h as i32 - 1
|
||||
{
|
||||
self.pixel(new_x_b, new_y_b, col);
|
||||
}
|
||||
counter += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Display an image
|
||||
fn image(&mut self, start_x: i32, start_y: i32, w: u32, h: u32, data: &[Color]) {
|
||||
match self.mode().get() {
|
||||
Mode::Blend => self.image_fast(start_x, start_y, w, h, data),
|
||||
Mode::Overwrite => self.image_opaque(start_x, start_y, w, h, data),
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Improve speed
|
||||
#[inline(always)]
|
||||
fn image_legacy(&mut self, start_x: i32, start_y: i32, w: u32, h: u32, data: &[Color]) {
|
||||
let mut i = 0;
|
||||
for y in start_y..start_y + h as i32 {
|
||||
for x in start_x..start_x + w as i32 {
|
||||
if i < data.len() {
|
||||
self.pixel(x, y, data[i])
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///Display an image overwriting a portion of window starting at given line : very quick!!
|
||||
fn image_over(&mut self, start: i32, image_data: &[Color]) {
|
||||
let start = start as usize * self.width() as usize;
|
||||
let window_data = self.data_mut();
|
||||
let stop = cmp::min(start + image_data.len(), window_data.len());
|
||||
let end = cmp::min(image_data.len(), window_data.len() - start);
|
||||
|
||||
window_data[start..stop].copy_from_slice(&image_data[..end]);
|
||||
}
|
||||
|
||||
///Display an image using non transparent method
|
||||
#[inline(always)]
|
||||
fn image_opaque(&mut self, start_x: i32, start_y: i32, w: u32, h: u32, image_data: &[Color]) {
|
||||
let w = w as usize;
|
||||
let mut h = h as usize;
|
||||
let width = self.width() as usize;
|
||||
let height = self.height() as usize;
|
||||
let start_x = start_x as usize;
|
||||
let start_y = start_y as usize;
|
||||
|
||||
//check boundaries
|
||||
if start_x >= width || start_y >= height {
|
||||
return;
|
||||
}
|
||||
if h + start_y > height {
|
||||
h = height - start_y;
|
||||
}
|
||||
let window_data = self.data_mut();
|
||||
let offset = start_y * width + start_x;
|
||||
//copy image slices to window line by line
|
||||
for l in 0..h {
|
||||
let start = offset + l * width;
|
||||
let mut stop = start + w;
|
||||
let begin = l * w;
|
||||
let mut end = begin + w;
|
||||
//check boundaries
|
||||
if start_x + w > width {
|
||||
stop = (start_y + l + 1) * width - 1;
|
||||
end = begin + stop - start;
|
||||
}
|
||||
window_data[start..stop].copy_from_slice(&image_data[begin..end]);
|
||||
}
|
||||
}
|
||||
|
||||
// Speed improved, image can be outside of window boundary
|
||||
#[inline(always)]
|
||||
fn image_fast(&mut self, start_x: i32, start_y: i32, w: u32, h: u32, image_data: &[Color]) {
|
||||
let w = w as usize;
|
||||
let h = h as usize;
|
||||
let width = self.width() as usize;
|
||||
let start_x = start_x as usize;
|
||||
let start_y = start_y as usize;
|
||||
|
||||
//simply return if image is outside of window
|
||||
if start_x >= width || start_y >= self.height() as usize {
|
||||
return;
|
||||
}
|
||||
let window_data = self.data_mut();
|
||||
let offset = start_y * width + start_x;
|
||||
|
||||
//copy image slices to window line by line
|
||||
for l in 0..h {
|
||||
let start = offset + l * width;
|
||||
let mut stop = start + w;
|
||||
let begin = l * w;
|
||||
let end = begin + w;
|
||||
|
||||
//check boundaries
|
||||
if start_x + w > width {
|
||||
stop = (start_y + l + 1) * width;
|
||||
}
|
||||
let mut k = 0;
|
||||
for i in begin..end {
|
||||
if i < image_data.len() {
|
||||
let new = image_data[i].data;
|
||||
let alpha = (new >> 24) & 0xFF;
|
||||
if alpha > 0 && (start + k) < window_data.len() && (start + k) < stop {
|
||||
let old = &mut window_data[start + k].data;
|
||||
if alpha >= 255 {
|
||||
*old = new;
|
||||
} else {
|
||||
let n_alpha = 255 - alpha;
|
||||
let rb = ((n_alpha * (*old & 0x00FF00FF))
|
||||
+ (alpha * (new & 0x00FF00FF)))
|
||||
>> 8;
|
||||
let ag = (n_alpha * ((*old & 0xFF00FF00) >> 8))
|
||||
+ (alpha * (0x01000000 | ((new & 0x0000FF00) >> 8)));
|
||||
|
||||
*old = (rb & 0x00FF00FF) | (ag & 0xFF00FF00);
|
||||
}
|
||||
}
|
||||
k += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Draw a linear gradient in a rectangular region
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
#[cfg(feature = "std")]
|
||||
fn linear_gradient(
|
||||
&mut self,
|
||||
rect_x: i32,
|
||||
rect_y: i32,
|
||||
rect_width: u32,
|
||||
rect_height: u32,
|
||||
start_x: i32,
|
||||
start_y: i32,
|
||||
end_x: i32,
|
||||
end_y: i32,
|
||||
start_color: Color,
|
||||
end_color: Color,
|
||||
) {
|
||||
if (start_x == end_x) && (start_y == end_y) {
|
||||
// Degenerate gradient
|
||||
self.rect(rect_x, rect_y, rect_width, rect_height, start_color);
|
||||
} else if start_x == end_x {
|
||||
// Vertical gradient
|
||||
for y in rect_y..(rect_y + rect_height as i32) {
|
||||
let proj = (y as f64 - start_y as f64) / (end_y as f64 - start_y as f64);
|
||||
let scale = if proj < 0.0 {
|
||||
0.0
|
||||
} else if proj > 1.0 {
|
||||
1.0
|
||||
} else {
|
||||
proj
|
||||
};
|
||||
let color = Color::interpolate(start_color, end_color, scale);
|
||||
self.line(rect_x, y, rect_x + rect_width as i32 - 1, y, color);
|
||||
}
|
||||
} else if start_y == end_y {
|
||||
// Horizontal gradient
|
||||
for x in rect_x..(rect_x + rect_width as i32) {
|
||||
let proj = (x as f64 - start_x as f64) / (end_x as f64 - start_x as f64);
|
||||
let scale = if proj < 0.0 {
|
||||
0.0
|
||||
} else if proj > 1.0 {
|
||||
1.0
|
||||
} else {
|
||||
proj
|
||||
};
|
||||
let color = Color::interpolate(start_color, end_color, scale);
|
||||
self.line(x, rect_y, x, rect_y + rect_height as i32 - 1, color);
|
||||
}
|
||||
} else {
|
||||
// Non axis-aligned gradient
|
||||
// Gradient vector
|
||||
let grad_x = end_x as f64 - start_x as f64;
|
||||
let grad_y = end_y as f64 - start_y as f64;
|
||||
let grad_len = grad_x * grad_x + grad_y * grad_y;
|
||||
|
||||
for y in rect_y..(rect_y + rect_height as i32) {
|
||||
for x in rect_x..(rect_x + rect_width as i32) {
|
||||
// Pixel vector
|
||||
let pix_x = x as f64 - start_x as f64;
|
||||
let pix_y = y as f64 - start_y as f64;
|
||||
// Scalar projection
|
||||
let proj = (pix_x * grad_x + pix_y * grad_y) / grad_len;
|
||||
// Saturation
|
||||
let scale = if proj < 0.0 {
|
||||
0.0
|
||||
} else if proj > 1.0 {
|
||||
1.0
|
||||
} else {
|
||||
proj
|
||||
};
|
||||
// Interpolation
|
||||
let color = Color::interpolate(start_color, end_color, scale);
|
||||
self.pixel(x, y, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Draw a rect with rounded corners
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn rounded_rect(
|
||||
&mut self,
|
||||
x: i32,
|
||||
y: i32,
|
||||
w: u32,
|
||||
h: u32,
|
||||
radius: u32,
|
||||
filled: bool,
|
||||
color: Color,
|
||||
) {
|
||||
let w = w as i32;
|
||||
let h = h as i32;
|
||||
let r = radius as i32;
|
||||
|
||||
if filled {
|
||||
//Draw inside corners
|
||||
self.arc(x + r, y + r, -r, 1 << 4 | 1 << 6, color);
|
||||
self.arc(x + w - 1 - r, y + r, -r, 1 << 5 | 1 << 7, color);
|
||||
self.arc(x + r, y + h - 1 - r, -r, 1 << 0 | 1 << 2, color);
|
||||
self.arc(x + w - 1 - r, y + h - 1 - r, -r, 1 << 1 | 1 << 3, color);
|
||||
|
||||
// Draw inside rectangles
|
||||
self.rect(x + r, y, (w - 1 - r * 2) as u32, r as u32 + 1, color);
|
||||
self.rect(
|
||||
x + r,
|
||||
y + h - 1 - r,
|
||||
(w - 1 - r * 2) as u32,
|
||||
r as u32 + 1,
|
||||
color,
|
||||
);
|
||||
self.rect(x, y + r + 1, w as u32, (h - 2 - r * 2) as u32, color);
|
||||
} else {
|
||||
//Draw outside corners
|
||||
self.arc(x + r, y + r, r, 1 << 4 | 1 << 6, color);
|
||||
self.arc(x + w - 1 - r, y + r, r, 1 << 5 | 1 << 7, color);
|
||||
self.arc(x + r, y + h - 1 - r, r, 1 << 0 | 1 << 2, color);
|
||||
self.arc(x + w - 1 - r, y + h - 1 - r, r, 1 << 1 | 1 << 3, color);
|
||||
|
||||
// Draw outside rectangles
|
||||
self.rect(x + r + 1, y, (w - 2 - r * 2) as u32, 1, color);
|
||||
self.rect(x + r + 1, y + h - 1, (w - 2 - r * 2) as u32, 1, color);
|
||||
self.rect(x, y + r + 1, 1, (h - 2 - r * 2) as u32, color);
|
||||
self.rect(x + w - 1, y + r + 1, 1, (h - 2 - r * 2) as u32, color);
|
||||
}
|
||||
}
|
||||
|
||||
/// Draws antialiased line
|
||||
#[cfg(feature = "std")]
|
||||
fn wu_line(&mut self, x0: i32, y0: i32, x1: i32, y1: i32, color: Color) {
|
||||
//adapted from https://rosettacode.org/wiki/Xiaolin_Wu's_line_algorithm#C.23
|
||||
let mut x0 = x0 as f64;
|
||||
let mut y0 = y0 as f64;
|
||||
let mut x1 = x1 as f64;
|
||||
let mut y1 = y1 as f64;
|
||||
let r = color.r();
|
||||
let g = color.g();
|
||||
let b = color.b();
|
||||
let a = color.a() as f64;
|
||||
|
||||
fn ipart(x: f64) -> i32 {
|
||||
x.trunc() as i32
|
||||
}
|
||||
|
||||
fn fpart(x: f64) -> f64 {
|
||||
if x < 0.0 {
|
||||
return 1.0 - (x - x.floor());
|
||||
}
|
||||
x - x.floor()
|
||||
}
|
||||
|
||||
fn rfpart(x: f64) -> f64 {
|
||||
1.0 - fpart(x)
|
||||
}
|
||||
|
||||
fn chkalpha(mut alpha: f64) -> u8 {
|
||||
if alpha > 255.0 {
|
||||
alpha = 255.0
|
||||
};
|
||||
if alpha < 0.0 {
|
||||
alpha = 0.0
|
||||
};
|
||||
alpha as u8
|
||||
}
|
||||
|
||||
let steep: bool = (y1 - y0).abs() > (x1 - x0).abs();
|
||||
let mut temp;
|
||||
if steep {
|
||||
temp = x0;
|
||||
x0 = y0;
|
||||
y0 = temp;
|
||||
temp = x1;
|
||||
x1 = y1;
|
||||
y1 = temp;
|
||||
}
|
||||
if x0 > x1 {
|
||||
temp = x0;
|
||||
x0 = x1;
|
||||
x1 = temp;
|
||||
temp = y0;
|
||||
y0 = y1;
|
||||
y1 = temp;
|
||||
}
|
||||
let dx = x1 - x0;
|
||||
let dy = y1 - y0;
|
||||
let gradient = dy / dx;
|
||||
|
||||
let mut xend: f64 = x0.round();
|
||||
let mut yend: f64 = y0 + gradient * (xend - x0);
|
||||
let mut xgap: f64 = rfpart(x0 + 0.5);
|
||||
let xpixel1 = xend as i32;
|
||||
let ypixel1 = ipart(yend);
|
||||
|
||||
if steep {
|
||||
self.pixel(
|
||||
ypixel1,
|
||||
xpixel1,
|
||||
Color::rgba(r, g, b, chkalpha(rfpart(yend) * xgap * a)),
|
||||
);
|
||||
self.pixel(
|
||||
ypixel1 + 1,
|
||||
xpixel1,
|
||||
Color::rgba(r, g, b, chkalpha(fpart(yend) * xgap * a)),
|
||||
);
|
||||
} else {
|
||||
self.pixel(
|
||||
xpixel1,
|
||||
ypixel1,
|
||||
Color::rgba(r, g, b, chkalpha(rfpart(yend) * xgap * a)),
|
||||
);
|
||||
self.pixel(
|
||||
xpixel1 + 1,
|
||||
ypixel1,
|
||||
Color::rgba(r, g, b, chkalpha(fpart(yend) * xgap * a)),
|
||||
);
|
||||
}
|
||||
let mut intery: f64 = yend + gradient;
|
||||
xend = x1.round();
|
||||
yend = y1 + gradient * (xend - x1);
|
||||
xgap = fpart(x1 + 0.5);
|
||||
let xpixel2 = xend as i32;
|
||||
let ypixel2 = ipart(yend) ;
|
||||
if steep {
|
||||
self.pixel(
|
||||
ypixel2,
|
||||
xpixel2,
|
||||
Color::rgba(r, g, b, chkalpha(rfpart(yend) * xgap * a)),
|
||||
);
|
||||
self.pixel(
|
||||
ypixel2 + 1,
|
||||
xpixel2,
|
||||
Color::rgba(r, g, b, chkalpha(fpart(yend) * xgap * a)),
|
||||
);
|
||||
} else {
|
||||
self.pixel(
|
||||
xpixel2,
|
||||
ypixel2,
|
||||
Color::rgba(r, g, b, chkalpha(rfpart(yend) * xgap * a)),
|
||||
);
|
||||
self.pixel(
|
||||
xpixel2 + 1,
|
||||
ypixel2,
|
||||
Color::rgba(r, g, b, chkalpha(fpart(yend) * xgap * a)),
|
||||
);
|
||||
}
|
||||
if steep {
|
||||
for x in (xpixel1 + 1)..(xpixel2) {
|
||||
self.pixel(
|
||||
ipart(intery),
|
||||
x,
|
||||
Color::rgba(r, g, b, chkalpha(a * rfpart(intery))),
|
||||
);
|
||||
self.pixel(
|
||||
ipart(intery) + 1,
|
||||
x,
|
||||
Color::rgba(r, g, b, chkalpha(a * fpart(intery))),
|
||||
);
|
||||
intery += gradient;
|
||||
}
|
||||
} else {
|
||||
for x in (xpixel1 + 1)..(xpixel2) {
|
||||
self.pixel(
|
||||
x,
|
||||
ipart(intery),
|
||||
Color::rgba(r, g, b, chkalpha(a * rfpart(intery))),
|
||||
);
|
||||
self.pixel(
|
||||
x,
|
||||
ipart(intery) + 1,
|
||||
Color::rgba(r, g, b, chkalpha(a * fpart(intery))),
|
||||
);
|
||||
intery += gradient;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///Draws antialiased circle
|
||||
#[cfg(feature = "std")]
|
||||
fn wu_circle(&mut self, x0: i32, y0: i32, radius: i32, color: Color) {
|
||||
let r = color.r();
|
||||
let g = color.g();
|
||||
let b = color.b();
|
||||
let a = color.a();
|
||||
let mut y = 0;
|
||||
let mut x = radius;
|
||||
let mut d = 0_f64;
|
||||
|
||||
self.pixel(x0 + x, y0 + y, color);
|
||||
self.pixel(x0 - x, y0 - y, color);
|
||||
self.pixel(x0 + y, y0 - x, color);
|
||||
self.pixel(x0 - y, y0 + x, color);
|
||||
|
||||
while x > y {
|
||||
let di = dist(radius, y);
|
||||
if di < d {
|
||||
x -= 1;
|
||||
}
|
||||
let col = Color::rgba(r, g, b, (a as f64 * (1.0 - di)) as u8);
|
||||
let col2 = Color::rgba(r, g, b, (a as f64 * di) as u8);
|
||||
|
||||
self.pixel(x0 + x, y0 + y, col);
|
||||
self.pixel(x0 + x - 1, y0 + y, col2); //-
|
||||
self.pixel(x0 - x, y0 + y, col);
|
||||
self.pixel(x0 - x + 1, y0 + y, col2); //+
|
||||
self.pixel(x0 + x, y0 - y, col);
|
||||
self.pixel(x0 + x - 1, y0 - y, col2); //-
|
||||
self.pixel(x0 - x, y0 - y, col);
|
||||
self.pixel(x0 - x + 1, y0 - y, col2); //+
|
||||
|
||||
self.pixel(x0 + y, y0 + x, col);
|
||||
self.pixel(x0 + y, y0 + x - 1, col2);
|
||||
self.pixel(x0 - y, y0 + x, col);
|
||||
self.pixel(x0 - y, y0 + x - 1, col2);
|
||||
self.pixel(x0 + y, y0 - x, col);
|
||||
self.pixel(x0 + y, y0 - x + 1, col2);
|
||||
self.pixel(x0 - y, y0 - x, col);
|
||||
self.pixel(x0 - y, y0 - x + 1, col2);
|
||||
d = di;
|
||||
y += 1;
|
||||
}
|
||||
|
||||
fn dist(r: i32, y: i32) -> f64 {
|
||||
let x: f64 = ((r * r - y * y) as f64).sqrt();
|
||||
x.ceil() - x
|
||||
}
|
||||
}
|
||||
|
||||
///Gets pixel color at x,y position
|
||||
fn getpixel(&self, x: i32, y: i32) -> Color {
|
||||
let p = (self.width() as i32 * y + x) as usize;
|
||||
if p >= self.data().len() {
|
||||
return Color::rgba(0, 0, 0, 0);
|
||||
}
|
||||
self.data()[p]
|
||||
}
|
||||
}
|
||||
440
third-party/vendor/orbclient/src/sys/orbital.rs
vendored
Normal file
440
third-party/vendor/orbclient/src/sys/orbital.rs
vendored
Normal file
|
|
@ -0,0 +1,440 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
|
||||
use std::{env, mem, slice, thread};
|
||||
|
||||
use libredox::{call as redox, flag};
|
||||
|
||||
use crate::color::Color;
|
||||
use crate::event::{Event, EVENT_RESIZE};
|
||||
use crate::renderer::Renderer;
|
||||
use crate::Mode;
|
||||
use crate::WindowFlag;
|
||||
|
||||
pub fn get_display_size() -> Result<(u32, u32), String> {
|
||||
let display_path = env::var("DISPLAY").or(Err("DISPLAY not set"))?;
|
||||
match File::open(&display_path) {
|
||||
Ok(display) => {
|
||||
let mut buf: [u8; 4096] = [0; 4096];
|
||||
let count = redox::fpath(display.as_raw_fd() as usize, &mut buf)
|
||||
.map_err(|err| format!("{}", err))?;
|
||||
let path = unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) };
|
||||
let res = path.split(":").nth(1).unwrap_or("");
|
||||
let width = res
|
||||
.split("/")
|
||||
.nth(1)
|
||||
.unwrap_or("")
|
||||
.parse::<u32>()
|
||||
.unwrap_or(0);
|
||||
let height = res
|
||||
.split("/")
|
||||
.nth(2)
|
||||
.unwrap_or("")
|
||||
.parse::<u32>()
|
||||
.unwrap_or(0);
|
||||
Ok((width, height))
|
||||
}
|
||||
Err(err) => Err(format!("{}", err)),
|
||||
}
|
||||
}
|
||||
|
||||
/// A window
|
||||
pub struct Window {
|
||||
/// The x coordinate of the window
|
||||
x: i32,
|
||||
/// The y coordinate of the window
|
||||
y: i32,
|
||||
/// The width of the window
|
||||
w: u32,
|
||||
/// The height of the window
|
||||
h: u32,
|
||||
/// The title of the window
|
||||
t: String,
|
||||
/// True if the window should not wait for events
|
||||
window_async: bool,
|
||||
/// True if the window can be resized
|
||||
resizable: bool,
|
||||
/// Drawing mode
|
||||
mode: Cell<Mode>,
|
||||
/// The input scheme
|
||||
file_opt: Option<File>,
|
||||
/// Window data
|
||||
data_opt: Option<&'static mut [Color]>,
|
||||
}
|
||||
|
||||
impl Renderer for Window {
|
||||
/// Get width
|
||||
fn width(&self) -> u32 {
|
||||
self.w
|
||||
}
|
||||
|
||||
/// Get height
|
||||
fn height(&self) -> u32 {
|
||||
self.h
|
||||
}
|
||||
|
||||
/// Access pixel buffer
|
||||
fn data(&self) -> &[Color] {
|
||||
self.data_opt.as_ref().unwrap()
|
||||
}
|
||||
|
||||
/// Access pixel buffer mutably
|
||||
fn data_mut(&mut self) -> &mut [Color] {
|
||||
self.data_opt.as_mut().unwrap()
|
||||
}
|
||||
|
||||
/// Flip the buffer
|
||||
fn sync(&mut self) -> bool {
|
||||
self.file_mut().sync_data().is_ok()
|
||||
}
|
||||
|
||||
/// Set/get mode
|
||||
fn mode(&self) -> &Cell<Mode> {
|
||||
&self.mode
|
||||
}
|
||||
}
|
||||
|
||||
impl Window {
|
||||
/// Create a new window
|
||||
pub fn new(x: i32, y: i32, w: u32, h: u32, title: &str) -> Option<Self> {
|
||||
Window::new_flags(x, y, w, h, title, &[])
|
||||
}
|
||||
|
||||
/// Create a new window with flags
|
||||
pub fn new_flags(
|
||||
x: i32,
|
||||
y: i32,
|
||||
w: u32,
|
||||
h: u32,
|
||||
title: &str,
|
||||
flags: &[WindowFlag],
|
||||
) -> Option<Self> {
|
||||
let mut flag_str = String::new();
|
||||
|
||||
let mut window_async = false;
|
||||
let mut resizable = false;
|
||||
for &flag in flags.iter() {
|
||||
match flag {
|
||||
WindowFlag::Async => {
|
||||
window_async = true;
|
||||
flag_str.push('a');
|
||||
}
|
||||
WindowFlag::Back => flag_str.push('b'),
|
||||
WindowFlag::Front => flag_str.push('f'),
|
||||
WindowFlag::Borderless => flag_str.push('l'),
|
||||
WindowFlag::Resizable => {
|
||||
resizable = true;
|
||||
flag_str.push('r');
|
||||
}
|
||||
WindowFlag::Transparent => flag_str.push('t'),
|
||||
WindowFlag::Unclosable => flag_str.push('u'),
|
||||
}
|
||||
}
|
||||
|
||||
if let Ok(file) = File::open(&format!(
|
||||
"orbital:{}/{}/{}/{}/{}/{}",
|
||||
flag_str, x, y, w, h, title
|
||||
)) {
|
||||
let mut window = Window {
|
||||
x,
|
||||
y,
|
||||
w,
|
||||
h,
|
||||
t: title.to_string(),
|
||||
window_async,
|
||||
resizable,
|
||||
mode: Cell::new(Mode::Blend),
|
||||
file_opt: Some(file),
|
||||
data_opt: None,
|
||||
};
|
||||
unsafe { window.remap(); }
|
||||
Some(window)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clipboard(&self) -> String {
|
||||
let mut text = String::new();
|
||||
let window_fd = self.file().as_raw_fd();
|
||||
if let Ok(clipboard_fd) = redox::dup(window_fd as usize, b"clipboard") {
|
||||
let mut clipboard_file = unsafe { File::from_raw_fd(clipboard_fd as RawFd) };
|
||||
let _ = clipboard_file.read_to_string(&mut text);
|
||||
}
|
||||
text
|
||||
}
|
||||
|
||||
pub fn set_clipboard(&mut self, text: &str) {
|
||||
let window_fd = self.file().as_raw_fd();
|
||||
if let Ok(clipboard_fd) = redox::dup(window_fd as usize, b"clipboard") {
|
||||
let mut clipboard_file = unsafe { File::from_raw_fd(clipboard_fd as RawFd) };
|
||||
let _ = clipboard_file.write(text.as_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
/// Not yet available on Redox OS.
|
||||
pub fn pop_drop_content(&self) -> Option<String> {
|
||||
None
|
||||
}
|
||||
|
||||
// TODO: Replace with smarter mechanism, maybe a move event?
|
||||
pub fn sync_path(&mut self) {
|
||||
let mut buf: [u8; 4096] = [0; 4096];
|
||||
if let Ok(count) = redox::fpath(self.file().as_raw_fd() as usize, &mut buf) {
|
||||
let path = unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) };
|
||||
// orbital:/x/y/w/h/t
|
||||
let mut parts = path.split('/');
|
||||
if let Some(flags) = parts.next() {
|
||||
self.window_async = flags.contains('a');
|
||||
self.resizable = flags.contains('r');
|
||||
}
|
||||
if let Some(x) = parts.next() {
|
||||
self.x = x.parse::<i32>().unwrap_or(0);
|
||||
}
|
||||
if let Some(y) = parts.next() {
|
||||
self.y = y.parse::<i32>().unwrap_or(0);
|
||||
}
|
||||
if let Some(w) = parts.next() {
|
||||
self.w = w.parse::<u32>().unwrap_or(0);
|
||||
}
|
||||
if let Some(h) = parts.next() {
|
||||
self.h = h.parse::<u32>().unwrap_or(0);
|
||||
}
|
||||
if let Some(t) = parts.next() {
|
||||
self.t = t.to_string();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get x
|
||||
// TODO: Sync with window movements
|
||||
pub fn x(&self) -> i32 {
|
||||
self.x
|
||||
}
|
||||
|
||||
/// Get y
|
||||
// TODO: Sync with window movements
|
||||
pub fn y(&self) -> i32 {
|
||||
self.y
|
||||
}
|
||||
|
||||
/// Get title
|
||||
pub fn title(&self) -> String {
|
||||
self.t.clone()
|
||||
}
|
||||
|
||||
/// Get async
|
||||
pub fn is_async(&self) -> bool {
|
||||
self.window_async
|
||||
}
|
||||
|
||||
/// Set async
|
||||
pub fn set_async(&mut self, is_async: bool) {
|
||||
self.window_async = is_async;
|
||||
let _ = self.file_mut().write(if is_async { b"A,1" } else { b"A,0" });
|
||||
}
|
||||
|
||||
/// Set cursor visibility
|
||||
pub fn set_mouse_cursor(&mut self, visible: bool) {
|
||||
let _ = self.file_mut().write(if visible { b"M,C,1" } else { b"M,C,0" });
|
||||
}
|
||||
|
||||
/// Set mouse grabbing
|
||||
pub fn set_mouse_grab(&mut self, grab: bool) {
|
||||
let _ = self.file_mut().write(if grab { b"M,G,1" } else { b"M,G,0" });
|
||||
}
|
||||
|
||||
/// Set mouse relative mode
|
||||
pub fn set_mouse_relative(&mut self, relative: bool) {
|
||||
let _ = self.file_mut().write(if relative { b"M,R,1" } else { b"M,R,0" });
|
||||
}
|
||||
|
||||
/// Set position
|
||||
pub fn set_pos(&mut self, x: i32, y: i32) {
|
||||
let _ = self.file_mut().write(&format!("P,{},{}", x, y).as_bytes());
|
||||
self.sync_path();
|
||||
}
|
||||
|
||||
/// Set size
|
||||
pub fn set_size(&mut self, width: u32, height: u32) {
|
||||
//TODO: Improve safety and reliability
|
||||
unsafe { self.unmap(); }
|
||||
|
||||
let _ = self
|
||||
.file_mut()
|
||||
.write(&format!("S,{},{}", width, height).as_bytes());
|
||||
self.sync_path();
|
||||
|
||||
unsafe { self.remap(); }
|
||||
}
|
||||
|
||||
/// Set title
|
||||
pub fn set_title(&mut self, title: &str) {
|
||||
let _ = self.file_mut().write(&format!("T,{}", title).as_bytes());
|
||||
self.sync_path();
|
||||
}
|
||||
|
||||
/// Blocking iterator over events
|
||||
pub fn events(&mut self) -> EventIter {
|
||||
let mut iter = EventIter {
|
||||
extra: None,
|
||||
events: [Event::new(); 16],
|
||||
i: 0,
|
||||
count: 0,
|
||||
};
|
||||
|
||||
'blocking: loop {
|
||||
if iter.count == iter.events.len() {
|
||||
if iter.extra.is_none() {
|
||||
iter.extra = Some(Vec::with_capacity(32));
|
||||
}
|
||||
iter.extra.as_mut().unwrap().extend_from_slice(&iter.events);
|
||||
iter.count = 0;
|
||||
}
|
||||
let bytes = unsafe {
|
||||
slice::from_raw_parts_mut(
|
||||
iter.events[iter.count..].as_mut_ptr() as *mut u8,
|
||||
iter.events[iter.count..].len() * mem::size_of::<Event>(),
|
||||
)
|
||||
};
|
||||
match self.file_mut().read(bytes) {
|
||||
Ok(0) => {
|
||||
if !self.window_async && iter.extra.is_none() && iter.count == 0 {
|
||||
thread::yield_now();
|
||||
} else {
|
||||
break 'blocking;
|
||||
}
|
||||
}
|
||||
Ok(count) => {
|
||||
let count = count / mem::size_of::<Event>();
|
||||
let events = &iter.events[iter.count..][..count];
|
||||
iter.count += count;
|
||||
|
||||
if self.resizable {
|
||||
let mut resize = None;
|
||||
for event in events {
|
||||
let event = *event;
|
||||
if event.code == EVENT_RESIZE {
|
||||
resize = Some((event.a as u32, event.b as u32));
|
||||
}
|
||||
}
|
||||
if let Some((w, h)) = resize {
|
||||
self.set_size(w, h);
|
||||
}
|
||||
}
|
||||
if !self.window_async {
|
||||
// Synchronous windows are blocking, can't attempt another read
|
||||
break 'blocking;
|
||||
}
|
||||
}
|
||||
Err(_) => break 'blocking,
|
||||
}
|
||||
}
|
||||
|
||||
iter
|
||||
}
|
||||
|
||||
fn file(&self) -> &File {
|
||||
self.file_opt.as_ref().unwrap()
|
||||
}
|
||||
|
||||
fn file_mut(&mut self) -> &mut File {
|
||||
self.file_opt.as_mut().unwrap()
|
||||
}
|
||||
|
||||
unsafe fn remap(&mut self) {
|
||||
self.unmap();
|
||||
|
||||
let size = (self.w * self.h) as usize;
|
||||
let address = redox::mmap(redox::MmapArgs {
|
||||
fd: self.file().as_raw_fd() as usize,
|
||||
offset: 0,
|
||||
length: size * mem::size_of::<Color>(),
|
||||
flags: flag::MAP_SHARED,
|
||||
prot: flag::PROT_READ | flag::PROT_WRITE,
|
||||
addr: core::ptr::null_mut(),
|
||||
}).expect("orbclient: failed to map memory");
|
||||
|
||||
self.data_opt = Some(
|
||||
slice::from_raw_parts_mut(address.cast::<Color>(), size)
|
||||
);
|
||||
}
|
||||
|
||||
unsafe fn unmap(&mut self) {
|
||||
if let Some(data) = self.data_opt.take() {
|
||||
redox::munmap(
|
||||
data.as_mut_ptr().cast(),
|
||||
data.len() * mem::size_of::<Color>(),
|
||||
).expect("orbclient: failed to unmap memory");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl Drop for Window {
|
||||
fn drop(&mut self) {
|
||||
unsafe { self.unmap(); }
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for Window {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.file().as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRawFd for Window {
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> Window {
|
||||
let mut window = Window {
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: 0,
|
||||
h: 0,
|
||||
t: String::new(),
|
||||
window_async: false,
|
||||
resizable: false,
|
||||
mode: Cell::new(Mode::Blend),
|
||||
file_opt: Some(File::from_raw_fd(fd)),
|
||||
data_opt: None,
|
||||
};
|
||||
window.sync_path();
|
||||
window.remap();
|
||||
window
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawFd for Window {
|
||||
fn into_raw_fd(mut self) -> RawFd {
|
||||
self.file_opt.take().unwrap().into_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
/// Event iterator
|
||||
pub struct EventIter {
|
||||
extra: Option<Vec<Event>>,
|
||||
events: [Event; 16],
|
||||
i: usize,
|
||||
count: usize,
|
||||
}
|
||||
|
||||
impl Iterator for EventIter {
|
||||
type Item = Event;
|
||||
fn next(&mut self) -> Option<Event> {
|
||||
let mut i = self.i;
|
||||
if let Some(ref mut extra) = self.extra {
|
||||
if i < extra.len() {
|
||||
self.i += 1;
|
||||
return Some(extra[i]);
|
||||
}
|
||||
i -= extra.len();
|
||||
}
|
||||
if i < self.count {
|
||||
self.i += 1;
|
||||
return Some(self.events[i]);
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
624
third-party/vendor/orbclient/src/sys/sdl2.rs
vendored
Normal file
624
third-party/vendor/orbclient/src/sys/sdl2.rs
vendored
Normal file
|
|
@ -0,0 +1,624 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::{mem, ptr, slice};
|
||||
|
||||
use crate::color::Color;
|
||||
use crate::event::*;
|
||||
use crate::renderer::Renderer;
|
||||
use crate::Mode;
|
||||
use crate::WindowFlag;
|
||||
|
||||
static SDL_USAGES: AtomicUsize = AtomicUsize::new(0);
|
||||
/// SDL2 Context
|
||||
static mut SDL_CTX: *mut sdl2::Sdl = ptr::null_mut();
|
||||
/// Video Context
|
||||
static mut VIDEO_CTX: *mut sdl2::VideoSubsystem = ptr::null_mut();
|
||||
/// Event Pump
|
||||
static mut EVENT_PUMP: *mut sdl2::EventPump = ptr::null_mut();
|
||||
|
||||
//Call this when the CTX needs to be used is created
|
||||
#[inline]
|
||||
unsafe fn init() {
|
||||
if SDL_USAGES.fetch_add(1, Ordering::Relaxed) == 0 {
|
||||
SDL_CTX = Box::into_raw(Box::new(sdl2::init().unwrap()));
|
||||
VIDEO_CTX = Box::into_raw(Box::new((*SDL_CTX).video().unwrap()));
|
||||
EVENT_PUMP = Box::into_raw(Box::new((*SDL_CTX).event_pump().unwrap()));
|
||||
}
|
||||
}
|
||||
|
||||
// Call this when drop the sdl2 CTX.
|
||||
#[inline]
|
||||
unsafe fn cleanup() {
|
||||
if SDL_USAGES.fetch_sub(1, Ordering::Relaxed) == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
drop(Box::from_raw(SDL_CTX));
|
||||
drop(Box::from_raw(VIDEO_CTX));
|
||||
drop(Box::from_raw(EVENT_PUMP));
|
||||
}
|
||||
|
||||
/// Return the (width, height) of the display in pixels
|
||||
pub fn get_display_size() -> Result<(u32, u32), String> {
|
||||
unsafe { init() };
|
||||
unsafe { &*VIDEO_CTX }
|
||||
.display_bounds(0)
|
||||
.map(|rect| (rect.width(), rect.height()))
|
||||
}
|
||||
|
||||
/// A window
|
||||
#[allow(dead_code)]
|
||||
pub struct Window {
|
||||
/// The x coordinate of the window
|
||||
x: i32,
|
||||
/// The y coordinate of the window
|
||||
y: i32,
|
||||
/// The width of the window
|
||||
w: u32,
|
||||
/// The height of the window
|
||||
h: u32,
|
||||
/// The title of the window
|
||||
t: String,
|
||||
/// True if the window should not wait for events
|
||||
window_async: bool,
|
||||
/// Drawing mode
|
||||
mode: Cell<Mode>,
|
||||
/// The inner renderer
|
||||
inner: sdl2::render::WindowCanvas,
|
||||
/// Mouse in relative mode
|
||||
mouse_relative: bool,
|
||||
/// Content of the last drop (file | text) operation
|
||||
drop_content: RefCell<Option<String>>,
|
||||
}
|
||||
|
||||
impl Drop for Window {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Renderer for Window {
|
||||
/// Get width
|
||||
fn width(&self) -> u32 {
|
||||
self.w
|
||||
}
|
||||
|
||||
/// Get height
|
||||
fn height(&self) -> u32 {
|
||||
self.h
|
||||
}
|
||||
|
||||
/// Access pixel buffer
|
||||
fn data(&self) -> &[Color] {
|
||||
let window = self.inner.window();
|
||||
let surface = window.surface(unsafe { &*EVENT_PUMP }).unwrap();
|
||||
let bytes = surface.without_lock().unwrap();
|
||||
unsafe {
|
||||
slice::from_raw_parts(
|
||||
bytes.as_ptr() as *const Color,
|
||||
bytes.len() / mem::size_of::<Color>(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Access pixel buffer mutably
|
||||
fn data_mut(&mut self) -> &mut [Color] {
|
||||
let window = self.inner.window_mut();
|
||||
let mut surface = window.surface(unsafe { &*EVENT_PUMP }).unwrap();
|
||||
let bytes = surface.without_lock_mut().unwrap();
|
||||
unsafe {
|
||||
slice::from_raw_parts_mut(
|
||||
bytes.as_mut_ptr() as *mut Color,
|
||||
bytes.len() / mem::size_of::<Color>(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Flip the window buffer
|
||||
fn sync(&mut self) -> bool {
|
||||
self.inner.present();
|
||||
true
|
||||
}
|
||||
|
||||
/// Set/get mode
|
||||
fn mode(&self) -> &Cell<Mode> {
|
||||
&self.mode
|
||||
}
|
||||
}
|
||||
|
||||
impl Window {
|
||||
/// Create a new window
|
||||
pub fn new(x: i32, y: i32, w: u32, h: u32, title: &str) -> Option<Self> {
|
||||
Window::new_flags(x, y, w, h, title, &[])
|
||||
}
|
||||
|
||||
/// Create a new window with flags
|
||||
pub fn new_flags(
|
||||
x: i32,
|
||||
y: i32,
|
||||
w: u32,
|
||||
h: u32,
|
||||
title: &str,
|
||||
flags: &[WindowFlag],
|
||||
) -> Option<Self> {
|
||||
//Insure that init has been called
|
||||
unsafe { init() };
|
||||
|
||||
let mut window_async = false;
|
||||
//TODO: Use z-order
|
||||
let mut _back = false;
|
||||
let mut _front = false;
|
||||
let mut borderless = false;
|
||||
let mut resizable = false;
|
||||
//TODO: Transparent
|
||||
let mut _transparent = false;
|
||||
//TODO: Hide exit button
|
||||
let mut _unclosable = false;
|
||||
for &flag in flags.iter() {
|
||||
match flag {
|
||||
WindowFlag::Async => window_async = true,
|
||||
WindowFlag::Back => _back = true,
|
||||
WindowFlag::Front => _front = true,
|
||||
WindowFlag::Borderless => borderless = true,
|
||||
WindowFlag::Resizable => resizable = true,
|
||||
WindowFlag::Transparent => _transparent = true,
|
||||
WindowFlag::Unclosable => _unclosable = true,
|
||||
}
|
||||
}
|
||||
|
||||
let mut builder = unsafe { &*VIDEO_CTX }.window(title, w, h);
|
||||
|
||||
{
|
||||
builder.allow_highdpi();
|
||||
}
|
||||
|
||||
if borderless {
|
||||
builder.borderless();
|
||||
}
|
||||
|
||||
if resizable {
|
||||
builder.resizable();
|
||||
}
|
||||
|
||||
if x >= 0 || y >= 0 {
|
||||
builder.position(x, y);
|
||||
}
|
||||
|
||||
match builder.build() {
|
||||
Ok(window) => Some(Window {
|
||||
x,
|
||||
y,
|
||||
w,
|
||||
h,
|
||||
t: title.to_string(),
|
||||
window_async,
|
||||
mode: Cell::new(Mode::Blend),
|
||||
inner: window.into_canvas().software().build().unwrap(),
|
||||
mouse_relative: false,
|
||||
drop_content: RefCell::new(None),
|
||||
}),
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn event_sender(&self) -> sdl2::event::EventSender {
|
||||
unsafe { &mut *SDL_CTX }.event().unwrap().event_sender()
|
||||
}
|
||||
|
||||
pub fn clipboard(&self) -> String {
|
||||
let result = unsafe { &*VIDEO_CTX }.clipboard().clipboard_text();
|
||||
|
||||
match result {
|
||||
Ok(value) => return value,
|
||||
Err(message) => println!("{}", message),
|
||||
}
|
||||
|
||||
String::default()
|
||||
}
|
||||
|
||||
pub fn set_clipboard(&mut self, text: &str) {
|
||||
let result = unsafe { &*VIDEO_CTX }.clipboard().set_clipboard_text(text);
|
||||
|
||||
if let Err(message) = result {
|
||||
println!("{}", message);
|
||||
}
|
||||
}
|
||||
|
||||
/// Pops the content of the last drop event from the window.
|
||||
pub fn pop_drop_content(&self) -> Option<String> {
|
||||
let result = self.drop_content.borrow().clone();
|
||||
*self.drop_content.borrow_mut() = None;
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
pub fn sync_path(&mut self) {
|
||||
let window = self.inner.window();
|
||||
let pos = window.position();
|
||||
let size = window.size();
|
||||
let title = window.title();
|
||||
self.x = pos.0;
|
||||
self.y = pos.1;
|
||||
self.w = size.0;
|
||||
self.h = size.1;
|
||||
self.t = title.to_string();
|
||||
}
|
||||
|
||||
/// Get x
|
||||
// TODO: Sync with window movements
|
||||
pub fn x(&self) -> i32 {
|
||||
self.x
|
||||
}
|
||||
|
||||
/// Get y
|
||||
// TODO: Sync with window movements
|
||||
pub fn y(&self) -> i32 {
|
||||
self.y
|
||||
}
|
||||
|
||||
/// Get title
|
||||
pub fn title(&self) -> String {
|
||||
self.t.clone()
|
||||
}
|
||||
|
||||
/// Get async
|
||||
pub fn is_async(&self) -> bool {
|
||||
self.window_async
|
||||
}
|
||||
|
||||
/// Set async
|
||||
pub fn set_async(&mut self, is_async: bool) {
|
||||
self.window_async = is_async;
|
||||
}
|
||||
|
||||
/// Set cursor visibility
|
||||
pub fn set_mouse_cursor(&mut self, visible: bool) {
|
||||
unsafe { &mut *SDL_CTX }.mouse().show_cursor(visible);
|
||||
}
|
||||
|
||||
/// Set mouse grabbing
|
||||
pub fn set_mouse_grab(&mut self, grab: bool) {
|
||||
unsafe { &mut *SDL_CTX }.mouse().capture(grab);
|
||||
}
|
||||
|
||||
/// Set mouse relative mode
|
||||
pub fn set_mouse_relative(&mut self, relative: bool) {
|
||||
unsafe { &mut *SDL_CTX }
|
||||
.mouse()
|
||||
.set_relative_mouse_mode(relative);
|
||||
self.mouse_relative = relative;
|
||||
}
|
||||
|
||||
/// Set position
|
||||
pub fn set_pos(&mut self, x: i32, y: i32) {
|
||||
self.inner.window_mut().set_position(
|
||||
sdl2::video::WindowPos::Positioned(x),
|
||||
sdl2::video::WindowPos::Positioned(y),
|
||||
);
|
||||
self.sync_path();
|
||||
}
|
||||
|
||||
/// Set size
|
||||
pub fn set_size(&mut self, width: u32, height: u32) {
|
||||
let _ = self.inner.window_mut().set_size(width, height);
|
||||
self.sync_path();
|
||||
}
|
||||
|
||||
/// Set title
|
||||
pub fn set_title(&mut self, title: &str) {
|
||||
let _ = self.inner.window_mut().set_title(title);
|
||||
self.sync_path();
|
||||
}
|
||||
|
||||
fn convert_scancode(
|
||||
&self,
|
||||
scancode_option: Option<sdl2::keyboard::Scancode>,
|
||||
shift: bool,
|
||||
) -> Option<(char, u8)> {
|
||||
if let Some(scancode) = scancode_option {
|
||||
match scancode {
|
||||
sdl2::keyboard::Scancode::A => Some((if shift { 'A' } else { 'a' }, K_A)),
|
||||
sdl2::keyboard::Scancode::B => Some((if shift { 'B' } else { 'b' }, K_B)),
|
||||
sdl2::keyboard::Scancode::C => Some((if shift { 'C' } else { 'c' }, K_C)),
|
||||
sdl2::keyboard::Scancode::D => Some((if shift { 'D' } else { 'd' }, K_D)),
|
||||
sdl2::keyboard::Scancode::E => Some((if shift { 'E' } else { 'e' }, K_E)),
|
||||
sdl2::keyboard::Scancode::F => Some((if shift { 'F' } else { 'f' }, K_F)),
|
||||
sdl2::keyboard::Scancode::G => Some((if shift { 'G' } else { 'g' }, K_G)),
|
||||
sdl2::keyboard::Scancode::H => Some((if shift { 'H' } else { 'h' }, K_H)),
|
||||
sdl2::keyboard::Scancode::I => Some((if shift { 'I' } else { 'i' }, K_I)),
|
||||
sdl2::keyboard::Scancode::J => Some((if shift { 'J' } else { 'j' }, K_J)),
|
||||
sdl2::keyboard::Scancode::K => Some((if shift { 'K' } else { 'k' }, K_K)),
|
||||
sdl2::keyboard::Scancode::L => Some((if shift { 'L' } else { 'l' }, K_L)),
|
||||
sdl2::keyboard::Scancode::M => Some((if shift { 'M' } else { 'm' }, K_M)),
|
||||
sdl2::keyboard::Scancode::N => Some((if shift { 'N' } else { 'n' }, K_N)),
|
||||
sdl2::keyboard::Scancode::O => Some((if shift { 'O' } else { 'o' }, K_O)),
|
||||
sdl2::keyboard::Scancode::P => Some((if shift { 'P' } else { 'p' }, K_P)),
|
||||
sdl2::keyboard::Scancode::Q => Some((if shift { 'Q' } else { 'q' }, K_Q)),
|
||||
sdl2::keyboard::Scancode::R => Some((if shift { 'R' } else { 'r' }, K_R)),
|
||||
sdl2::keyboard::Scancode::S => Some((if shift { 'S' } else { 's' }, K_S)),
|
||||
sdl2::keyboard::Scancode::T => Some((if shift { 'T' } else { 't' }, K_T)),
|
||||
sdl2::keyboard::Scancode::U => Some((if shift { 'U' } else { 'u' }, K_U)),
|
||||
sdl2::keyboard::Scancode::V => Some((if shift { 'V' } else { 'v' }, K_V)),
|
||||
sdl2::keyboard::Scancode::W => Some((if shift { 'W' } else { 'w' }, K_W)),
|
||||
sdl2::keyboard::Scancode::X => Some((if shift { 'X' } else { 'x' }, K_X)),
|
||||
sdl2::keyboard::Scancode::Y => Some((if shift { 'Y' } else { 'y' }, K_Y)),
|
||||
sdl2::keyboard::Scancode::Z => Some((if shift { 'Z' } else { 'z' }, K_Z)),
|
||||
sdl2::keyboard::Scancode::Num0 => Some((if shift { ')' } else { '0' }, K_0)),
|
||||
sdl2::keyboard::Scancode::Num1 => Some((if shift { '!' } else { '1' }, K_1)),
|
||||
sdl2::keyboard::Scancode::Num2 => Some((if shift { '@' } else { '2' }, K_2)),
|
||||
sdl2::keyboard::Scancode::Num3 => Some((if shift { '#' } else { '3' }, K_3)),
|
||||
sdl2::keyboard::Scancode::Num4 => Some((if shift { '$' } else { '4' }, K_4)),
|
||||
sdl2::keyboard::Scancode::Num5 => Some((if shift { '%' } else { '5' }, K_5)),
|
||||
sdl2::keyboard::Scancode::Num6 => Some((if shift { '^' } else { '6' }, K_6)),
|
||||
sdl2::keyboard::Scancode::Num7 => Some((if shift { '&' } else { '7' }, K_7)),
|
||||
sdl2::keyboard::Scancode::Num8 => Some((if shift { '*' } else { '8' }, K_8)),
|
||||
sdl2::keyboard::Scancode::Num9 => Some((if shift { '(' } else { '9' }, K_9)),
|
||||
sdl2::keyboard::Scancode::Grave => Some((if shift { '~' } else { '`' }, K_TICK)),
|
||||
sdl2::keyboard::Scancode::Minus => Some((if shift { '_' } else { '-' }, K_MINUS)),
|
||||
sdl2::keyboard::Scancode::Equals => Some((if shift { '+' } else { '=' }, K_EQUALS)),
|
||||
sdl2::keyboard::Scancode::LeftBracket => {
|
||||
Some((if shift { '{' } else { '[' }, K_BRACE_OPEN))
|
||||
}
|
||||
sdl2::keyboard::Scancode::RightBracket => {
|
||||
Some((if shift { '}' } else { ']' }, K_BRACE_CLOSE))
|
||||
}
|
||||
sdl2::keyboard::Scancode::Backslash => {
|
||||
Some((if shift { '|' } else { '\\' }, K_BACKSLASH))
|
||||
}
|
||||
sdl2::keyboard::Scancode::Semicolon => {
|
||||
Some((if shift { ':' } else { ';' }, K_SEMICOLON))
|
||||
}
|
||||
sdl2::keyboard::Scancode::Apostrophe => {
|
||||
Some((if shift { '"' } else { '\'' }, K_QUOTE))
|
||||
}
|
||||
sdl2::keyboard::Scancode::Comma => Some((if shift { '<' } else { ',' }, K_COMMA)),
|
||||
sdl2::keyboard::Scancode::Period => Some((if shift { '>' } else { '.' }, K_PERIOD)),
|
||||
sdl2::keyboard::Scancode::Slash => Some((if shift { '?' } else { '/' }, K_SLASH)),
|
||||
sdl2::keyboard::Scancode::Space => Some((' ', K_SPACE)),
|
||||
sdl2::keyboard::Scancode::Backspace => Some(('\0', K_BKSP)),
|
||||
sdl2::keyboard::Scancode::Tab => Some(('\t', K_TAB)),
|
||||
sdl2::keyboard::Scancode::LCtrl => Some(('\0', K_CTRL)),
|
||||
sdl2::keyboard::Scancode::RCtrl => Some(('\0', K_CTRL)),
|
||||
sdl2::keyboard::Scancode::LAlt => Some(('\0', K_ALT)),
|
||||
sdl2::keyboard::Scancode::RAlt => Some(('\0', K_ALT)),
|
||||
sdl2::keyboard::Scancode::Return => Some(('\n', K_ENTER)),
|
||||
sdl2::keyboard::Scancode::Escape => Some(('\x1B', K_ESC)),
|
||||
sdl2::keyboard::Scancode::F1 => Some(('\0', K_F1)),
|
||||
sdl2::keyboard::Scancode::F2 => Some(('\0', K_F2)),
|
||||
sdl2::keyboard::Scancode::F3 => Some(('\0', K_F3)),
|
||||
sdl2::keyboard::Scancode::F4 => Some(('\0', K_F4)),
|
||||
sdl2::keyboard::Scancode::F5 => Some(('\0', K_F5)),
|
||||
sdl2::keyboard::Scancode::F6 => Some(('\0', K_F6)),
|
||||
sdl2::keyboard::Scancode::F7 => Some(('\0', K_F7)),
|
||||
sdl2::keyboard::Scancode::F8 => Some(('\0', K_F8)),
|
||||
sdl2::keyboard::Scancode::F9 => Some(('\0', K_F9)),
|
||||
sdl2::keyboard::Scancode::F10 => Some(('\0', K_F10)),
|
||||
sdl2::keyboard::Scancode::Home => Some(('\0', K_HOME)),
|
||||
sdl2::keyboard::Scancode::LGui => Some(('\0', K_HOME)),
|
||||
sdl2::keyboard::Scancode::Up => Some(('\0', K_UP)),
|
||||
sdl2::keyboard::Scancode::PageUp => Some(('\0', K_PGUP)),
|
||||
sdl2::keyboard::Scancode::Left => Some(('\0', K_LEFT)),
|
||||
sdl2::keyboard::Scancode::Right => Some(('\0', K_RIGHT)),
|
||||
sdl2::keyboard::Scancode::End => Some(('\0', K_END)),
|
||||
sdl2::keyboard::Scancode::Down => Some(('\0', K_DOWN)),
|
||||
sdl2::keyboard::Scancode::PageDown => Some(('\0', K_PGDN)),
|
||||
sdl2::keyboard::Scancode::Delete => Some(('\0', K_DEL)),
|
||||
sdl2::keyboard::Scancode::F11 => Some(('\0', K_F11)),
|
||||
sdl2::keyboard::Scancode::F12 => Some(('\0', K_F12)),
|
||||
sdl2::keyboard::Scancode::LShift => Some(('\0', K_LEFT_SHIFT)),
|
||||
sdl2::keyboard::Scancode::RShift => Some(('\0', K_RIGHT_SHIFT)),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn get_mouse_position(&self) -> (i32, i32) {
|
||||
unsafe {
|
||||
let p_x: *mut i32 = libc::malloc(mem::size_of::<i32>()) as *mut i32;
|
||||
let p_y: *mut i32 = libc::malloc(mem::size_of::<i32>()) as *mut i32;
|
||||
sdl2_sys::SDL_GetMouseState(p_x, p_y);
|
||||
|
||||
(*p_x, *p_y)
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_event(&self, event: sdl2::event::Event) -> Vec<Event> {
|
||||
let mut events = Vec::new();
|
||||
|
||||
let button_event = || -> Event {
|
||||
let mouse = unsafe { &mut *EVENT_PUMP }.mouse_state();
|
||||
ButtonEvent {
|
||||
left: mouse.left(),
|
||||
middle: mouse.middle(),
|
||||
right: mouse.right(),
|
||||
}
|
||||
.to_event()
|
||||
};
|
||||
|
||||
let mods = unsafe { &mut *SDL_CTX }.keyboard().mod_state();
|
||||
let shift = mods.contains(sdl2::keyboard::Mod::CAPSMOD)
|
||||
|| mods.contains(sdl2::keyboard::Mod::LSHIFTMOD)
|
||||
|| mods.contains(sdl2::keyboard::Mod::RSHIFTMOD);
|
||||
|
||||
match event {
|
||||
sdl2::event::Event::RenderTargetsReset { .. } => {
|
||||
events.push(Event::new());
|
||||
}
|
||||
sdl2::event::Event::Window { win_event, .. } => match win_event {
|
||||
sdl2::event::WindowEvent::Moved(x, y) => {
|
||||
events.push(MoveEvent { x, y }.to_event())
|
||||
}
|
||||
sdl2::event::WindowEvent::Resized(w, h) => events.push(
|
||||
ResizeEvent {
|
||||
width: w as u32,
|
||||
height: h as u32,
|
||||
}
|
||||
.to_event(),
|
||||
),
|
||||
sdl2::event::WindowEvent::FocusGained => {
|
||||
events.push(FocusEvent { focused: true }.to_event())
|
||||
}
|
||||
sdl2::event::WindowEvent::FocusLost => {
|
||||
events.push(FocusEvent { focused: false }.to_event())
|
||||
}
|
||||
sdl2::event::WindowEvent::Enter => {
|
||||
events.push(HoverEvent { entered: true }.to_event())
|
||||
}
|
||||
sdl2::event::WindowEvent::Leave => {
|
||||
events.push(HoverEvent { entered: false }.to_event())
|
||||
}
|
||||
sdl2::event::WindowEvent::None => events.push(Event::new()),
|
||||
_ => (),
|
||||
},
|
||||
sdl2::event::Event::ClipboardUpdate { .. } => {
|
||||
events.push(ClipboardUpdateEvent.to_event())
|
||||
}
|
||||
sdl2::event::Event::MouseMotion {
|
||||
x, y, xrel, yrel, ..
|
||||
} => {
|
||||
if self.mouse_relative {
|
||||
events.push(MouseRelativeEvent { dx: xrel, dy: yrel }.to_event())
|
||||
} else {
|
||||
events.push(MouseEvent { x, y }.to_event())
|
||||
}
|
||||
}
|
||||
sdl2::event::Event::MouseButtonDown { .. } => events.push(button_event()),
|
||||
sdl2::event::Event::MouseButtonUp { .. } => events.push(button_event()),
|
||||
sdl2::event::Event::MouseWheel { x, y, .. } => {
|
||||
events.push(ScrollEvent { x, y }.to_event())
|
||||
}
|
||||
sdl2::event::Event::TextInput { text, .. } => {
|
||||
for character in text.chars() {
|
||||
events.push(
|
||||
TextInputEvent {
|
||||
character,
|
||||
}
|
||||
.to_event(),
|
||||
);
|
||||
}
|
||||
}
|
||||
sdl2::event::Event::KeyDown { scancode, .. } => {
|
||||
if let Some(code) = self.convert_scancode(scancode, shift) {
|
||||
events.push(
|
||||
KeyEvent {
|
||||
character: code.0,
|
||||
scancode: code.1,
|
||||
pressed: true,
|
||||
}
|
||||
.to_event(),
|
||||
);
|
||||
}
|
||||
}
|
||||
sdl2::event::Event::DropFile { filename, .. } => {
|
||||
*self.drop_content.borrow_mut() = Some(filename);
|
||||
|
||||
let (x, y) = self.get_mouse_position();
|
||||
|
||||
events.push(MouseEvent { x, y }.to_event());
|
||||
|
||||
events.push(DropEvent { kind: DROP_FILE }.to_event())
|
||||
}
|
||||
sdl2::event::Event::DropText { filename, .. } => {
|
||||
*self.drop_content.borrow_mut() = Some(filename);
|
||||
|
||||
let (x, y) = self.get_mouse_position();
|
||||
|
||||
events.push(MouseEvent { x, y }.to_event());
|
||||
events.push(DropEvent { kind: DROP_TEXT }.to_event())
|
||||
}
|
||||
sdl2::event::Event::KeyUp { scancode, .. } => {
|
||||
if let Some(code) = self.convert_scancode(scancode, shift) {
|
||||
events.push(
|
||||
KeyEvent {
|
||||
character: code.0,
|
||||
scancode: code.1,
|
||||
pressed: false,
|
||||
}
|
||||
.to_event(),
|
||||
);
|
||||
}
|
||||
}
|
||||
sdl2::event::Event::Quit { .. } => events.push(QuitEvent.to_event()),
|
||||
_ => (),
|
||||
}
|
||||
|
||||
events
|
||||
}
|
||||
|
||||
/// Blocking iterator over events
|
||||
pub fn events(&mut self) -> EventIter {
|
||||
let mut iter = EventIter {
|
||||
events: [Event::new(); 16],
|
||||
i: 0,
|
||||
count: 0,
|
||||
};
|
||||
|
||||
if !self.window_async {
|
||||
let event = unsafe { &mut *EVENT_PUMP }.wait_event();
|
||||
if let sdl2::event::Event::Window { .. } = event {
|
||||
self.sync_path();
|
||||
}
|
||||
for converted_event in self.convert_event(event) {
|
||||
if iter.count < iter.events.len() {
|
||||
iter.events[iter.count] = converted_event;
|
||||
iter.count += 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while let Some(event) = unsafe { &mut *EVENT_PUMP }.poll_event() {
|
||||
if let sdl2::event::Event::Window { .. } = event {
|
||||
self.sync_path();
|
||||
}
|
||||
for converted_event in self.convert_event(event) {
|
||||
if iter.count < iter.events.len() {
|
||||
iter.events[iter.count] = converted_event;
|
||||
iter.count += 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if iter.count + 2 < iter.events.len() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
iter
|
||||
}
|
||||
|
||||
/// Returns the id
|
||||
pub fn id(&self) -> u32 {
|
||||
self.inner.window().id()
|
||||
}
|
||||
}
|
||||
|
||||
/// Event iterator
|
||||
pub struct EventIter {
|
||||
events: [Event; 16],
|
||||
i: usize,
|
||||
count: usize,
|
||||
}
|
||||
|
||||
impl Iterator for EventIter {
|
||||
type Item = Event;
|
||||
fn next(&mut self) -> Option<Event> {
|
||||
if self.i < self.count {
|
||||
if let Some(event) = self.events.get(self.i) {
|
||||
self.i += 1;
|
||||
Some(*event)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue