Commit be574696 authored by Florian Blasius's avatar Florian Blasius 🤘
Browse files

[feature] finish dragging example

parent 9c0d2939
Pipeline #2385 passed with stage
in 2 minutes and 50 seconds
......@@ -4,7 +4,7 @@ version = "0.1.0"
authors = ["Florian Blasius <flovanpt@posteo.de>"]
edition = "2018"
[target.'cfg(target_arch = "wasm32")'.dependencies]
[target.wasm32-unknown-unknown.dependencies]
stdweb = "0.4.12"
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
......
......@@ -28,7 +28,6 @@ name = "dragging"
version = "0.1.0"
dependencies = [
"orbrender 0.1.0",
"stdweb 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
]
......@@ -37,7 +36,6 @@ name = "drawing"
version = "0.1.0"
dependencies = [
"orbrender 0.1.0",
"stdweb 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
]
......
......@@ -5,6 +5,5 @@ authors = ["Florian Blasius <flovanpt@posteo.de>"]
edition = "2018"
[dependencies]
stdweb = "0.4.12"
time = "0.1.41"
orbrender = { path = "../.." }
\ No newline at end of file
use orbrender;
use orbrender::backend::Runner;
use orbrender::prelude::*;
use stdweb;
use stdweb::{_js_impl, js};
use time::PreciseTime;
use std::sync::atomic::{self, AtomicBool};
......@@ -13,36 +11,41 @@ struct State {
pub mouse_position: (f32, f32),
pub rect: (f32, f32, f32, f32),
pub rect_pressed: bool,
pub rect_index: usize,
}
fn main() {
orbrender::initialize();
let mut window = WindowBuilder::new()
.with_title("OrbRender - dragging example")
.with_background(Color::rgb(59, 67, 74))
.with_size(Size::new(800.0, 600.0))
.build();
window.push_text(
Text::default()
.with_text("Drag the rectangle")
.with_position(Point::new(10.0, 20.0))
.with_foreground(Color::rgb(0, 0, 0))
.with_font(FontConfig::default().with_family("Roboto").with_size(14.0)),
);
let mut example_state = State {
mouse_delta: (0.0, 0.0),
mouse_position: (0.0, 0.0),
rect: (10.0, 40.0, 40.0, 40.0),
rect_index: 0,
rect_pressed: false,
};
window.push_rectangle(
example_state.rect_index = window.push_rectangle(
Rectangle::default()
.with_size(Size::new(example_state.rect.2, example_state.rect.3))
.with_position(Point::new(example_state.rect.0, example_state.rect.1))
.with_background(Color::rgb(255, 0, 0)),
);
window.push_text(
Text::default()
.with_text("Drag the rectangle")
.with_position(Point::new(10.0, 20.0))
.with_foreground(Color::rgb(204, 222, 237))
.with_font(FontConfig::default().with_family("Roboto").with_size(14.0)),
);
let update = Arc::new(AtomicBool::new(true));
Runner::new(Box::new(move || {
......@@ -65,16 +68,9 @@ fn main() {
&& pos.1 <= rect.1 + rect.3
{
example_state.rect_pressed = true;
js! {
console.log("Click in");
}
} else {
example_state.rect_pressed = false;
js! {
console.log("Click out");
}
example_state.mouse_delta = (0.0, 0.0);
}
} else if button == MouseButton::Left && state == ElementState::Released {
example_state.rect_pressed = false;
......@@ -84,6 +80,30 @@ fn main() {
let mouse_pos = &example_state.mouse_position;
example_state.mouse_delta = (mouse_pos.0 - point.x, mouse_pos.1 - point.y);
example_state.mouse_position = (point.x, point.y);
if example_state.rect_pressed {
example_state.rect.0 -= example_state.mouse_delta.0;
example_state.rect.1 -= example_state.mouse_delta.1;
let window_size = window.size();
if example_state.rect.0 + example_state.rect.2 > window_size.width {
example_state.rect.0 = window_size.width - example_state.rect.2;
} else if example_state.rect.0 < 0.0 {
example_state.rect.0 = 0.0;
}
if example_state.rect.1 + example_state.rect.3 > window_size.height {
example_state.rect.1 = window_size.height - example_state.rect.3;
} else if example_state.rect.1 < 0.0 {
example_state.rect.1 = 0.0;
}
if let Some(rect) = window.get_mut_rectangle(example_state.rect_index) {
rect.position.x = example_state.rect.0;
rect.position.y = example_state.rect.1;
update.store(true, atomic::Ordering::Release);
}
}
}
_ => {}
},
......
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>OrbRender - drawing example</title>
<style>
* {
padding: 0;
margin: 0;
}
canvas {
display: block;
margin: 0;
}
</style>
</head>
<body>
<canvas id="canvas" width="800", height="600"></canvas>
<script src="dragging.js"></script>
</body>
</html>
\ No newline at end of file
......@@ -5,6 +5,5 @@ authors = ["Florian Blasius <flovanpt@posteo.de>"]
edition = "2018"
[dependencies]
stdweb = "0.4.12"
time = "0.1.41"
orbrender = { path = "../.." }
\ No newline at end of file
use orbrender;
use orbrender::backend::Runner;
use orbrender::prelude::*;
use stdweb;
use stdweb::{
_js_impl, js,
};
//use stdweb;
//use stdweb::{
// _js_impl, js,
//};
use time::PreciseTime;
use std::sync::atomic::{self, AtomicBool};
use std::sync::Arc;
fn main() {
orbrender::initialize();
let mut window = WindowBuilder::new()
.with_title("OrbRender - drawing example")
.with_background(Color::rgb(59, 67, 74))
.with_size(Size::new(800.0, 600.0))
.build();
......@@ -20,15 +22,15 @@ fn main() {
Rectangle::default()
.with_size(Size::new(40.0, 40.0))
.with_position(Point::new(10.0, 10.0))
.with_background(Color::rgb(100, 100, 100)),
.with_background(Color::rgb(100, 123, 145)),
);
window.push_rectangle(
Rectangle::default()
.with_size(Size::new(40.0, 40.0))
.with_position(Point::new(60.0, 10.0))
.with_background(Color::rgb(100, 100, 100))
.with_border_color(Color::rgb(64, 64, 64))
.with_background(Color::rgb(100, 123, 145))
.with_border_color(Color::rgb(173, 179, 184))
.with_border_thickness(
Thickness::default()
.with_left_right(4.0)
......@@ -42,7 +44,7 @@ fn main() {
Rectangle::default()
.with_size(Size::new(20.0, 20.0))
.with_position(Point::new(120.0, 20.0))
.with_background(Color::rgb(255, 0, 0)),
.with_background(Color::rgb(248, 222, 97)),
10,
);
......@@ -50,14 +52,14 @@ fn main() {
Rectangle::default()
.with_size(Size::new(40.0, 40.0))
.with_position(Point::new(110.0, 10.0))
.with_background(Color::rgb(100, 100, 100)),
.with_background(Color::rgb(100, 123, 145)),
);
window.push_text(
Text::default()
.with_text("OrbRender")
.with_position(Point::new(10.0, 80.0))
.with_foreground(Color::rgb(100, 100, 100))
.with_foreground(Color::rgb(204, 222, 237))
.with_font(FontConfig::default().with_family("Roboto").with_size(22.0)),
);
......
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>OrbRender - drawing example</title>
<style>
* {
padding: 0;
margin: 0;
}
canvas {
display: block;
margin: 0;
}
</style>
</head>
<body>
<canvas id="canvas" width="800", height="600"></canvas>
<script src="drawing.js"></script>
</body>
</html>
\ No newline at end of file
......@@ -4,9 +4,9 @@ use rust_cairo::*;
use std::ffi::CString;
use crate::{
events::{Event, SystemEvent},
events::{Event, SystemEvent, MouseButton, MouseEvent, ElementState},
render_objects::{Image, Rectangle, RenderStorage, Text},
structs::Color,
structs::{Color, Size, Point},
traits::Window,
window::WindowBuilder,
};
......@@ -81,9 +81,14 @@ pub struct CairoWindow {
render_storage: RenderStorage,
background: Color,
cairo_context: *mut _cairo,
left_pressed: bool,
}
impl Window for CairoWindow {
fn size(&self) -> Size {
Size::new(self.inner_window.width() as f32, self.inner_window.height() as f32)
}
fn render(&mut self) {
// window background
self.inner_window.set(orbclient::Color::rgba(
......@@ -260,7 +265,15 @@ impl Window for CairoWindow {
self.render_storage.push_with_z(image, z)
}
fn remove_render_objet(&mut self, index: usize) {
fn get_rectangle(&mut self, index: usize) -> Option<&Rectangle> {
self.render_storage.get::<Rectangle>(index)
}
fn get_mut_rectangle(&mut self, index: usize) -> Option<&mut Rectangle> {
self.render_storage.get_mut::<Rectangle>(index)
}
fn remove_render_object(&mut self, index: usize) {
self.render_storage.remove(index);
}
......@@ -275,6 +288,27 @@ impl Window for CairoWindow {
match event.to_option() {
orbclient::EventOption::Quit(_) => {
events.push(Event::System(SystemEvent::Quit));
},
orbclient::EventOption::Button(button) => {
let state = {
if button.left {
ElementState::Pressed
} else {
ElementState::Released
}
};
events.push(Event::Mouse(MouseEvent::Button {
button: MouseButton::Left,
state,
}));
},
orbclient::EventOption::Mouse(mouse) => {
events.push(Event::Mouse(MouseEvent::Move(Point::new(
mouse.x as f32,
mouse.y as f32,
))));
}
_ => {}
}
......@@ -327,6 +361,7 @@ impl From<WindowBuilder> for CairoWindow {
render_storage: RenderStorage::default(),
background: builder.background,
cairo_context: cr,
left_pressed: false
}
}
}
pub fn initialize() {}
\ No newline at end of file
pub fn initialize() {
stdweb::initialize();
}
\ No newline at end of file
pub use self::runner::Runner;
pub use self::initialize::initialize;
#[cfg(target_arch = "wasm32")]
pub use self::stdweb::{build_window, initialize};
pub use self::stdweb::{build_window};
#[cfg(target_arch = "wasm32")]
mod stdweb;
#[cfg(target_arch = "wasm32")]
#[path = "initialize/stdweb.rs"]
mod initialize;
#[cfg(target_arch = "wasm32")]
#[path = "runner/stdweb.rs"]
mod runner;
#[cfg(not(target_arch = "wasm32"))]
pub use self::cairo::{build_window, initialize};
pub use self::cairo::{build_window};
#[cfg(not(target_arch = "wasm32"))]
mod cairo;
......@@ -20,6 +25,10 @@ mod cairo;
#[path = "runner/default.rs"]
mod runner;
#[cfg(not(target_arch = "wasm32"))]
#[path = "initialize/default.rs"]
mod initialize;
////
//#[cfg(not(target_arch = "wasm32"))]
......
......@@ -133,7 +133,7 @@ impl Window for OrbClientWindow {
self.render_storage.push_with_z(image, z)
}
fn remove_render_objet(&mut self, index: usize) {
fn remove_render_object(&mut self, index: usize) {
self.render_storage.remove(index);
}
......
......@@ -11,28 +11,14 @@ use stdweb::{
},
};
// Shamelessly stolen from webplatform's TodoMVC example.
macro_rules! enclose {
( ($( $x:ident ),*) $y:expr ) => {
{
$(let $x = $x.clone();)*
$y
}
};
}
use crate::{
events::{ElementState, Event, MouseButton, MouseEvent, SystemEvent},
render_objects::{Image, Rectangle, RenderStorage, Text},
structs::{Color, Point},
render_objects::{Image, Rectangle, RenderObject, RenderStorage, Text},
structs::{Color, Point, Size},
traits::Window,
window::WindowBuilder,
};
pub fn initialize() {
stdweb::initialize();
}
fn get_mouse_button(button: web::event::MouseButton) -> MouseButton {
match button {
web::event::MouseButton::Left => MouseButton::Left,
......@@ -86,6 +72,10 @@ pub struct StdWebWindow {
//}
impl Window for StdWebWindow {
fn size(&self) -> Size {
Size::new(self.canvas.width() as f32, self.canvas.height() as f32)
}
fn render(&mut self) {
// window background
self.context
......@@ -202,7 +192,15 @@ impl Window for StdWebWindow {
self.render_storage.push_with_z(image, z)
}
fn remove_render_objet(&mut self, index: usize) {
fn get_rectangle(&mut self, index: usize) -> Option<&Rectangle> {
self.render_storage.get::<Rectangle>(index)
}
fn get_mut_rectangle(&mut self, index: usize) -> Option<&mut Rectangle> {
self.render_storage.get_mut::<Rectangle>(index)
}
fn remove_render_object(&mut self, index: usize) {
self.render_storage.remove(index);
}
......@@ -220,22 +218,61 @@ impl Window for StdWebWindow {
impl From<WindowBuilder> for StdWebWindow {
fn from(builder: WindowBuilder) -> StdWebWindow {
let canvas: CanvasElement = document()
.query_selector("#canvas")
.unwrap()
.create_element("canvas")
.unwrap()
.try_into()
.unwrap();
canvas.set_width(builder.size.width as u32);
canvas.set_height(builder.size.height as u32);
js! {
document.body.style.padding = 0;
document.body.style.margin = 0;
@{&canvas}.style.display = "block";
@{&canvas}.style.margin = "0";
}
document().body().unwrap().append_child(&canvas);
let events = Rc::new(RefCell::new(vec![]));
document().set_title(&builder.title[..]);
let context: CanvasRenderingContext2d = canvas.get_context().unwrap();
canvas.set_width(builder.size.width as u32);
canvas.set_height(builder.size.height as u32);
let devicePixelRatio = window().device_pixel_ratio();
let backingStoreRatio = js! {
var context = @{&context};
return context.webkitBackingStorePixelRatio ||
context.mozBackingStorePixelRatio ||
context.msBackingStorePixelRatio ||
context.oBackingStorePixelRatio ||
context.backingStorePixelRatio || 1;
};
let ratio: f64 = js! {
return @{&devicePixelRatio} / @{&backingStoreRatio};
}.try_into().unwrap();
if devicePixelRatio != backingStoreRatio {
let old_width = canvas.width();
let old_height = canvas.height();
canvas.set_width((old_width as f64 * ratio) as u32);
canvas.set_height((old_height as f64 * ratio) as u32);
js! {
@{&canvas}.style.width = @{&old_width} + "px";
@{&canvas}.style.height = @{&old_height} + "px";
}
context.scale(ratio, ratio);
}
let events_c = events.clone();
canvas.add_event_listener(move |e: event::MouseDownEvent| {
window().add_event_listener(move |e: event::MouseDownEvent| {
events_c.borrow_mut().push(Event::Mouse(MouseEvent::Button {
button: get_mouse_button(e.button()),
state: ElementState::Pressed,
......@@ -243,7 +280,7 @@ impl From<WindowBuilder> for StdWebWindow {
});
let events_c = events.clone();
canvas.add_event_listener(move |e: event::MouseUpEvent| {
window().add_event_listener(move |e: event::MouseUpEvent| {
events_c.borrow_mut().push(Event::Mouse(MouseEvent::Button {
button: get_mouse_button(e.button()),
state: ElementState::Released,
......
......@@ -261,7 +261,7 @@ impl Window for WebRenderWindow {
self.render_storage.push_with_z(image, z)
}
fn remove_render_objet(&mut self, index: usize) {
fn remove_render_object(&mut self, index: usize) {
self.render_storage.remove(index);
}
......
pub use self::backend::initialize;
pub mod backend;
pub mod enums;
pub mod events;
......
pub use crate::{
initialize,
enums::WindowMode,
events::{Event, SystemEvent, MouseButton, MouseEvent, ElementState},
render_objects::{Rectangle, Text, Image},
......
use std::any::Any;
use std::any::{Any, TypeId};
use std::collections::{btree_map::Iter, btree_set, BTreeMap, BTreeSet};
pub use self::image::Image;
......@@ -40,6 +40,28 @@ impl RenderStorage {
self.render_object_counter - 1
}
/// Returns a reference to a render object depending on the type of index.
pub fn get<R: RenderObject>(&mut self, index: usize) -> Option<&R> {
if let Some(render_object) = self.render_objects.get_mut(&index) {
if let Some(render_object) = render_object.downcast_ref::<R>() {
return Some(render_object);
}
}
None
}
/// Returns a mutable reference to a render object depending on the type of index.
pub fn get_mut<R: RenderObject>(&mut self, index: usize) -> Option<&mut R> {
if let Some(render_object) = self.render_objects.get_mut(&index) {
if let Some(render_object) = render_object.downcast_mut::<R>() {
return Some(render_object);
}
}
None
}
/// Removes the render object with the given `index` from the storage.
pub fn remove(&mut self, index: usize) {
self.render_objects.remove(&index);
......
use crate::{
events::Event,
render_objects::{Rectangle, Text, Image},
structs::Color,
render_objects::{Rectangle, RenderObject, Text, Image},
structs::{Color, Size},
};
pub trait Window {
/// Returns the size of the window.
fn size(&self) -> Size;
/// Renders all render objects of the window.
fn render(&mut self);