Skip to content

Commit

Permalink
[libgui - Rust] Provide a Window implementation that can be used in U…
Browse files Browse the repository at this point in the history
…EFI contexts
  • Loading branch information
codyd51 committed Feb 7, 2024
1 parent a8ea0a1 commit cee2b7d
Show file tree
Hide file tree
Showing 4 changed files with 193 additions and 7 deletions.
8 changes: 6 additions & 2 deletions rust_programs/libgui/src/font.rs
Expand Up @@ -13,7 +13,7 @@ use ttf_renderer::{

#[cfg(target_os = "axle")]
use axle_rt::{amc_message_await__u32_event, amc_message_send};
#[cfg(not(target_os = "axle"))]
#[cfg(not(any(target_os = "axle", feature = "run_in_uefi")))]
use std::fs;

pub const CHAR_WIDTH: usize = 8;
Expand Down Expand Up @@ -211,7 +211,11 @@ pub fn load_font(path: &str) -> Font {
data.to_vec()
}
}
#[cfg(not(target_os = "axle"))]
#[cfg(feature = "run_in_uefi")]
{
panic!("Not available in no_std");
}
#[cfg(not(any(target_os = "axle", feature = "run_in_uefi")))]
{
fs::read(path).unwrap()
}
Expand Down
14 changes: 10 additions & 4 deletions rust_programs/libgui/src/lib.rs
@@ -1,4 +1,4 @@
#![cfg_attr(target_os = "axle", no_std)]
#![cfg_attr(any(target_os = "axle", feature = "run_in_uefi"), no_std)]
#![feature(format_args_nl)]

extern crate alloc;
Expand Down Expand Up @@ -27,9 +27,15 @@ pub use axle_rt::{print, println};
#[cfg(target_os = "axle")]
pub use window_axle::*;

#[cfg(not(target_os = "axle"))]
#[cfg(not(any(target_os = "axle", feature = "run_in_uefi")))]
mod window_std;
#[cfg(not(target_os = "axle"))]

#[cfg(feature = "run_in_uefi")]
mod window_uefi;
#[cfg(feature = "run_in_uefi")]
pub use window_uefi::*;

