Commit 973e9247 authored by Florian Blasius's avatar Florian Blasius 🤘

Implement web events. Improved web text position.

Add calculator example.
Add platform indipendent console log.
parent 0d99a82a
......@@ -23,7 +23,6 @@
"preLaunchTask": "build-web",
"url": "http://localhost:8000",
},
{
"type": "lldb",
"request": "launch",
......
......@@ -425,7 +425,7 @@ dependencies = [
[[package]]
name = "orbgl"
version = "0.1.0"
source = "git+https://gitlab.redox-os.org/redox-os/orbgl.git#837cfbabc9d70607a8aed2c317b0dfd0e9765481"
source = "git+https://gitlab.redox-os.org/redox-os/orbgl.git#3063a228825d555e2ffb36ea2564c1b7d7c8e2f7"
dependencies = [
"orbclient 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
"orbgl_api 0.1.0 (git+https://gitlab.redox-os.org/redox-os/orbgl.git)",
......@@ -436,7 +436,7 @@ dependencies = [
[[package]]
name = "orbgl_api"
version = "0.1.0"
source = "git+https://gitlab.redox-os.org/redox-os/orbgl.git#837cfbabc9d70607a8aed2c317b0dfd0e9765481"
source = "git+https://gitlab.redox-os.org/redox-os/orbgl.git#3063a228825d555e2ffb36ea2564c1b7d7c8e2f7"
dependencies = [
"orbclient 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
"orbfont 0.1.9 (git+https://gitlab.redox-os.org/redox-os/orbfont.git)",
......@@ -447,7 +447,7 @@ dependencies = [
[[package]]
name = "orbgl_web"
version = "0.1.0"
source = "git+https://gitlab.redox-os.org/redox-os/orbgl.git#837cfbabc9d70607a8aed2c317b0dfd0e9765481"
source = "git+https://gitlab.redox-os.org/redox-os/orbgl.git#3063a228825d555e2ffb36ea2564c1b7d7c8e2f7"
dependencies = [
"orbgl_api 0.1.0 (git+https://gitlab.redox-os.org/redox-os/orbgl.git)",
"stdweb 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)",
......
......@@ -52,13 +52,13 @@ impl ThemeBuilder {
}
for extension_path in self.theme_extension_paths.iter().rev() {
let file = File::open(extension_path).unwrap();
if let Ok(file) = File::open(extension_path) {
let mut reader = BufReader::new(file);
let mut css = String::new();
let _ = reader.read_to_string(&mut css).unwrap();
let mut reader = BufReader::new(file);
let mut css = String::new();
let _ = reader.read_to_string(&mut css).unwrap();
theme.push_str(&css);
theme.push_str(&css);
}
}
if let Some(css) = self.theme_css {
......@@ -66,13 +66,14 @@ impl ThemeBuilder {
};
if let Some(path) = self.theme_path {
let file = File::open(path).unwrap();
if let Ok(file) = File::open(path) {
let mut reader = BufReader::new(file);
let mut css = String::new();
let _ = reader.read_to_string(&mut css).unwrap();
theme.push_str(&css);
}
};
Theme::parse(&theme)
......
......@@ -230,6 +230,10 @@ impl<A> WindowBuilder<A> where A: WindowAdapter {
}
}
pub fn log(message: String) {
println!("{}", message);
}
// --- obsolete will be removed after OrbGL supports text rendering ---
pub struct OrbFontMeasure;
......@@ -264,7 +268,6 @@ impl OrbFontRenderer {
color: Color,
font: &Font,
) {
println!("{} {}", global_position.y, text);
if font_size > 0.0 {
let line = font.render(text, font_size);
line.draw_clipped(
......
......@@ -2,20 +2,19 @@
use std::{cell::{Cell, RefCell}, collections::HashMap, rc::Rc, sync::Arc};
use orbgl_api::{Canvas, Font};
use orbgl_web::prelude::*;
use stdweb::{
_js_impl, js,
traits::*,
unstable::TryInto,
web::{
self, document, event,
html_element::{CanvasElement, ImageElement},
window, CanvasRenderingContext2d, FillRule,
self, CanvasRenderingContext2d, document,
event,
FillRule, html_element::{CanvasElement, ImageElement}, window,
},
};
use orbgl_api::{Canvas, Font};
use orbgl_web::prelude::*;
use orbtk_utils::{Point, Rect};
use crate::{obsolete, prelude::*};
......@@ -24,38 +23,90 @@ pub fn initialize() {
stdweb::initialize();
}
fn get_mouse_button(button: event::MouseButton) -> MouseButton {
match button {
event::MouseButton::Wheel => MouseButton::Middle,
event::MouseButton::Right => MouseButton::Right,
_ => MouseButton::Left,
}
}
fn get_key(code: &str, key: char) -> Key {
match code {
"Backspace" => Key::Backspace,
"Delete" => Key::Delete,
"ControlLeft" => Key::Control,
"ShiftLeft" => Key::ShiftL,
"ShiftRight" => Key::ShiftR,
"AltLeft" => Key::Alt,
"ArrowUp" => Key::Up,
"ArrowLeft" => Key::Left,
"ArrowRight" => Key::Right,
"ArrowDown" => Key::Down,
_ => match key {
'\n' => Key::Enter,
_ => Key::from(key)
}
}
}
/// Concrete implementation of the window shell.
pub struct WindowShell<A> where A: WindowAdapter {
pub inner: WebRenderer,
pub canvas: Canvas,
adapter: A
pub mouse_move_events: Rc<RefCell<Vec<event::MouseMoveEvent>>>,
pub mouse_up_events: Rc<RefCell<Vec<event::MouseUpEvent>>>,
pub mouse_down_events: Rc<RefCell<Vec<event::MouseDownEvent>>>,
pub key_up_events: Rc<RefCell<Vec<event::KeyUpEvent>>>,
pub key_down_events: Rc<RefCell<Vec<event::KeyDownEvent>>>,
adapter: A,
}
impl<A> WindowShell<A> where A: WindowAdapter {
/// Creates a new window shell with an adapter.
pub fn new(inner: WebRenderer, canvas: Canvas, adapter: A) -> WindowShell<A> {
WindowShell {
inner,
canvas,
adapter,
}
}
/// Gets the shell adapter.
pub fn adapter(&mut self) -> &mut A {
&mut self.adapter
}
fn drain_events(&mut self) {
while let Some(event) = self.mouse_move_events.borrow_mut().pop() {
self.adapter.mouse(event.client_x() as f64, event.client_y() as f64);
}
while let Some(event) = self.mouse_down_events.borrow_mut().pop() {
self.adapter.mouse_event(MouseEvent {
x: event.client_x() as f64,
y: event.client_y() as f64,
button: get_mouse_button(event.button()),
state: ButtonState::Down,
});
}
while let Some(event) = self.mouse_up_events.borrow_mut().pop() {
self.adapter.mouse_event(MouseEvent {
x: event.client_x() as f64,
y: event.client_y() as f64,
button: get_mouse_button(event.button()),
state: ButtonState::Up,
});
}
while let Some(event) = self.key_down_events.borrow_mut().pop() {
self.adapter.key_event(KeyEvent {
key: get_key(event.code().as_str(), event.key().remove(0)),
state: ButtonState::Down,
});
}
while let Some(event) = self.key_up_events.borrow_mut().pop() {
self.adapter.key_event(KeyEvent {
key: get_key(event.code().as_str(), event.key().remove(0)),
state: ButtonState::Up,
});
}
}
}
// impl<A> Drop for WindowShell<A> where A: WindowAdapter {
// fn drop(&mut self) {
// self.inner.sync();
// }
// }
/// Implementation of the OrbClient based shell runner.
pub struct ShellRunner<A> where A: WindowAdapter + 'static {
pub window_shell: Rc<RefCell<WindowShell<A>>>,
......@@ -66,10 +117,11 @@ pub struct ShellRunner<A> where A: WindowAdapter + 'static {
impl<A> ShellRunner<A> where A: WindowAdapter {
pub fn run(mut self) {
window().request_animation_frame(move |_| {
self.updater.update();
self.update.set(false);
self.window_shell.borrow_mut().drain_events();
self.run();
});
}
}
......@@ -116,13 +168,12 @@ impl<A> WindowBuilder<A> where A: WindowAdapter {
/// Builds the window shell.
pub fn build(self) -> WindowShell<A> {
let canvas: CanvasElement = document()
.create_element("canvas")
.unwrap()
.try_into()
.unwrap();
canvas.set_width(self.bounds.width as u32);
canvas.set_height(self.bounds.height as u32);
......@@ -133,12 +184,44 @@ impl<A> WindowBuilder<A> where A: WindowAdapter {
@{&canvas}.style.margin = "0";
}
// web event queues
let mouse_move = Rc::new(RefCell::new(vec![]));
let mouse_up = Rc::new(RefCell::new(vec![]));
let mouse_down = Rc::new(RefCell::new(vec![]));
let key_down = Rc::new(RefCell::new(vec![]));
let key_up = Rc::new(RefCell::new(vec![]));
let mouse_down_c = mouse_down.clone();
canvas.add_event_listener(move |e: event::MouseDownEvent| {
mouse_down_c.borrow_mut().push(e);
});
let mouse_up_c = mouse_up.clone();
canvas.add_event_listener(move |e: event::MouseUpEvent| {
mouse_up_c.borrow_mut().push(e);
});
let mouse_move_c = mouse_move.clone();
canvas.add_event_listener(move |e: event::MouseMoveEvent| {
mouse_move_c.borrow_mut().push(e);
});
let key_down_c = key_down.clone();
document().add_event_listener(move |e: event::KeyDownEvent| {
e.prevent_default();
key_down_c.borrow_mut().push(e);
});
let key_up_c = key_up.clone();
document().add_event_listener(move |e: event::KeyUpEvent| {
e.prevent_default();
key_up_c.borrow_mut().push(e);
});
document().body().unwrap().append_child(&canvas);
let context: CanvasRenderingContext2d = canvas.get_context().unwrap();
context.set_font("Roboto");
let devicePixelRatio = window().device_pixel_ratio();
let devicePixelRatio = window().device_pixel_ratio();
let backingStoreRatio = js! {
var context = @{&context};
......@@ -152,8 +235,8 @@ impl<A> WindowBuilder<A> where A: WindowAdapter {
let ratio: f64 = js! {
return @{&devicePixelRatio} / @{&backingStoreRatio};
}
.try_into()
.unwrap();
.try_into()
.unwrap();
if devicePixelRatio != backingStoreRatio {
let old_width = canvas.width();
......@@ -177,11 +260,22 @@ impl<A> WindowBuilder<A> where A: WindowAdapter {
stdweb::event_loop();
WindowShell::new(
WebRenderer {},
WindowShell {
inner: WebRenderer {},
canvas,
self.adapter,
)
adapter: self.adapter,
mouse_move_events: mouse_move,
mouse_up_events: mouse_up,
mouse_down_events: mouse_down,
key_down_events: key_down,
key_up_events: key_up,
}
}
}
pub fn log(message: String) {
js! {
console.log(@{&message});
}
}
......@@ -191,12 +285,11 @@ pub struct WebFontMeasure;
impl FontMeasure for WebFontMeasure {
fn measure(&self, text: &str, font: &Font, font_size: u32) -> (u32, u32) {
let canvas: CanvasElement = document().query_selector( "canvas" ).unwrap().unwrap().try_into().unwrap();
let canvas: CanvasElement = document().query_selector("canvas").unwrap().unwrap().try_into().unwrap();
let context: CanvasRenderingContext2d = canvas.get_context().unwrap();
context.set_font(&format!("{}px Roboto ", font_size));
(context.measure_text(text).unwrap().get_width() as u32, font_size)
context.set_font(&format!("{}px {}", font_size, font.family));
(context.measure_text(text).unwrap().get_width() as u32, font_size)
}
}
......@@ -204,9 +297,7 @@ lazy_static! {
pub static ref FONT_MEASURE: Arc<WebFontMeasure> = { Arc::new(WebFontMeasure) };
}
pub struct WebRenderer {
}
pub struct WebRenderer {}
impl obsolete::Renderer for WebRenderer {
fn render_text(
......@@ -220,17 +311,21 @@ impl obsolete::Renderer for WebRenderer {
font: &Font,
) {
if color.r() == 0 && color.g() == 0 && color.b() == 0 && color.a() == 0 {
return;
}
let canvas: CanvasElement = document().query_selector( "canvas" ).unwrap().unwrap().try_into().unwrap();
return;
}
let canvas: CanvasElement = document().query_selector("canvas").unwrap().unwrap().try_into().unwrap();
let context: CanvasRenderingContext2d = canvas.get_context().unwrap();
js! {
console.log(@{&font.family})
}
context.save();
context.begin_path();
context.rect(global_position.x, global_position.y, parent_bounds.width, parent_bounds.height);
context.clip(FillRule::EvenOdd);
context.set_font(&format!("{}px {}", font_size, font.family));
context.set_fill_style_color(&color.to_string());
context.fill_text(text, global_position.x + bounds.x, global_position.y + bounds.y + font_size as f64 - 2.0, Some(parent_bounds.width));
context.set_text_baseline(web::TextBaseline::Top);
context.fill_text(text, global_position.x + bounds.x, global_position.y + bounds.y , None);
context.close_path();
context.restore();
}
}
......
This diff is collapsed.
......@@ -91,7 +91,7 @@ fn main() {
.position((100.0, 100.0))
.size(420.0, 730.0)
.theme(ThemeValue::create()
.extension_path("examples/res/grid.css")
.extension_css(include_str!("res/grid.css"))
.build())
.child(MainView::create().build(ctx))
.build(ctx)
......
container.header {
background: #444e55;
}
container.content {
background: #3b434a;
}
text-box {
background: transparent;
border-width: 0;
color: #9dafbf;
font-size: 16;
}
#input {
font-size: 16;
}
text-block {
font-size: 42;
color: #dfebf5;
}
#input {
background: transparent;
}
container {
background: "green";
}
button {
border-radius: 1;
font-size: 20;
}
\ No newline at end of file
container.header {
background: #ffffff;
}
container.content {
background: #fafafa;
}
text-box {
color: #4d4c4c;
}
text-block {
color: #4d4c4c;
}
\ No newline at end of file
......@@ -62,7 +62,7 @@ impl KeyboardState {
#[cfg(test)]
mod tests {
use super::*;
#[test]
/// A quick test to ensure that the items are properly set.
fn basic_test() {
......
......@@ -4,13 +4,12 @@
pub use dces::prelude::*;
pub use dces::prelude::*;
pub use shell::initialize;
pub use orbtk_css_engine::prelude as css_engine;
pub use orbtk_shell::prelude as shell;
pub use orbtk_theme::prelude as theme;
pub use orbtk_tree::prelude as tree;
pub use orbtk_utils::prelude as utils;
pub use shell::initialize;
pub use crate::application::*;
pub use crate::event::*;
......
use std::fmt;
use orbgl_api::Color;
use orbgl_api::Image as OrbImage;
#[cfg(not(target_arch = "wasm32"))]
use orbclient::Renderer;
use orbgl_api::Color;
use orbgl_api::Image as OrbImage;
use crate::prelude::*;
......@@ -12,15 +11,15 @@ use crate::prelude::*;
pub struct InnerImage(pub OrbImage);
impl Default for InnerImage {
#[cfg(not(target_arch = "wasm32"))]
#[cfg(not(target_arch = "wasm32"))]
fn default() -> Self {
InnerImage(OrbImage::new(0, 0))
InnerImage(OrbImage::new(0, 0))
}
#[cfg(target_arch = "wasm32")]
fn default() -> Self {
InnerImage(OrbImage::new())
}
#[cfg(target_arch = "wasm32")]
fn default() -> Self {
InnerImage(OrbImage::new())
}
}
impl fmt::Debug for InnerImage {
......@@ -57,7 +56,7 @@ pub trait ImageExt {
/// Gets the height.
fn height(&self) -> u32;
#[cfg(not(target_arch = "wasm32"))]
#[cfg(not(target_arch = "wasm32"))]
/// Gets the color data.
fn data(&self) -> &[Color];
}
......@@ -95,7 +94,7 @@ impl ImageExt for Image {
// --- Conversions ---
impl From<&str> for Image {
#[cfg(not(target_arch = "wasm32"))]
#[cfg(not(target_arch = "wasm32"))]
fn from(s: &str) -> Image {
Image::from(InnerImage::from(OrbImage::from_path(s).unwrap()))
}
......
use orbgl_api::{Canvas, Color};
use orbgl_api::Canvas;
use crate::prelude::*;
......@@ -16,10 +16,7 @@ impl RectangleRenderObject {
brush: Brush,
) {
match brush {
Brush::SolidColor(color) => {
if color.r() == 0 && color.g() == 0 && color.b() == 0 && color.a() == 0 {
return;
}
Brush::SolidColor(color) => {
canvas.set_fill_style(color)
}
_ => {} // todo: gradient
......@@ -98,11 +95,9 @@ impl RectangleRenderObject {
270.0 * degrees,
);
match brush {
match brush {
Brush::SolidColor(color) => {
if color.r() == 0 && color.g() == 0 && color.b() == 0 && color.a() == 0 {
return;
}
canvas.set_fill_style(color)
}
_ => {} // todo: gradient
......
......@@ -47,11 +47,11 @@ impl System<Tree> for InitSystem {
let debug = false;
if debug {
println!("\n------ Widget tree ------\n");
crate::shell::log("\n------ Widget tree ------\n".to_string());
print_tree(tree.root, 0, tree, ecm);
println!("\n------ Widget tree ------\n");
crate::shell::log("\n------ Widget tree ------\n".to_string());
}
let window_shell = &mut self.shell.borrow_mut();
......@@ -82,7 +82,7 @@ fn print_tree(entity: Entity, depth: usize, tree: &Tree, ecm: &mut EntityCompone
let name = Name::get(entity, ecm);
let selector = Selector::get(entity, ecm);
println!("{}{} (entity: {}{})", "| ".repeat(depth), name, entity.0, selector);
crate::shell::log(format!("{}{} (entity: {}{})", "| ".repeat(depth), name, entity.0, selector));
for child in tree.children.get(&entity).unwrap() {
print_tree(*child, depth + 1, tree, ecm);
......
......@@ -23,7 +23,7 @@ impl System<Tree> for LayoutSystem {
}
// if self.debug_flag.get() {
// println!("\n------ Start layout update ------\n");
// shell::log("\n------ Start layout update ------\n".to_string());
// }
let mut window_size = (0.0, 0.0);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment