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

[api update] button, stack, image, switch,

toggle-button, check.box, fixes
parent 4c400c68
......@@ -8,7 +8,7 @@
> OrbTk 0.3.0 is under heavy development and it's not compatible to earlier releases.
The Orbital Widget Toolkit is a multi platform (G)UI toolkit for building scalable user interfaces with the programming language Rust. It's based
on the [Entity Component System Pattern](https://en.wikipedia.org/wiki/Entity%E2%80%93component%E2%80%93system) and provides a functional-reactive API.
on the [Entity Component System Pattern](https://en.wikipedia.org/wiki/Entity%E2%80%93component%E2%80%93system) and provides a functional-reactive like API.
The main goals of OrbTk are fast performance, easy to use and cross platform.
......@@ -16,7 +16,7 @@ The main goals of OrbTk are fast performance, easy to use and cross platform.
## Features:
* Modern [Flutter](https://flutter.io/), [React](https://reactjs.org/), [Redux](https://redux.js.org/) like API
* Modern lightweight API
* Uses the Entity Component System library [DCES](https://gitlab.redox-os.org/redox-os/dces-rust) for widget and properties handling
* Updating instead of rebuilding sub-trees
* Flexible event system
......@@ -55,9 +55,8 @@ fn main() {
.create_window()
.bounds(Bounds::new(100.0, 100.0, 420.0, 730.0))
.title("OrbTk - minimal example")
.root(TextBlock::create().text("OrbTk").into())
.debug_flag(false)
.build();
.build(TextBlock::create().text("OrbTk"));
application.run();
}
```
......@@ -90,12 +89,13 @@ cargo doc --no-deps --open
* Exchange views / widgets / screens on runtime
* Split application in modules
* Theme update
* Support for Android, iOS and WebAssembly
* Support for Android, iOS, Ubuntu Touch and WebAssembly
* Vulkan / OpenGL Support
## Dependencies
* [OrbClient](https://gitlab.redox-os.org/redox-os/orbclient): window creation, drawing, window events
* [OrbGL](https://gitlab.redox-os.org/redox-os/orbgl): 2D/3D drawing
* [OrbClient](https://gitlab.redox-os.org/redox-os/orbclient): window creation, window events
* [OrbFont](https://gitlab.redox-os.org/redox-os/orbfont): font rendering
* [OrbImage](https://gitlab.redox-os.org/redox-os/orbimage/tree/master/src): image loading
* [DCES](https://gitlab.redox-os.org/redox-os/dces-rust): Entity Component System
......
......@@ -22,6 +22,4 @@
// application.run();
// }
fn main() {
}
\ No newline at end of file
fn main() {}
\ No newline at end of file
// use orbtk::*;
// widget!(MainView);
// impl Widget for MainView {
// fn create() -> Self {
// MainView::new()
// .debug_name("MainView")
// .child(ImageWidget::create()
// .image("res/orbtk-space.png"))
// }
// }
// fn main() {
// let mut application = Application::default();
// application
// .create_window()
// .bounds((100.0, 100.0, 800.0, 420.0))
// .title("OrbTk - image example")
// .root(MainView::create())
// .build();
// application.run();
// }
use orbtk::*;
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();
}
\ No newline at end of file
......@@ -138,6 +138,4 @@
// application.run();
// }
fn main() {
}
\ No newline at end of file
fn main() {}
\ No newline at end of file
......@@ -83,6 +83,4 @@
// application.run();
// }
fn main() {
}
\ No newline at end of file
fn main() {}
\ No newline at end of file
// use orbtk::*;
// fn main() {
// let mut application = Application::default();
// application
// .create_window()
// .bounds((100.0, 100.0, 420.0, 730.0))
// .title("OrbTk - minimal example")
// .root(Button::create().text("OrbTk"))
// .debug_flag(false)
// .build();
// application.run();
// }
use orbtk::*;
fn main() {
}
\ No newline at end of file
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();
}
......@@ -19,14 +19,7 @@ use orbtk::*;
// }
// }
// fn create_header(text: &str, grid: usize, column: usize) -> Template {
// TextBlock::create()
// .text(text)
// .selector(Selector::from("textblock").class("h1"))
// .attach(GridColumn(grid))
// .attach(GridRow(column))
// .into()
// }
// widget!(MainView);
......@@ -124,16 +117,102 @@ use orbtk::*;
// }
// }
fn create_header(context: &mut BuildContext, text: &str, grid: usize, column: usize) -> Entity {
TextBlock::create()
.text(text)
.selector(SelectorValue::new().with("text-block").class("h1"))
.attach(GridColumn(grid))
.attach(GridRow(column))
.build(context)
}
widget!(MainView);
impl Template for MainView {
fn template(self, _: Entity, context: &mut BuildContext) -> Self {
self.name("MainView").child(
Button::create()
.text("Click me")
.vertical_alignment("Start")
.horizontal_alignment("Start")
.build(context),
Grid::create()
.margin(8.0)
.columns(
Columns::create()
.column("Auto")
.column(32.0)
.column("Auto")
.column("*")
.build(),
)
.rows(
Rows::create()
.row("Auto")
.row("Auto")
.row("Auto")
.row("Auto")
.row("Auto")
.row("Auto")
.build(),
)
// Column 0
.child(create_header(context, "Button", 0, 0))
.child(
Button::create()
.text("Button")
.margin((0.0, 8.0, 0.0, 0.0))
.icon(material_font_icons::CHECK_FONT_ICON)
.attach(GridColumn(0))
.attach(GridRow(1))
.on_click(move |_| {
println!("Blub");
// state.increment();
true
}).build(context)
)
.child(
Button::create()
.text("Primary")
.selector(SelectorValue::new().with("button").class("primary"))
.margin((0.0, 8.0, 0.0, 0.0))
.icon(material_font_icons::CHECK_FONT_ICON)
.attach(GridColumn(0))
.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)
)
.child(
CheckBox::create()
.text("CheckBox")
.margin((0.0, 8.0, 0.0, 0.0))
.attach(GridColumn(0))
.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)
)
// Column 2
.child(create_header(context, "Text", 2, 0))
.child(
TextBlock::create()
.selector(SelectorValue::new().class("body"))
// .text(button_count_text.share())
.margin((0.0, 8.0, 0.0, 0.0))
.attach(GridColumn(2))
.attach(GridRow(1)).build(context)
)
// .child(
// TextBox::create()
// .water_mark("TextBox...")
// .margin((0.0, 8.0, 0.0, 0.0))
// .attach(GridColumn(2))
// .attach(GridRow(2)).build(context)
// )
.build(context)
)
}
}
......
......@@ -88,12 +88,12 @@ impl<'a> WindowBuilder<'a> {
/// Creates the window with the given properties and builds its widget tree.
pub fn build<W>(self, root: W)
where
W: Widget,
where
W: Widget,
{
let mut world = World::from_container(Tree::default());
// register window as entity with global properties
// register window as entity with global properties
let window = world
.create_entity()
.with(Global::default())
......@@ -108,7 +108,7 @@ impl<'a> WindowBuilder<'a> {
let (mut runner, backend) =
target_backend(&self.title, self.bounds, self.resizable, self.theme);
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()));
......@@ -122,7 +122,7 @@ impl<'a> WindowBuilder<'a> {
}
if debug_flag.get() {
println!("Window (id = {}, children_len = 1)", window,);
println!("Window (id = {}, children_len = 1)", window, );
}
let mut context = BuildContext::new(
......@@ -132,7 +132,7 @@ impl<'a> WindowBuilder<'a> {
handlers.clone(),
states.clone(),
);
// Register root widget as child of window
let root = root.build(&mut context);
world.entity_container().append_child(window, root).unwrap();
......
......@@ -102,7 +102,7 @@ impl Drop for OrbitalBackend {
impl Backend for OrbitalBackend {
fn drain_events(&mut self) {
self.inner.sync();
self.inner.sync();
for event in self.inner.events() {
match event.to_option() {
......@@ -257,7 +257,7 @@ impl BackendRunner for OrbitalBackendRunner {
loop {
if !running.get() {
break;
}
}
if let Some(world) = &mut self.world {
world.run();
......
......@@ -37,7 +37,7 @@ pub fn target_backend(
title,
&flags,
)
.unwrap(),
.unwrap(),
)));
let backend_runner = Box::new(OrbitalBackendRunner {
......
......@@ -13,7 +13,7 @@ use crate::{
backend::{FontMeasure, FONT_MEASURE},
properties::{
Bounds, Constraint, Font, FontIcon, FontSize, HorizontalAlignment, IconFont, IconSize,
Image, Text, VerticalAlignment, Visibility, VisibilityValue, WaterMark, ImageExtension, ConstraintExtension
Image, Text, VerticalAlignment, Visibility, VisibilityValue, WaterMark, ImageExtension, ConstraintExtension,
},
enums::Alignment,
structs::{DirtySize, Size},
......@@ -119,6 +119,7 @@ impl Layout for FixedSizeLayout {
// -- todo will be removed after orbgl merge --
let constraint = Constraint::get(entity, ecm);
let sub_constraint = Constraint::get(entity, ecm);
if constraint.width() > 0.0 {
self.desired_size.borrow_mut().set_width(constraint.width());
......
......@@ -65,7 +65,6 @@ impl GridLayout {
&self,
rows_cache: &BTreeMap<usize, (f64, f64)>,
entity: Entity,
ecm: &EntityComponentManager,
grid_row: usize,
) -> (f64, f64) {
......@@ -168,13 +167,13 @@ impl Layout for GridLayout {
parent_size.0,
self.desired_size.borrow().width(),
margin.left(),
margin.right()
margin.right(),
),
vertical_alignment.align_measure(
parent_size.1,
self.desired_size.borrow().height(),
margin.top(),
margin.bottom()
margin.bottom(),
),
));
......@@ -267,9 +266,9 @@ impl Layout for GridLayout {
let stretch_width = ((size.0 - used_width)
/ columns
.iter()
.filter(|column| column.width == ColumnWidth::Stretch)
.count() as f64)
.iter()
.filter(|column| column.width == ColumnWidth::Stretch)
.count() as f64)
.trunc();
columns
......@@ -331,9 +330,9 @@ impl Layout for GridLayout {
let stretch_height = ((size.1 - used_height)
/ rows
.iter()
.filter(|row| row.height == RowHeight::Stretch)
.count() as f64)
.iter()
.filter(|row| row.height == RowHeight::Stretch)
.count() as f64)
.trunc();
rows.iter_mut()
......@@ -375,7 +374,7 @@ impl Layout for GridLayout {
let mut available_size = *self.children_sizes.borrow().get(child).unwrap();
// child margin
let c_margin = Margin::get(*child,ecm);
let c_margin = Margin::get(*child, ecm);
let c_vertical_alignment = VerticalAlignment::get(*child, ecm);
let c_horizontal_alignment = HorizontalAlignment::get(*child, ecm);
......
use std::{cell::RefCell, collections::BTreeMap, rc::Rc, any::Any };
use std::{cell::RefCell, collections::BTreeMap, rc::Rc, any::Any};
use dces::prelude::{Entity, EntityComponentManager};
......
......@@ -9,7 +9,7 @@ use dces::prelude::{Entity, EntityComponentManager};
use crate::{
application::Tree,
properties::{
Bounds, Constraint, HorizontalAlignment, Margin, Padding, VerticalAlignment, Visibility, VisibilityValue, ConstraintExtension
Bounds, Constraint, HorizontalAlignment, Margin, Padding, VerticalAlignment, Visibility, VisibilityValue, ConstraintExtension,
},
enums::Alignment,
structs::{DirtySize, Position, Size, Spacer},
......@@ -125,13 +125,13 @@ impl Layout for PaddingLayout {
parent_size.0,
self.desired_size.borrow().width(),
margin.left(),
margin.right()
margin.right(),
),
vertical_alignment.align_measure(
parent_size.1,
self.desired_size.borrow().height(),
margin.top(),
margin.bottom()
margin.top(),
margin.bottom(),
),
));
......@@ -159,20 +159,20 @@ impl Layout for PaddingLayout {
child_bounds.set_x(
padding.left()
+ child_horizontal_alignment.align_position(
available_size.0,
child_bounds.width(),
child_margin.left(),
child_margin.right()
),
available_size.0,
child_bounds.width(),
child_margin.left(),
child_margin.right(),
),
);
child_bounds.set_y(
padding.top()
+ child_vertical_alignment.align_position(
available_size.1,
child_bounds.height(),
child_margin.top(),
child_margin.bottom()
),
available_size.1,
child_bounds.height(),
child_margin.top(),
child_margin.bottom(),
),
);
}
}
......
......@@ -114,7 +114,7 @@ impl Layout for StackLayout {
let vertical_alignment = VerticalAlignment::get(entity, ecm);
let margin = Margin::get(entity, ecm);
let constraint = Constraint::get(entity, ecm);
let orientation = Orientation::get(entity, ecm);
let orientation = Orientation::get(entity, ecm);
let mut size_counter = 0.0;
let size = constraint.perform((
......@@ -122,13 +122,13 @@ impl Layout for StackLayout {
parent_size.0,
self.desired_size.borrow().width(),
margin.left(),
margin.right()
margin.right(),
),
vertical_alignment.align_measure(
parent_size.1,
self.desired_size.borrow().height(),
margin.top(),
margin.bottom()
margin.bottom(),
),
));
......@@ -162,17 +162,17 @@ impl Layout for StackLayout {
child_bounds.set_x(
size_counter
+ child_horizontal_alignment.align_position(
available_size.0,
child_bounds.width(),
child_margin.left(),
child_margin.right()
),
available_size.0,
child_bounds.width(),
child_margin.left(),
child_margin.right(),
),
);
child_bounds.set_y(child_vertical_alignment.align_position(
available_size.1,
child_bounds.height(),
child_margin.top(),
child_margin.bottom()
child_margin.bottom(),
));
size_counter +=
child_bounds.width() + child_margin.left() + child_margin.right();
......@@ -182,16 +182,16 @@ impl Layout for StackLayout {
available_size.0,
child_bounds.width(),
child_margin.left(),
child_margin.right()
child_margin.right(),
));
child_bounds.set_y(
size_counter
+ child_vertical_alignment.align_position(
available_size.1,
child_bounds.height(),
child_margin.top(),
child_margin.bottom()
),
available_size.1,
child_bounds.height(),
child_margin.top(),
child_margin.bottom(),
),
);
size_counter +=
child_bounds.height() + child_margin.top() + child_margin.bottom();
......
......@@ -8,7 +8,7 @@ macro_rules! property {
#[derive(Default, Debug, Clone, PartialEq)]
$(#[$property_doc])*
pub struct $property(pub $type);
impl $property {
/// Returns the value of a property.
pub fn get(entity: Entity, ecm: &EntityComponentManager) -> $type {
......@@ -58,7 +58,8 @@ macro_rules! widget {
use crate::{event::EventHandler,
properties::{Bounds, Constraint, VerticalAlignment, HorizontalAlignment, Visibility, Name},
widget::{PropertySource, Widget, BuildContext}};
widget::{PropertySource, Widget, BuildContext},
structs::Point};
$(#[$widget_doc])*
pub struct $widget {
......@@ -70,6 +71,7 @@ macro_rules! widget {
name: Option<Name>,
horizontal_alignment: HorizontalAlignment,
vertical_alignment: VerticalAlignment,
margin: Margin,
enabled: Enabled,
visibility: Visibility,
$(
......@@ -114,12 +116,72 @@ macro_rules! widget {
self.attach(visibility)
}
/// Sets or shares the margin property.
pub fn margin<P: Into<PropertySource<Margin>>>(self, margin: P) -> Self {
self.attach(margin)
}
/// Sets or shares the enabled property.
pub fn enabled<P: Into<PropertySource<Enabled>>>(self, enabled: P) -> Self {
self.attach(enabled)
}
// todo: constraint also by with min max, ...
/// Inserts a new width.
pub fn width(mut self, width: f64) -> Self {
self.constraint.set_width(width);
self
}
/// Inserts a new height.
pub fn height(mut self, height: f64) -> Self {
self.constraint.set_height(height);
self
}
/// Inserts a new size.
pub fn size(mut self, width: f64, height: f64) -> Self {
self.constraint.set_width(width);
self.constraint.set_height(height);
self
}
/// Inserts a new min_width.
pub fn min_width(mut self, min_width: f64) -> Self {
self.constraint.set_min_width(min_width);
self
}
/// Inserts a new min_height.
pub fn min_height(mut self, min_height: f64) -> Self {
self.constraint.set_min_height(min_height);
self
}
/// Inserts a new min_size.
pub fn min_size(mut self, min_width: f64, min_height: f64) -> Self {
self.constraint.set_min_width(min_width);
self.constraint.set_min_height(min_height);
self
}
/// Inserts a new max_width.