Commit ae764c3d authored by Florian Blasius's avatar Florian Blasius 🤘

Merge branch '166-window' into 'master'

Resolve "Window"

See merge request redox-os/orbtk!109
parents 4f23cda4 0a8a2dd8
......@@ -7,7 +7,7 @@
{
"type": "lldb",
"request": "launch",
"name": "OrbTk: Widgets",
"name": "Widgets",
"program": "${workspaceFolder}/target/debug/examples/widgets",
"cwd": "${workspaceFolder}",
"preLaunchTask": "build",
......@@ -18,7 +18,18 @@
{
"type": "lldb",
"request": "launch",
"name": "OrbTk: Canvas",
"name": "Widgets debug",
"program": "${workspaceFolder}/target/debug/examples/widgets",
"cwd": "${workspaceFolder}",
"preLaunchTask": "build debug",
"sourceLanguages": [
"rust",
]
},
{
"type": "lldb",
"request": "launch",
"name": "Canvas",
"program": "${workspaceFolder}/target/debug/examples/canvas",
"cwd": "${workspaceFolder}",
"preLaunchTask": "build",
......@@ -29,7 +40,7 @@
{
"type": "lldb",
"request": "launch",
"name": "OrbTk: Image",
"name": "Image",
"program": "${workspaceFolder}/target/debug/examples/image",
"cwd": "${workspaceFolder}",
"preLaunchTask": "build",
......@@ -40,7 +51,7 @@
{
"type": "lldb",
"request": "launch",
"name": "OrbTk: Light Theme",
"name": "Light Theme",
"program": "${workspaceFolder}/target/debug/examples/light-theme",
"cwd": "${workspaceFolder}",
"preLaunchTask": "build",
......@@ -51,7 +62,7 @@
{
"type": "lldb",
"request": "launch",
"name": "OrbTk: Messages",
"name": "Messages",
"program": "${workspaceFolder}/target/debug/examples/messages",
"cwd": "${workspaceFolder}",
"preLaunchTask": "build",
......@@ -62,7 +73,7 @@
{
"type": "lldb",
"request": "launch",
"name": "OrbTk: Grid",
"name": "Grid",
"program": "${workspaceFolder}/target/debug/examples/grid",
"cwd": "${workspaceFolder}",
"preLaunchTask": "build",
......@@ -73,7 +84,7 @@
{
"type": "lldb",
"request": "launch",
"name": "OrbTk: Minimal",
"name": "Minimal",
"program": "${workspaceFolder}/target/debug/examples/minimal",
"cwd": "${workspaceFolder}",
"preLaunchTask": "build",
......@@ -84,7 +95,7 @@
{
"type": "lldb",
"request": "launch",
"name": "OrbTk: Test",
"name": "Test",
"cargo": {
"args": [
"test",
......
......@@ -19,6 +19,25 @@
"kind": "build",
"isDefault": true
}
},
{
"label": "build debug",
"command": "cargo",
"type": "shell",
"args": [
"build",
"--examples=minimal",
"--features",
"debug"
],
"presentation": {
"reveal": "always",
"panel": "new"
},
"group": {
"kind": "build",
"isDefault": true
}
}
]
}
\ No newline at end of file
......@@ -39,6 +39,9 @@ dces = { git = "https://gitlab.redox-os.org/redox-os/dces-rust.git" }
orbgl_api = { git = "https://gitlab.redox-os.org/redox-os/orbgl.git" }
# orbgl = { path = "../orbgl/orbgl" }
[features]
debug = []
[workspace]
members = [
"crates/css-engine",
......
......@@ -55,17 +55,19 @@ If you want to use OrbTk with cairo (recommanded) you have to install cairo grap
## Minimal Example
```rust
use orbtk::*;
use orbtk::prelude::*;
fn main() {
let mut application = Application::default();
application
.create_window()
.bounds(Bounds::new(100.0, 100.0, 420.0, 730.0))
.title("OrbTk - minimal example")
.debug_flag(false)
.build(TextBlock::create().text("OrbTk"));
application.run();
Application::new()
.window(|ctx| {
Window::create()
.title("OrbTk - minimal example")
.position((100.0, 100.0))
.size(420.0, 730.0)
.child(TextBlock::create().text("OrbTk").build(ctx))
.build(ctx)
})
.run();
}
```
......
......@@ -80,13 +80,12 @@ impl ThemeBuilder {
}
/// `Theme` is the representation of a css styling.
#[derive(Debug, Clone)]
#[derive(Clone, PartialEq, Default, Debug)]
pub struct Theme {
parent: Option<Arc<Theme>>,
rules: Vec<Rule>,
}
impl Theme {
/// Creates a new `ThemeBuilder` object with default theme as base.
pub fn create() -> ThemeBuilder {
......@@ -191,20 +190,20 @@ impl Theme {
}
}
#[derive(Clone, Debug)]
#[derive(Clone, Default, PartialEq, Debug)]
pub struct Rule {
pub selectors: Vec<Selector>,
pub declarations: Vec<Declaration>,
}
#[derive(Clone, Debug)]
#[derive(Clone, Default, PartialEq, Debug)]
pub struct Declaration {
pub property: String,
pub value: Value,
pub important: bool,
}
#[derive(Clone, Debug)]
#[derive(Clone, PartialEq, Debug)]
pub enum Value {
UInt(u32),
Float(f32),
......@@ -212,6 +211,12 @@ pub enum Value {
Str(String),
}
impl Default for Value {
fn default() -> Self {
Value::UInt(0)
}
}
impl Value {
pub fn uint(&self) -> Option<u32> {
match *self {
......
......@@ -2,3 +2,4 @@ pub static LINK_WATER_COLOR: &'static str = "#dfebf5";
pub static LYNCH_COLOR: &'static str = "#647b91";
pub static BOMBAY_COLOR: &'static str = "#adb3B8";
pub static SLATE_GRAY_COLOR: &'static str = "#6c7a90";
pub static BRIGHT_GRAY_COLOR: &'static str = "#3b434a";
......@@ -8,6 +8,10 @@
icon-family: "Material Icons Regular";
}
window {
background: #3b434a;
}
.body {
color: #dfebf5;
font-size: 16;
......
......@@ -10,6 +10,10 @@
color: #3b434a;
}
window {
background: #fafafa;
}
button, toggle-button {
/* min-width: 60; */
/* height: 40; */
......
......@@ -266,7 +266,7 @@ mod tests {
tree.append_child(0, 1).unwrap();
tree.append_child(0, 2).unwrap();
tree.append_child(1, 3).unwrap();
tree.append_child(1, 4).unwrap();
......@@ -275,12 +275,12 @@ mod tests {
let mut iterator = tree.into_iter();
assert_eq!(0, iterator.next().unwrap());
assert_eq!(1, iterator.next().unwrap());
assert_eq!(3, iterator.next().unwrap());
assert_eq!(4, iterator.next().unwrap());
assert_eq!(2, iterator.next().unwrap());
assert_eq!(5, iterator.next().unwrap());
assert_eq!(6, iterator.next().unwrap());
assert_eq!(0, iterator.next().unwrap());
assert_eq!(1, iterator.next().unwrap());
assert_eq!(3, iterator.next().unwrap());
assert_eq!(4, iterator.next().unwrap());
assert_eq!(2, iterator.next().unwrap());
assert_eq!(5, iterator.next().unwrap());
assert_eq!(6, iterator.next().unwrap());
}
}
......@@ -117,7 +117,7 @@ pub trait Bordered {
#[cfg(test)]
mod tests {
use crate::prelude::*;
#[test]
fn test_brush() {
let brush = Brush::from("#000000");
......
// todo: documentation
#[derive(Copy, Clone, Default)]
#[derive(Copy, Clone, Default, Debug, PartialEq)]
pub struct Point {
pub x: f64,
pub y: f64,
......
......@@ -129,7 +129,7 @@ pub trait Spacer {
#[cfg(test)]
mod tests {
use crate::prelude::*;
#[test]
fn test_new() {
let rect = Thickness::new(5.0, 10.0, 20.0, 30.0);
......
......@@ -4,18 +4,18 @@ use stdweb::web::event::*;
pub enum Mouse {
Up(MouseUpEvent),
Down(MouseDownEvent),
Move(MouseMoveEvent)
Move(MouseMoveEvent),
}
/// Defines web key events.
pub enum Key {
Up(KeyUpEvent),
Down(KeyDownEvent)
Down(KeyDownEvent),
}
/// Defines a web window event.
pub enum Event {
Mouse(Mouse),
Key(Key)
Key(Key),
}
......@@ -80,18 +80,19 @@ impl Template for MainView {
}
}
fn main() {
let mut application = Application::default();
application
.create_window()
.bounds((100.0, 100.0, 420.0, 730.0))
.title("OrbTk - grid example")
.theme(
Theme::create()
.extension_path("examples/res/grid.css")
.build(),
)
.resizable(true)
.build(MainView::create());
application.run();
}
Application::new()
.window(|ctx| {
Window::create()
.title("OrbTk - grid example")
.position((100.0, 100.0))
.size(420.0, 730.0)
.theme(ThemeValue::create()
.extension_path("examples/res/grid.css")
.build())
.child(MainView::create().build(ctx))
.build(ctx)
})
.run();
}
\ No newline at end of file
use orbtk::prelude::*;
fn main() {
let mut application = Application::default();
application
.create_window()
.bounds((100.0, 100.0, 800.0, 420.0))
.title("OrbTk - minimal example")
.debug_flag(false)
.build(ImageWidget::create().image("res/orbtk-space.png"));
application.run();
Application::new()
.window(|ctx| {
Window::create()
.title("OrbTk - minimal example")
.position((100.0, 100.0))
.size(800.0, 420.0)
.child(ImageWidget::create().image("res/orbtk-space.png").build(ctx))
.build(ctx)
})
.run();
}
\ No newline at end of file
......@@ -128,14 +128,15 @@ impl Template for MainView {
}
fn main() {
let mut application = Application::default();
application
.create_window()
.bounds((100.0, 100.0, 420.0, 730.0))
.title("OrbTk - light theme example")
.debug_flag(false)
.theme(light_theme())
.build(MainView::create());
application.run();
Application::new()
.window(|ctx| {
Window::create()
.title("OrbTk - light theme example")
.position((100.0, 100.0))
.size(420.0, 730.0)
.theme(light_theme())
.child(MainView::create().build(ctx))
.build(ctx)
})
.run();
}
use orbtk::prelude::*;
fn main() {
let mut application = Application::default();
application
.create_window()
.bounds((100.0, 100.0, 420.0, 730.0))
.title("OrbTk - minimal example")
.debug_flag(false)
.build(TextBlock::create().text("OrbTk"));
application.run();
Application::new()
.window(|ctx| {
Window::create()
.title("OrbTk - minimal example")
.position((100.0, 100.0))
.size(420.0, 730.0)
.child(TextBlock::create().text("OrbTk").build(ctx))
.build(ctx)
})
.run();
}
......@@ -73,7 +73,8 @@ impl Template for MainView {
.on_click(move |_| {
state.increment();
true
}).build(context)
})
.build(context),
)
.child(
Button::create()
......@@ -82,27 +83,31 @@ impl Template for MainView {
.margin((0.0, 8.0, 0.0, 0.0))
.icon(material_font_icons::CHECK_FONT_ICON)
.attach(GridColumn(0))
.attach(GridRow(2)).build(context)
.attach(GridRow(2))
.build(context),
)
.child(
ToggleButton::create()
.text("ToggleButton")
.margin((0.0, 8.0, 0.0, 0.0))
.attach(GridColumn(0))
.attach(GridRow(3)).build(context)
.attach(GridRow(3))
.build(context),
)
.child(
CheckBox::create()
.text("CheckBox")
.margin((0.0, 8.0, 0.0, 0.0))
.attach(GridColumn(0))
.attach(GridRow(4)).build(context)
.attach(GridRow(4))
.build(context),
)
.child(
Switch::create()
.margin((0.0, 8.0, 0.0, 0.0))
.attach(GridColumn(0))
.attach(GridRow(5)).build(context)
.attach(GridRow(5))
.build(context),
)
// Column 2
.child(create_header(context, "Text", 2, 0))
......@@ -112,7 +117,8 @@ impl Template for MainView {
.text(id)
.margin((0.0, 8.0, 0.0, 0.0))
.attach(GridColumn(2))
.attach(GridRow(1)).build(context)
.attach(GridRow(1))
.build(context),
)
.child(
TextBox::create()
......@@ -120,21 +126,23 @@ impl Template for MainView {
.text("")
.margin((0.0, 8.0, 0.0, 0.0))
.attach(GridColumn(2))
.attach(GridRow(2)).build(context)
.attach(GridRow(2))
.build(context),
)
.build(context)
.build(context),
)
}
}
fn main() {
let mut application = Application::default();
application
.create_window()
.bounds((100.0, 100.0, 420.0, 730.0))
.title("OrbTk - widgets example")
.debug_flag(false)
.build(MainView::create());
application.run();
Application::new()
.window(|ctx| {
Window::create()
.title("OrbTk - widgets example")
.position((100.0, 100.0))
.size(420.0, 730.0)
.child(MainView::create().build(ctx))
.build(ctx)
})
.run();
}
//! This module contains the base elements of an OrbTk application (Application, WindowBuilder and Window).
use std::{
cell::{Cell, RefCell},
collections::BTreeMap,
rc::Rc,
};
use dces::prelude::{Entity, World};
use crate::prelude::*;
use crate::backend::*;
use crate::systems::*;
pub use self::global::*;
pub use self::window::*;
......@@ -8,10 +18,10 @@ pub use self::window::*;
mod global;
mod window;
#[derive(Default)]
/// The `Application` represents the entry point of an OrbTk based application.
#[derive(Default)]
pub struct Application {
windows: Vec<Window>,
windows: Vec<WindowShell>,
}
impl Application {
......@@ -20,16 +30,112 @@ impl Application {
Self::default()
}
/// Returns a `WindowBuilder.
pub fn create_window(&mut self) -> WindowBuilder<'_> {
WindowBuilder {
application: self,
bounds: Bounds::default(),
title: String::from(""),
theme: default_theme(),
resizable: false,
debug_flag: false,
pub fn window<F: Fn(&mut BuildContext) -> Entity + 'static>(mut self, create_fn: F) -> Self {
let mut world = World::from_container(Tree::default());
let render_objects = Rc::new(RefCell::new(BTreeMap::new()));
let layouts = Rc::new(RefCell::new(BTreeMap::new()));
let handlers = Rc::new(RefCell::new(BTreeMap::new()));
let states = Rc::new(RefCell::new(BTreeMap::new()));
let update = Rc::new(Cell::new(true));
let running = Rc::new(Cell::new(true));
let mut context = BuildContext::new(
&mut world,
render_objects.clone(),
layouts.clone(),
handlers.clone(),
states.clone(),
);
let window = create_fn(&mut context);
{
let tree: &mut Tree = world.entity_container();
tree.root = window;
}
let title = world.entity_component_manager().borrow_component::<Title>(window).unwrap().clone();
let resizeable = world.entity_component_manager().borrow_component::<Resizeable>(window).unwrap().clone();
let position = world.entity_component_manager().borrow_component::<Pos>(window).unwrap().clone();
let constraint = world.entity_component_manager().borrow_component::<Constraint>(window).unwrap().clone();
world.entity_component_manager().register_component(window, Global::default());
world.entity_component_manager().register_component(window, Global::default());
world.entity_component_manager().register_component(window, Bounds::from((0.0, 0.0, constraint.width(), constraint.height())));
let (mut runner, backend) =
target_backend(&title.0, Bounds::from((position.0.x, position.0.y, constraint.width(), constraint.height())), false);
world.register_init_system(InitSystem {
backend: backend.clone(),
states: states.clone(),
});
world
.create_system(EventSystem {
backend: backend.clone(),
handlers: handlers.clone(),
update: update.clone(),
running: running.clone(),
})
.with_priority(0)
.build();
world
.create_system(StateSystem {
backend: backend.clone(),
states: states.clone(),
update: update.clone(),
running: running.clone(),
})
.with_priority(1)
.build();
world
.create_system(LayoutSystem {
backend: backend.clone(),
layouts: layouts.clone(),
update: update.clone(),
running: running.clone(),
})
.with_priority(2)
.build();
world
.create_system(PostLayoutStateSystem {
backend: backend.clone(),
states: states.clone(),
update: update.clone(),
running: running.clone(),
})
.with_priority(3)
.build();
world
.create_system(RenderSystem {
backend: backend.clone(),
render_objects: render_objects.clone(),
update: update.clone(),
running: running.clone(),
})
.with_priority(4)
.build();
runner.world(world);
self.windows.push(WindowShell {
backend_runner: runner,
render_objects,
layouts,
handlers,
states,
update,
running,
resizable: resizeable.0,
});
self
}
/// Starts the application and run it until quit is requested.
......
<
......@@ -4,14 +4,13 @@ use std::{
rc::Rc,
};
use dces::prelude::{Entity, World};
use dces::prelude::Entity;
use crate::prelude::*;
use crate::backend::*;
use crate::systems::*;
/// Represents a window. Each window has its own tree, event pipeline and backend.
pub struct Window {
pub struct WindowShell {
pub backend_runner: Box<dyn BackendRunner>,
pub render_objects: Rc<RefCell<BTreeMap<Entity, Box<dyn RenderObject>>>>,
pub layouts: Rc<RefCell<BTreeMap<Entity, Box<dyn Layout>>>>,
......@@ -20,175 +19,12 @@ pub struct Window {
pub update: Rc<Cell<bool>>,
pub running: Rc<Cell<bool>>,
pub resizable: bool,
pub debug_flag: Rc<Cell<bool>>,
}
impl Window {
impl WindowShell {
/// Executes the given window until quit is requested.
pub fn run(&mut self) {
self.backend_runner
.run(self.update.clone(), self.running.clone());
}
}
/// The `WindowBuilder` is used to define and build a `Window`.
pub struct WindowBuilder<'a> {
pub application: &'a mut Application,
pub bounds: Bounds,
pub title: String,
pub theme: Theme,
// pub root: Option<Template>,
pub resizable: bool,
pub debug_flag: bool,
}
impl<'a> WindowBuilder<'a> {
/// Used to define the render `bounds` of the window.
pub fn bounds<B: Into<Bounds>>(mut self, bounds: B) -> Self {
self.bounds = bounds.into();
self
}
/// Used to set the `title` of the window.
pub fn title<S: Into<String>>(mut self, title: S) -> Self {
self.title = title.into();
self
}
/// Used to set the css `theme` of the window.
pub fn theme(mut self, theme: Theme) -> Self {
self.theme = theme;
self