#[cfg(not(any(target_os = "axle", feature = "run_in_uefi")))]
pub use std::{print, println};
#[cfg(not(target_os = "axle"))]
#[cfg(not(any(target_os = "axle", feature = "run_in_uefi")))]
pub use window_std::*;
2 changes: 1 addition & 1 deletion rust_programs/libgui/src/text_view.rs
Expand Up @@ -30,7 +30,7 @@ use ttf_renderer::{
use axle_rt::{amc_message_await__u32_event, amc_message_send};

use crate::font::{draw_char_with_font_onto, load_font, scaled_metrics_for_codepoint};
#[cfg(not(target_os = "axle"))]
#[cfg(not(any(target_os = "axle", feature = "run_in_uefi")))]
use std::fs;

#[derive(Debug, Copy, Clone)]
Expand Down
176 changes: 176 additions & 0 deletions rust_programs/libgui/src/window_uefi.rs
@@ -0,0 +1,176 @@
use alloc::vec;
use alloc::{boxed::Box, rc::Rc};
use alloc::{rc::Weak, vec::Vec};

use core::cell::RefCell;

use axle_rt::core_commands::{AmcSleepUntilDelayOrMessage, AMC_CORE_SERVICE_NAME};

use axle_rt::{printf, ExpectsEventField};

use agx_definitions::{
Drawable, Layer, LikeLayerSlice, NestedLayerSlice, PixelByteLayout, Point, Rect,
SingleFramebufferLayer, Size,
};

use crate::ui_elements::*;
use crate::window_events::*;

pub struct AwmWindow {
pub layer: RefCell<SingleFramebufferLayer>,
pub current_size: RefCell<Size>,
ui_elements: RefCell<Vec<Rc<dyn UIElement>>>,
ui_elements_containing_mouse: RefCell<Vec<Rc<dyn UIElement>>>,
}

impl AwmWindow {
pub fn new(size: Size) -> Rc<Self> {
// PT: Assume 4 bytes per pixel everywhere...
let bpp = 4;
let framebuffer =
vec![0; (size.width * size.height * (bpp as isize)) as usize].into_boxed_slice();
let layer = RefCell::new(SingleFramebufferLayer::from_framebuffer(
framebuffer,
bpp,
size,
PixelByteLayout::BGRA,
));

Rc::new(Self {
layer,
current_size: RefCell::new(size),
ui_elements: RefCell::new(vec![]),
ui_elements_containing_mouse: RefCell::new(vec![]),
})
}

pub fn add_component(self: Rc<Self>, elem: Rc<dyn UIElement>) {
// Ensure the component has a frame by running its sizer
elem.handle_superview_resize(*self.current_size.borrow());
// Set up a link to the parent
elem.set_parent(Rc::downgrade(&(Rc::clone(&self) as _)));
self.ui_elements.borrow_mut().push(elem);
}

pub fn draw(&self) {
let elems = &*self.ui_elements.borrow();
for elem in elems {
elem.draw();
}
}

pub fn commit(&self) {}

pub fn resize_subviews(&self) {
let elems = &*self.ui_elements.borrow();
for elem in elems {
elem.handle_superview_resize(*self.current_size.borrow());
}
self.draw();
self.commit();
}

pub fn handle_key_pressed(&self, key_code: KeyCode) {
let elems = self.ui_elements.borrow();
for elem in elems.iter() {
elem.handle_key_pressed(key_code);
}
}

pub fn handle_key_released(&self, key_code: KeyCode) {
let elems = self.ui_elements.borrow();
for elem in elems.iter() {
elem.handle_key_released(key_code);
}
}

pub fn handle_mouse_moved(&self, mouse_point: Point) {
let elems = &*self.ui_elements.borrow();
let elems_containing_mouse = &mut *self.ui_elements_containing_mouse.borrow_mut();

// First up, send entered/exited events for each element
for elem in elems {
let elem_contains_mouse = elem.frame().contains(mouse_point);

// Did this element previously bound the mouse?
if let Some(index) = elems_containing_mouse
.iter()
.position(|e| Rc::ptr_eq(e, elem))
{
// Did the mouse just exit this element?
if !elem_contains_mouse {
elem.handle_mouse_exited();
// We don't need to preserve ordering, so swap_remove is OK
elems_containing_mouse.swap_remove(index);
}
} else if elem_contains_mouse {
elem.handle_mouse_entered();
elems_containing_mouse.push(Rc::clone(elem));
}
}

for elem in elems_containing_mouse {
// Translate the mouse position to the element's coordinate system
let elem_pos = mouse_point - elem.frame().origin;
elem.handle_mouse_moved(elem_pos);
}
}

pub fn handle_mouse_left_click_down(&self, mouse_pos: Point) {
let mut clicked_elem = None;
{
let elems = &*self.ui_elements.borrow();
for elem in elems {
if elem.frame().contains(Point::from(mouse_pos)) {
clicked_elem = Some(Rc::clone(elem));
break;
}
}
}

if let Some(c) = clicked_elem {
// Translate the mouse position to the element's coordinate system
let mouse_point = Point::from(mouse_pos);
let elem_pos = mouse_point - c.frame().origin;
c.handle_left_click(elem_pos);
}
}

pub fn handle_mouse_left_click_up(&self, mouse_pos: Point) {
// Nothing to do
}
}

impl NestedLayerSlice for AwmWindow {
fn get_parent(&self) -> Option<Weak<dyn NestedLayerSlice>> {
None
}

fn set_parent(&self, _parent: Weak<dyn NestedLayerSlice>) {
panic!("Not supported for AwmWindow");
}

fn get_slice(&self) -> Box<dyn LikeLayerSlice> {
self.layer
.borrow_mut()
.get_slice(Rect::from_parts(Point::zero(), *self.current_size.borrow()))
}

fn get_slice_for_render(&self) -> Box<dyn LikeLayerSlice> {
self.get_slice()
}
}

impl Drawable for AwmWindow {
fn frame(&self) -> Rect {
Rect::from_parts(Point::zero(), *self.current_size.borrow())
}

fn content_frame(&self) -> Rect {
self.frame()
}

fn draw(&self) -> Vec<Rect> {
panic!("Not available for AwmWindow");
}
}

0 comments on commit cee2b7d

Please sign in to comment.