Update code style to use rust fmt (#3131)

This commit is contained in:
Michael Mauderer 2021-11-02 14:05:43 +01:00 committed by GitHub
parent ab0f50a7a3
commit c822256e6c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
432 changed files with 35600 additions and 29765 deletions

View File

@ -122,6 +122,8 @@ jobs:
run: npm install --save-dev --save-exact prettier
- name: Install Clippy
run: rustup component add clippy
- name: Install Clippy
run: rustup component add rustfmt
- name: Lint Markdown sources
run: npx prettier --check '*.md'
- name: Lint JavaScript sources

View File

@ -240,8 +240,8 @@ commands.test.rust = async function(argv) {
commands.lint = command(`Lint the codebase`)
commands.lint.rust = async function() {
// We run clippy-preview due to https://github.com/rust-lang/rust-clippy/issues/4612
await run_cargo('cargo',['clippy','--','-D','warnings'])
await run_cargo('cargo',['fmt','--','--check'])
}

View File

@ -128,6 +128,11 @@ let installClippy = {
run: 'rustup component add clippy',
}
let installFmt = {
name: "Install Clippy",
run: "rustup component add rustfmt"
}
// Install fixed version to avoid upgrading to a breaking version.
// Should be removed once this has a better solution as described here:
// https://github.com/enso-org/ide/issues/1772
@ -465,6 +470,7 @@ let workflow = {
installRust,
installPrettier,
installClippy,
installFmt,
lintMarkdown,
lintJavaScript,
lintRust,

View File

@ -1,43 +1,20 @@
---
layout: style-guide
title: Rust Style Guide
category: style-guide
tags: [style-guide,contributing]
layout: style-guide title: Rust Style Guide category: style-guide tags: [style-guide,contributing]
---
# Rust Style Guide
## Motivation - why not rely on a formatting tool for code style?
The code style is way more than just formatting. In many cases formatting can be
automated. According to rustfmt docs: "formatting code is a mostly mechanical
task which takes both time and mental effort. By using an automatic formatting
tool, a programmer is relieved of this task and can concentrate on more
important things.". While in many cases it is true, if the code author does not
take extra effort to make his code pretty by refactoring long lines to
variables, moving code to specific modules, or sections, the formatting tool
will result in code that is hard to read and hard to write. Thus, it is
important to take time to write code in such way that we can be proud of its
quality.
Because `rustfmt` does not support many of our requirements, we have created a
guide to describe how to format Rust code in this project. Please read it
carefully. We hope that in the future, some of the things described below will
be possible while using `rustfmt` (and we encourage you to contribute there!),
however, even if it happens, many parts of this guide will still be valid and
will need to be handled manually.
We are using `rustfmt` for the basic formatting of our rust code, which is also checked on CI. We
have some additional guidelines for imports, naming, sections within files and naming which are
documented here.
## Styling rules
### Code width
Each line in a source file should have max 80 chars of text (including
comments).
### Imports
Imports should be divided into 4 groups separated by blank lines. Items in the
groups should be sorted alphabetically.
Imports should be divided into 4 groups separated by blank lines. Items in the groups should be
sorted alphabetically.
```rust
// Group 1: sub-module definitions.
// Group 2: prelude-like imports.
@ -46,6 +23,7 @@ groups should be sorted alphabetically.
```
For example:
```rust
pub mod display_object;
@ -60,17 +38,14 @@ use nalgebra::Matrix4;
use nalgebra::Vector3;
```
### Sections
Source files should be divided into sections. Section headers should be placed
before each new "concept" defined in a file. By "concept" we normally mean a
structure with related implementations. In case related implementations use some
helper structs with very small implementations, these helper structs may be
defined in the same section. Moreover, the code in each section should be
divided into sub-sections, grouping related definitions. At least one section
should be defined in a file (if there is at least one struct definition as
well). For example:
Source files should be divided into sections. Section headers should be placed before each new "
concept" defined in a file. By "concept" we normally mean a structure with related implementations.
In case related implementations use some helper structs with very small implementations, these
helper structs may be defined in the same section. Moreover, the code in each section should be
divided into sub-sections, grouping related definitions. At least one section should be defined in a
file (if there is at least one struct definition as well). For example:
```rust
// =================
@ -86,7 +61,6 @@ impl Default for AxisOrder {
}
// =================
// === Transform ===
// =================
@ -107,7 +81,6 @@ impl Default for TransformOrder {
}
// =============================
// === HierarchicalTransform ===
// =============================
@ -166,28 +139,15 @@ impl<OnChange:Callback0> HierarchicalTransform<OnChange> {
}
```
### Vertical spacing
We use the following amount of vertical spacing:
- 3 blank lines after imports.
- 3 blank lines before each section.
- 2 blank lines before each sub-section.
- 1 blank line after each section / sub-section.
- 1 blank line before functions / structures / impls.
- 1 blank line at the end of the file.
Please note that vertical spacing overlaps. For example, if there is a section
after imports, the total number of blank lines is 3, not 6.
### Multiline Expressions
Most (preferably all) expressions should be single line. Multiline expressions
are hard to read and introduce noise in the code. Often, it is also an indicator
of code that is not properly refactored. Try to refactor parts of multiline
expressions to well-named variables, and divide them to several single-line
expressions.
Most (preferably all) expressions should be single line. Multiline expressions are hard to read and
introduce noise in the code. Often, it is also an indicator of code that is not properly refactored.
Try to refactor parts of multiline expressions to well-named variables, and divide them to several
single-line expressions.
Example of poorly formatted code:
```rust
pub fn new() -> Self {
let shape_dirty = ShapeDirty::new(logger.sub("shape_dirty"),
@ -197,6 +157,7 @@ pub fn new() -> Self {
Self { dirty_flag, dirty_flag }
}
```
Example of properly formatted code:
```rust
@ -209,134 +170,11 @@ pub fn new() -> Self {
}
```
### Vertical alignment
The following elements should be aligned vertically in subsequent lines:
- assignment operators (`=`),
- type operators (`:`),
- match arrows (`=>`),
- similar parameters or types.
Examples:
```rust
impl Printer for GlobalVarStorage {
fn print(&self, builder:&mut Builder) {
match self {
Self::ConstStorage => build!(builder,"const"),
Self::UniformStorage => build!(builder,"uniform"),
Self::InStorage (qual) => build!(builder,"in" ,qual),
Self::OutStorage (qual) => build!(builder,"out",qual),
}
}
}
```
### Spaces
- Type operator is not spaced: `fn test(foo:String, bar:Int) { ... }`.
- Commas between complex expressions (including arg list) are spaced.
- Commas between simple elements are not spaced: `Result<Self,Error>`.
- Arguments to functions are not spaced: `build(builder,"out",qual)`.
- Operators are always spaced: `let foo = a + b * c;`.
### Function definitions
The following examples show proper function styles:
```rust
pub fn new<Dom:Str>(dom:Dom, logger:Logger) -> Result<Self,Error> {
...
}
```
```rust
pub fn new<Dom:Str>(dom:Dom, logger:Logger) -> Result<Self,Error> {
...
}
```
```rust
pub fn new<Dom:Str>
(dom:Dom, logger:Logger, on_dirty:OnDirty) -> Result<Self,Error> {
...
}
```
```rust
pub fn new<Dom:Str>
(dom:Dom, logger:Logger, on_dirty:OnDirty, on_remove:OnRemove)
-> Result<Self,Error> {
...
}
```
```rust
pub fn new<Dom:Str>
( dom : Dom
, logger : Logger
, on_dirty : OnDirty
, on_remove : OnRemove
, on_replace : OnReplace
) -> Result<Self,Error> {
...
}
```
Long `where` clauses are formatted this way:
```rust
pub fn new<D,L>(dom:D, logger:L) -> Result<Self,Error>
where D:AsRef<str>, L:IsLogger {
...
}
```
Or, in case they are really long, this way:
```rust
pub fn new<D,L>(dom:D, logger:L) -> Result<Self,Error>
where D:AsRef<str>
L:IsLogger
... {
...
}
```
### Impl definitions
Sometimes when browsing code it is hard to understand where the header of
an impl declaration is. Thus, the following style allows to find it easier.
The `where` block should be placed after a linebreak.
All of the following are correct:
```rust
// No constraints
impl<T> Printer for Option<T> {
...
}
```
```rust
// Some constraints
impl<T:Printer>
Printer for Option<T> {
...
}
```
```rust
// Constraints in where block
impl<T> Printer for Option<T>
where T: Printer {
...
}
```
### Getters and Setters
Getters do not have the `get_` prefix, while setters do. If a setter is
provided (method with the `set_` prefix), a `mut` accessor should be
provided as well. The correct way of defining getters and setters is
presented below:
Getters do not have the `get_` prefix, while setters do. If a setter is provided (method with
the `set_` prefix), a `mut` accessor should be provided as well. The correct way of defining getters
and setters is presented below:
```rust
fn field(&self) -> &Type {
@ -352,8 +190,8 @@ fn set_field(&mut self, val:Type) {
}
```
### Trait exporting
All names should be designed to be used in a qualified fashion. However, this makes one situation
tricky. In order to use methods defined in a trait, it has to be in scope. Consider a trait
`display::Object`. We want to use it as function bound like `fn test<T:display::Object>(t:T) {...}`,

74
gui/rustfmt.toml Normal file
View File

@ -0,0 +1,74 @@
max_width = 100
hard_tabs = false
tab_spaces = 4
newline_style = "Unix"
indent_style = "Block"
use_small_heuristics = "Max"
fn_call_width = 100
attr_fn_like_width = 100
struct_lit_width = 100
struct_variant_width = 100
array_width = 100
chain_width = 100
single_line_if_else_max_width = 100
wrap_comments = true
format_code_in_doc_comments = true
comment_width = 100
normalize_comments = false
normalize_doc_attributes = false
license_template_path = ""
format_strings = false
format_macro_matchers = false
format_macro_bodies = true
empty_item_single_line = true
struct_lit_single_line = true
fn_single_line = false
where_single_line = true
imports_indent = "Block"
imports_layout = "Mixed"
imports_granularity = "Item"
group_imports = "Preserve"
reorder_imports = true
reorder_modules = true
reorder_impl_items = false
type_punctuation_density = "Wide"
space_before_colon = false
space_after_colon = true
spaces_around_ranges = false
binop_separator = "Front"
remove_nested_parens = true
combine_control_expr = true
overflow_delimited_expr = true
struct_field_align_threshold = 20
enum_discrim_align_threshold = 20
match_arm_blocks = false
match_arm_leading_pipes = "Never"
force_multiline_blocks = false
fn_args_layout = "Tall"
brace_style = "PreferSameLine"
control_brace_style = "AlwaysSameLine"
trailing_semicolon = true
trailing_comma = "Vertical"
match_block_trailing_comma = false
blank_lines_upper_bound = 3
blank_lines_lower_bound = 0
edition = "2018"
version = "One"
inline_attribute_width = 0
merge_derives = false
use_try_shorthand = false
use_field_init_shorthand = true
force_explicit_abi = true
condense_wildcard_suffixes = false
color = "Auto"
unstable_features = false
disable_all_formatting = false
skip_children = false
hide_parse_errors = false
error_on_line_overflow = false
error_on_unformatted = false
report_todo = "Never"
report_fixme = "Never"
ignore = []
emit_mode = "Files"
make_backup = false

View File

@ -1,8 +1,8 @@
#![feature(trait_alias)]
use std::path;
use std::io::ErrorKind;
use std::fmt::Display;
use std::io::ErrorKind;
use std::path;
/// Types that can yield a reference to std::path::Path.
pub trait PathRef = AsRef<path::Path>;
@ -20,7 +20,8 @@ impl<T:AsRef<str>+Display> GithubRelease<T> {
///
/// The project_url should be a project's main page on GitHub.
pub fn download(&self, destination_dir: &path::Path) {
let url = format!("{}/releases/download/{}/{}",self.project_url,self.version,self.filename);
let url =
format!("{}/releases/download/{}/{}", self.project_url, self.version, self.filename);
let destination_file = destination_dir.join(self.filename.as_ref());
Self::remove_old_file(&destination_file);
let mut resp = reqwest::blocking::get(&url).expect("Download failed.");

View File

@ -1,10 +1,12 @@
use std::{path, env};
use std::env;
use std::path;
/// A module with functions generating huge chunk of texts for text component benchmarks.
mod huge_text_generator {
use std::collections::hash_map::DefaultHasher;
use std::fs::File;
use std::hash::{Hash,Hasher};
use std::hash::Hash;
use std::hash::Hasher;
use std::io::Write;
use std::path::Path;
@ -43,12 +45,14 @@ mod huge_text_generator {
}
fn write_verse(file: &mut File, i: usize) {
write!(file,
write!(
file,
"{i} bottles of beer on the wall, {i} bottles of beer.\
Take one down and pass it around, {j} bottles of beer on the wall. ",
i = i,
j = i - 1
).unwrap();
)
.unwrap();
}
}

View File

@ -2,8 +2,8 @@
use crate::prelude::*;
use ensogl_core::system::web;
use ensogl_core::application::Application;
use ensogl_core::system::web;
use ensogl_core::DEPRECATED_Animation;
use ensogl_text_msdf_sys::run_once_initialized;
use logger::TraceLogger as Logger;
@ -34,7 +34,6 @@ pub fn entry_point_animation() {
// ========================
fn init() {
let logger: Logger = Logger::new("AnimationTest");
let network = enso_frp::Network::new("test");
let animation = DEPRECATED_Animation::<f32>::new(&network);

View File

@ -2,15 +2,15 @@
use ensogl_core::prelude::*;
use ensogl_core::data::color;
use ensogl_core::display::navigation::navigator::Navigator;
use ensogl_core::system::web;
use wasm_bindgen::prelude::*;
use ensogl_core::display::object::ObjectOps;
use ensogl_core::display::world::*;
use ensogl_core::display::scene;
use ensogl_core::display::shape::*;
use ensogl_core::data::color;
use ensogl_core::display::style::theme;
use ensogl_core::display::world::*;
use ensogl_core::system::web;
use wasm_bindgen::prelude::*;
@ -97,7 +97,8 @@ pub fn entry_point_complex_shape_system() {
mask.size.set(Vector2::new(300.0, 300.0));
mask.mod_position(|t| *t = Vector3::new(-50.0, 0.0, 0.0));
let scissor_box = scene::layer::ScissorBox::new_with_position_and_size(default(),Vector2(600,600));
let scissor_box =
scene::layer::ScissorBox::new_with_position_and_size(default(), Vector2(600, 600));
scene.layers.main.set_scissor_box(Some(&scissor_box));
let view2 = shape::View::new(&logger);
@ -111,7 +112,8 @@ pub fn entry_point_complex_shape_system() {
let scene = world.scene().clone_ref();
let mut frame = 0;
world.on_frame(move |_time| {
world
.on_frame(move |_time| {
mask.set_position_x(((frame as f32) / 30.0).sin() * 100.0);
let _keep_alive = &navigator;
@ -156,6 +158,6 @@ pub fn entry_point_complex_shape_system() {
theme_manager.set_enabled(&["theme2".to_string()]);
}
frame += 1;
}).forget();
})
.forget();
}

View File

@ -1,15 +1,15 @@
#![allow(missing_docs)]
use ensogl_core::traits::*;
use ensogl_core::prelude::*;
use ensogl_core::system::web;
use ensogl_core::system::web::NodeInserter;
use ensogl_core::display::symbol::DomSymbol;
use ensogl_core::display::navigation::navigator::Navigator;
use ensogl_core::display::symbol::geometry::Sprite;
use ensogl_core::display::symbol::geometry::SpriteSystem;
use ensogl_core::display::symbol::DomSymbol;
use ensogl_core::display::world::*;
use ensogl_core::display::navigation::navigator::Navigator;
use ensogl_core::system::web;
use ensogl_core::system::web::NodeInserter;
use web::StyleSetter;
use nalgebra::Vector2;
@ -76,7 +76,8 @@ pub fn entry_point_dom_symbols() {
let mut iter_to_change = 0;
let mut i = 0;
world.keep_alive_forever();
world.on_frame(move |_| {
world
.on_frame(move |_| {
let _keep_alive = &navigator;
let _keep_alive = &sprites;
let _keep_alive = &sprite_system;
@ -89,5 +90,6 @@ pub fn entry_point_dom_symbols() {
}
}
iter_to_change -= 1;
}).forget();
})
.forget();
}

View File

@ -3,11 +3,11 @@
use enso_prelude::*;
use ensogl_core::frp::web;
use ensogl_core::display::world::World;
use ensogl_core::frp::web;
use ensogl_web::drop;
use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::spawn_local;
use ensogl_web::drop;
fn download_file(file: drop::File) {
spawn_local(async move {
@ -16,11 +16,11 @@ fn download_file(file:drop::File) {
match file.read_chunk().await {
Ok(Some(chunk)) => {
INFO!("Received chunk: {chunk:?}");
},
}
Ok(None) => {
INFO!("All chunks received successfully");
break
},
break;
}
Err(err) => {
ERROR!("Error in receiving chunk promise: {err:?}");
break;
@ -45,16 +45,16 @@ pub fn entry_point_drop_manager() {
}
let mut loader_hidden = false;
world.on_frame(move |_| {
world
.on_frame(move |_| {
if !loader_hidden {
web::get_element_by_id("loader").map(|t| {
t.parent_node().map(|p| {
p.remove_child(&t).unwrap()
})
}).ok();
web::get_element_by_id("loader")
.map(|t| t.parent_node().map(|p| p.remove_child(&t).unwrap()))
.ok();
loader_hidden = true;
}
}).forget();
})
.forget();
std::mem::forget(world);
std::mem::forget(network);

View File

@ -2,21 +2,21 @@
use crate::prelude::*;
use ensogl_core::animation::easing::*;
use ensogl_core::animation;
use ensogl_core::system::web::AttributeSetter;
use ensogl_core::animation::easing::*;
use ensogl_core::system::web;
use ensogl_core::system::web::create_element;
use ensogl_core::system::web::get_element_by_id;
use ensogl_core::system::web::AttributeSetter;
use ensogl_core::system::web::NodeInserter;
use ensogl_core::system::web::StyleSetter;
use ensogl_core::system::web;
use js_sys::Math;
use nalgebra::Vector2;
use std::ops::Add;
use std::ops::Mul;
use std::rc::Rc;
use wasm_bindgen::JsCast;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
use web_sys::CanvasRenderingContext2d;
use web_sys::HtmlCanvasElement;
use web_sys::HtmlElement;
@ -32,7 +32,7 @@ use web_sys::HtmlElement;
#[allow(missing_docs)]
pub struct SpriteData {
pub position: Vector2<f32>,
pub size : f64
pub size: f64,
}
impl SpriteData {
@ -79,7 +79,7 @@ impl Add<SpriteData> for SpriteData {
#[derive(Clone, Debug)]
pub struct Canvas {
canvas: HtmlCanvasElement,
context : CanvasRenderingContext2d
context: CanvasRenderingContext2d,
}
impl Canvas {
@ -123,7 +123,12 @@ impl Canvas {
self.context.scale(self.width() / 2.0, self.height() / 2.0).ok();
self.context.set_line_width(2.0 / self.height());
self.context.translate(1.0, 1.0).ok();
self.context.fill_rect(point.x as f64 - size / 2.0,point.y as f64 - size / 2.0,size,size);
self.context.fill_rect(
point.x as f64 - size / 2.0,
point.y as f64 - size / 2.0,
size,
size,
);
self.context.restore();
}
@ -185,7 +190,15 @@ impl Sampler {
let easing_animator = Animator::new(start, end, easing_function2, animation_cb, ());
let time = 0.0;
easing_animator.set_duration(2000.0);
Self {color,time,left_canvas,right_canvas,easing_animator,properties,easing_function}
Self {
color,
time,
left_canvas,
right_canvas,
easing_animator,
properties,
easing_function,
}
}
fn render(&mut self, time_diff: f32) {
@ -209,16 +222,16 @@ impl Sampler {
// ===============
struct Example {
_animator : animation::Loop<Box<dyn FnMut(animation::TimeInfo)>>
_animator: animation::Loop<Box<dyn FnMut(animation::TimeInfo)>>,
}
impl Example {
#[allow(trivial_casts)]
pub fn new
( name : &str
, ease_in : impl CloneableFnEasing
, ease_out : impl CloneableFnEasing
, ease_in_out : impl CloneableFnEasing
pub fn new(
name: &str,
ease_in: impl CloneableFnEasing,
ease_out: impl CloneableFnEasing,
ease_in_out: impl CloneableFnEasing,
) -> Self {
let example = web::create_div();
example.set_attribute_or_panic("id", name);

View File

@ -5,8 +5,8 @@ use ensogl_core::prelude::*;
use ensogl_core::data::color;
use ensogl_core::display::world::*;
use ensogl_core::system::web;
use ensogl_text_msdf_sys::run_once_initialized;
use ensogl_text::typeface::*;
use ensogl_text_msdf_sys::run_once_initialized;
use wasm_bindgen::prelude::*;

View File

@ -13,7 +13,7 @@
/// leaked when the `Leak` is dropped.
#[derive(Debug)]
pub struct Leak<T> {
value: Option<T>
value: Option<T>,
}
impl<T> Leak<T> {

View File

@ -20,18 +20,16 @@
#![warn(unsafe_code)]
#![warn(unused_import_braces)]
#![warn(unused_qualifications)]
#![recursion_limit = "1024"]
#[allow(clippy::option_map_unit_fn)]
mod leak;
pub mod animation;
pub mod complex_shape_system;
pub mod dom_symbols;
pub mod drop_manager;
pub mod easing_animator;
pub mod glyph_system;
#[allow(clippy::option_map_unit_fn)]
mod leak;
pub mod list_view;
pub mod mouse_events;
pub mod scroll_area;
@ -43,6 +41,6 @@ pub mod text_area;
/// Common types that should be visible across the whole crate.
pub mod prelude {
pub use ensogl_core::prelude::*;
pub use super::leak::*;
pub use ensogl_core::prelude::*;
}

View File

@ -2,15 +2,15 @@
use crate::prelude::*;
use ensogl_core::system::web;
use ensogl_core::application::Application;
use ensogl_core::display::object::ObjectOps;
use ensogl_text_msdf_sys::run_once_initialized;
use ensogl_core::system::web;
use ensogl_gui_components::list_view;
use ensogl_text::buffer::data::unit::Bytes;
use ensogl_text_msdf_sys::run_once_initialized;
use ensogl_theme as theme;
use logger::TraceLogger as Logger;
use wasm_bindgen::prelude::*;
use ensogl_text::buffer::data::unit::Bytes;
use ensogl_theme as theme;
@ -49,7 +49,9 @@ impl MockEntries {
}
impl list_view::entry::ModelProvider<list_view::entry::GlyphHighlightedLabel> for MockEntries {
fn entry_count(&self) -> usize { self.entries_count }
fn entry_count(&self) -> usize {
self.entries_count
}
fn get(&self, id: usize) -> Option<list_view::entry::GlyphHighlightedLabelModel> {
if id >= self.entries_count {

View File

@ -3,7 +3,6 @@
use ensogl_core::prelude::*;
use wasm_bindgen::prelude::*;
use ensogl_core::system::web;
use ensogl_core::application;
use ensogl_core::application::Application;
use ensogl_core::data::color;
@ -12,6 +11,7 @@ use ensogl_core::display;
use ensogl_core::display::navigation::navigator::Navigator;
use ensogl_core::display::object::ObjectOps;
use ensogl_core::display::shape::*;
use ensogl_core::system::web;
use enso_frp as frp;
use ensogl_text_msdf_sys::run_once_initialized;
@ -103,22 +103,34 @@ impl View {
}
impl display::Object for View {
fn display_object(&self) -> &display::object::Instance { &self.model.display_object }
fn display_object(&self) -> &display::object::Instance {
&self.model.display_object
}
}
impl Deref for View {
type Target = Frp;
fn deref(&self) -> &Self::Target { &self.frp }
fn deref(&self) -> &Self::Target {
&self.frp
}
}
impl application::command::FrpNetworkProvider for View {
fn network(&self) -> &frp::Network { &self.frp.network }
fn network(&self) -> &frp::Network {
&self.frp.network
}
}
impl application::View for View {
fn label() -> &'static str { "Circul" }
fn new(app:&Application) -> Self { View::new(app) }
fn app(&self) -> &Application { &self.model.app }
fn label() -> &'static str {
"Circul"
}
fn new(app: &Application) -> Self {
View::new(app)
}
fn app(&self) -> &Application {
&self.model.app
}
}

View File

@ -6,14 +6,16 @@ use wasm_bindgen::prelude::*;
use ensogl_core::application::Application;
use ensogl_core::data::color;
use ensogl_core::display::object::ObjectOps;
use ensogl_core::display::shape::Circle;
use ensogl_core::display::shape::PixelDistance;
use ensogl_core::display::shape::Rect;
use ensogl_core::display::shape::ShapeOps;
use ensogl_core::display::shape::ShapeSystem;
use ensogl_core::display::Sprite;
use ensogl_core::system::web;
use ensogl_gui_components::scroll_area::ScrollArea;
use ensogl_text_msdf_sys::run_once_initialized;
use ensogl_theme as theme;
use ensogl_gui_components::scroll_area::ScrollArea;
use ensogl_core::display::shape::{Circle, Rect, ShapeSystem};
use ensogl_core::display::shape::PixelDistance;
use ensogl_core::display::shape::ShapeOps;
use ensogl_core::display::Sprite;

View File

@ -2,14 +2,14 @@
use ensogl_core::prelude::*;
use ensogl_core::data::color;
use ensogl_core::display::navigation::navigator::Navigator;
use ensogl_core::system::web;
use wasm_bindgen::prelude::*;
use ensogl_core::display::object::ObjectOps;
use ensogl_core::display::shape::ShapeSystem;
use ensogl_core::display::world::*;
use ensogl_core::display::shape::*;
use ensogl_core::data::color;
use ensogl_core::display::world::*;
use ensogl_core::system::web;
use wasm_bindgen::prelude::*;
@ -53,8 +53,10 @@ pub fn entry_point_shape_system() {
world.add_child(&sprite_system);
world.keep_alive_forever();
world.on_frame(move |_time| {
world
.on_frame(move |_time| {
let _keep_alive = &sprite;
let _keep_alive = &navigator;
}).forget();
})
.forget();
}

View File

@ -7,8 +7,8 @@ use ensogl_core::application::Application;
use ensogl_core::data::color;
use ensogl_core::display::object::ObjectOps;
use ensogl_core::system::web;
use ensogl_gui_components::selector::Bounds;
use ensogl_gui_components::selector;
use ensogl_gui_components::selector::Bounds;
use ensogl_text_msdf_sys::run_once_initialized;
use ensogl_theme as theme;

View File

@ -6,8 +6,8 @@ use wasm_bindgen::prelude::*;
use ensogl_core::display::navigation::navigator::Navigator;
use ensogl_core::display::symbol::geometry::SpriteSystem;
use ensogl_core::display::world::*;
use ensogl_core::system::web::forward_panic_hook_to_console;
use ensogl_core::system::web;
use ensogl_core::system::web::forward_panic_hook_to_console;
#[wasm_bindgen]
@ -30,7 +30,8 @@ pub fn entry_point_sprite_system() {
world.keep_alive_forever();
let mut i = 0;
world.on_frame(move |_| {
world
.on_frame(move |_| {
i += 1;
let _keep_alive = &navigator;
let _keep_alive = &sprite1;
@ -40,5 +41,6 @@ pub fn entry_point_sprite_system() {
sprite1.mod_position(|p| p.x += 1.0);
sprite2.mod_position(|p| p.y += 1.0);
}
}).forget();
})
.forget();
}

View File

@ -2,15 +2,15 @@
use ensogl_core::traits::*;
use ensogl_core::animation;
use ensogl_core::display::camera::Camera2d;
use ensogl_core::display::navigation::navigator::Navigator;
use ensogl_core::display::symbol::geometry::Sprite;
use ensogl_core::display::symbol::geometry::SpriteSystem;
use ensogl_core::display::world::*;
use ensogl_core::prelude::*;
use ensogl_core::system::web::forward_panic_hook_to_console;
use ensogl_core::system::web;
use ensogl_core::animation;
use ensogl_core::system::web::forward_panic_hook_to_console;
use nalgebra::Vector2;
use nalgebra::Vector3;
use wasm_bindgen::prelude::*;
@ -45,7 +45,8 @@ pub fn entry_point_sprite_system_benchmark() {
let mut iter: i32 = 0;
let mut i = 0;
world.on_frame(move |time| {
world
.on_frame(move |time| {
i += 1;
if i <= 100 {
sprite1.mod_position(|p| p.x += 1.0);
@ -63,18 +64,19 @@ pub fn entry_point_sprite_system_benchmark() {
// println!("sprite[5] is visible? {:?}",sprites[5].is_visible());
on_frame(&camera, time, &mut iter, &sprite1, &mut sprites, &sprite_system)
}).forget();
})
.forget();
}
#[allow(clippy::too_many_arguments)]
#[allow(clippy::many_single_char_names)]
pub fn on_frame
( camera : &Camera2d
, time : animation::TimeInfo
, iter : &mut i32
, sprite1 : &Sprite
, sprites : &mut Vec<Sprite>
, sprite_system : &SpriteSystem
pub fn on_frame(
camera: &Camera2d,
time: animation::TimeInfo,
iter: &mut i32,
sprite1: &Sprite,
sprites: &mut Vec<Sprite>,
sprite_system: &SpriteSystem,
) {
*iter += 1;
@ -122,7 +124,11 @@ pub fn on_frame
y += (z * 1.25 + t * 2.00).cos() * 0.5;
z += (x * 1.25 + t * 3.25).cos() * 0.5;
let position = Vector3::new(x * 150.0 + half_width - 75.0, y * 150.0 + half_height - 75.0, z * 150.0);
let position = Vector3::new(
x * 150.0 + half_width - 75.0,
y * 150.0 + half_height - 75.0,
z * 150.0,
);
sprite.set_position(position);
}
}

View File

@ -2,12 +2,12 @@
use ensogl_core::prelude::*;
use ensogl_core::application::Application;
use ensogl_core::display::navigation::navigator::Navigator;
use ensogl_core::system::web;
use ensogl_text::Area;
use ensogl_text_msdf_sys::run_once_initialized;
use wasm_bindgen::prelude::*;
use ensogl_core::application::Application;
use ensogl_text::Area;
use ensogl_core::display::navigation::navigator::Navigator;
/// Main example runner.
@ -26,7 +26,9 @@ pub fn entry_point_text_area() {
fn init(app: &Application) {
let area = app.new_view::<Area>();
area.set_position_x(-100.0);
area.set_content("Et Eärello Endorenna utúlien.\nSinome maruvan ar Hildinyar tenn' Ambar-metta");
area.set_content(
"Et Eärello Endorenna utúlien.\nSinome maruvan ar Hildinyar tenn' Ambar-metta",
);
area.focus();
area.hover();
area.set_cursor_at_end();
@ -36,8 +38,10 @@ fn init(app:&Application) {
app.display.scene().add_child(&area);
let keep = Some(area);
app.display.on_frame(move |_frame| {
app.display
.on_frame(move |_frame| {
let _ = &keep;
}).forget();
})
.forget();
std::mem::forget(navigator);
}

View File

@ -9,11 +9,11 @@
use crate::prelude::*;
use enso_frp as frp;
use ensogl_core::application::Application;
use ensogl_core::application::command::CommandApi;
use ensogl_core::application;
use ensogl_core::display::shape::*;
use ensogl_core::application::command::CommandApi;
use ensogl_core::application::Application;
use ensogl_core::display;
use ensogl_core::display::shape::*;
@ -84,10 +84,15 @@ impl<M: display::Object,F> display::Object for Component<M,F> {
impl<M, F: Frp<M>> Deref for Component<M, F> {
type Target = F;
fn deref(&self) -> &Self::Target { &self.frp }
fn deref(&self) -> &Self::Target {
&self.frp
}
}
impl<M, F: application::command::FrpNetworkProvider> application::command::FrpNetworkProvider
for Component<M,F> {
fn network(&self) -> &frp::Network { self.frp.network() }
for Component<M, F>
{
fn network(&self) -> &frp::Network {
self.frp.network()
}
}

View File

@ -6,12 +6,12 @@ use crate::list_view::entry::ModelProvider;
use enso_frp as frp;
use enso_frp;
use ensogl_core::DEPRECATED_Animation;
use ensogl_core::application::Application;
use ensogl_core::data::color;
use ensogl_core::display::shape::*;
use ensogl_core::display::shape::primitive::StyleWatch;
use ensogl_core::display;
use ensogl_core::display::shape::primitive::StyleWatch;
use ensogl_core::display::shape::*;
use ensogl_core::DEPRECATED_Animation;
use ensogl_text as text;
use ensogl_theme as theme;
@ -150,8 +150,10 @@ impl Model {
self.selection_menu.unset_parent()
}
fn get_content_item
(&self, id:Option<list_view::entry::Id>) -> Option<<Entry as list_view::entry::Entry>::Model> {
fn get_content_item(
&self,
id: Option<list_view::entry::Id>,
) -> Option<<Entry as list_view::entry::Entry>::Model> {
self.content.borrow().as_ref()?.get(id?)
}
@ -190,7 +192,9 @@ pub struct DropDownMenu {
impl Deref for DropDownMenu {
type Target = Frp;
fn deref(&self) -> &Self::Target { &self.frp }
fn deref(&self) -> &Self::Target {
&self.frp
}
}
impl DropDownMenu {

View File

@ -7,10 +7,10 @@ use crate::prelude::*;
use crate::file_browser::model::*;
use ensogl_core::display::shape::*;
use std::path::PathBuf;
use ensogl_core::display;
use ensogl_core::display::shape::*;
use ensogl_core::display::Scene;
use std::path::PathBuf;
// ===========
@ -56,7 +56,9 @@ pub struct FileBrowser {
impl Deref for FileBrowser {
type Target = Frp;
fn deref(&self) -> &Self::Target { &self.frp }
fn deref(&self) -> &Self::Target {
&self.frp
}
}
@ -71,9 +73,13 @@ impl FileBrowser {
}
impl Default for FileBrowser {
fn default() -> Self { Self::new() }
fn default() -> Self {
Self::new()
}
}
impl display::Object for FileBrowser {
fn display_object(&self) -> &display::object::Instance<Scene> {&self.display_object }
fn display_object(&self) -> &display::object::Instance<Scene> {
&self.display_object
}
}

View File

@ -4,8 +4,8 @@
use crate::prelude::*;
use enso_frp as frp;
use std::path::PathBuf;
use std::cmp::Ordering;
use std::path::PathBuf;
// =============
@ -53,17 +53,22 @@ impl Ord for EntryType {
(Self::File, Self::File) => Ordering::Equal,
(Self::File, Self::Folder { .. }) => Ordering::Greater,
(Self::Folder { .. }, Self::File) => Ordering::Less,
(Self::Folder {type_:type1,..},Self::Folder {type_:type2,..}) => type1.cmp(type2),
(Self::Folder { type_: type1, .. }, Self::Folder { type_: type2, .. }) =>
type1.cmp(type2),
}
}
}
impl PartialOrd for EntryType {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl PartialEq for EntryType {
fn eq(&self, other: &Self) -> bool { self.cmp(other) == Ordering::Equal }
fn eq(&self, other: &Self) -> bool {
self.cmp(other) == Ordering::Equal
}
}
impl Eq for EntryType {}
@ -87,8 +92,11 @@ pub struct Entry {
pub trait FolderContent: Debug {
/// Request the list of entries inside the folder. When the list is ready, it is emitted at
/// `entries_loaded`. If an error occurs then the error message is emitted at `error_occurred`.
fn request_entries
(&self, entries_loaded:frp::Any<Rc<Vec<Entry>>>, error_occurred:frp::Any<ImString>);
fn request_entries(
&self,
entries_loaded: frp::Any<Rc<Vec<Entry>>>,
error_occurred: frp::Any<ImString>,
);
}
/// A wrapper around `Rc<dyn FolderContent>`. Necessary to implement the `Default` trait on this
@ -118,8 +126,11 @@ impl<D:'static + FolderContent> From<D> for AnyFolderContent {
pub struct EmptyFolderContent;
impl FolderContent for EmptyFolderContent {
fn request_entries
(&self, entries_loaded:frp::Any<Rc<Vec<Entry>>>, _error_occured:frp::Any<ImString>) {
fn request_entries(
&self,
entries_loaded: frp::Any<Rc<Vec<Entry>>>,
_error_occured: frp::Any<ImString>,
) {
entries_loaded.emit(Rc::new(vec![]));
}
}

View File

@ -7,9 +7,9 @@ use enso_frp as frp;
use enso_frp;
use ensogl_core::application::Application;
use ensogl_core::data::color;
use ensogl_core::display;
use ensogl_core::display::shape::*;
use ensogl_core::display::traits::*;
use ensogl_core::display;
use ensogl_text as text;
use ensogl_theme::component::label as theme;
@ -174,5 +174,7 @@ impl Label {
}
impl display::Object for Label {
fn display_object(&self) -> &display::object::Instance { &self.model.display_object }
fn display_object(&self) -> &display::object::Instance {
&self.model.display_object
}
}

View File

@ -4,7 +4,6 @@
#![feature(option_result_contains)]
#![feature(trait_alias)]
#![warn(missing_copy_implementations)]
#![warn(missing_debug_implementations)]
#![warn(missing_docs)]
@ -13,7 +12,6 @@
#![warn(unsafe_code)]
#![warn(unused_import_braces)]
#![warn(unused_qualifications)]
#![recursion_limit = "512"]
pub mod component;

View File

@ -10,8 +10,8 @@ use crate::shadow;
use enso_frp as frp;
use ensogl_core::application;
use ensogl_core::application::Application;
use ensogl_core::application::shortcut;
use ensogl_core::application::Application;
use ensogl_core::display;
use ensogl_core::display::scene::layer::LayerId;
use ensogl_core::display::shape::*;
@ -111,7 +111,6 @@ struct Model<E:Entry> {
}
impl<E: Entry> Model<E> {
fn new(app: &Application) -> Self {
let app = app.clone_ref();
let logger = Logger::new("SelectionContainer");
@ -157,12 +156,11 @@ impl<E:Entry> Model<E> {
if entry_count == 0 {
0..0
} else {
let entry_at_y_saturating = |y:f32| {
match entry::List::<E>::entry_at_y_position(y,entry_count) {
let entry_at_y_saturating =
|y: f32| match entry::List::<E>::entry_at_y_position(y, entry_count) {
entry::list::IdAtYPosition::AboveFirst => 0,
entry::list::IdAtYPosition::UnderLast => entry_count - 1,
entry::list::IdAtYPosition::Entry(id) => id,
}
};
let first = entry_at_y_saturating(*position_y);
let last = entry_at_y_saturating(position_y - size.y) + 1;
@ -172,18 +170,25 @@ impl<E:Entry> Model<E> {
/// Check if the `point` is inside component assuming that it have given `size`.
fn is_inside(&self, point: Vector2<f32>, size: Vector2<f32>) -> bool {
let pos_obj_space = self.app.display.scene().screen_to_object_space(&self.background,point);
let pos_obj_space =
self.app.display.scene().screen_to_object_space(&self.background, point);
let x_range = (-size.x / 2.0)..=(size.x / 2.0);
let y_range = (-size.y / 2.0)..=(size.y / 2.0);
x_range.contains(&pos_obj_space.x) && y_range.contains(&pos_obj_space.y)
}
fn selected_entry_after_jump
(&self, current_entry:Option<entry::Id>, jump:isize) -> Option<entry::Id> {
fn selected_entry_after_jump(
&self,
current_entry: Option<entry::Id>,
jump: isize,
) -> Option<entry::Id> {
if jump < 0 {
let current_entry = current_entry?;
if current_entry == 0 { None }
else { Some(current_entry.saturating_sub(-jump as usize)) }
if current_entry == 0 {
None
} else {
Some(current_entry.saturating_sub(-jump as usize))
}
} else {
let max_entry = self.entries.entry_count().checked_sub(1)?;
Some(current_entry.map_or(0, |id| id + (jump as usize)).min(max_entry))
@ -251,11 +256,14 @@ pub struct ListView<E:Entry> {
impl<E: Entry> Deref for ListView<E> {
type Target = Frp<E>;
fn deref(&self) -> &Self::Target { &self.frp }
fn deref(&self) -> &Self::Target {
&self.frp
}
}
impl<E: Entry> ListView<E>
where E::Model : Default {
where E::Model: Default
{
/// Constructor.
pub fn new(app: &Application) -> Self {
let frp = Frp::new();
@ -430,26 +438,40 @@ where E::Model : Default {
}
impl<E: Entry> display::Object for ListView<E> {
fn display_object(&self) -> &display::object::Instance { &self.model.display_object }
fn display_object(&self) -> &display::object::Instance {
&self.model.display_object
}
}
impl<E: Entry> application::command::FrpNetworkProvider for ListView<E> {
fn network(&self) -> &frp::Network { &self.frp.network }
fn network(&self) -> &frp::Network {
&self.frp.network
}
}
impl<E: Entry> application::View for ListView<E> {
fn label() -> &'static str { "ListView" }
fn new(app:&Application) -> Self { ListView::new(app) }
fn app(&self) -> &Application { &self.model.app }
fn label() -> &'static str {
"ListView"
}
fn new(app: &Application) -> Self {
ListView::new(app)
}
fn app(&self) -> &Application {
&self.model.app
}
fn default_shortcuts() -> Vec<shortcut::Shortcut> {
use shortcut::ActionType::*;
(&[ (PressAndRepeat , "up" , "move_selection_up")
, (PressAndRepeat , "down" , "move_selection_down")
, (Press , "page-up" , "move_selection_page_up")
, (Press , "page-down" , "move_selection_page_down")
, (Press , "home" , "move_selection_to_first")
, (Press , "end" , "move_selection_to_last")
, (Press , "enter" , "chose_selected_entry")
]).iter().map(|(a,b,c)|Self::self_shortcut(*a,*b,*c)).collect()
(&[
(PressAndRepeat, "up", "move_selection_up"),
(PressAndRepeat, "down", "move_selection_down"),
(Press, "page-up", "move_selection_page_up"),
(Press, "page-down", "move_selection_page_down"),
(Press, "home", "move_selection_to_first"),
(Press, "end", "move_selection_to_last"),
(Press, "enter", "chose_selected_entry"),
])
.iter()
.map(|(a, b, c)| Self::self_shortcut(*a, *b, *c))
.collect()
}
}

View File

@ -118,7 +118,9 @@ impl Entry for Label {
}
impl display::Object for Label {
fn display_object(&self) -> &display::object::Instance { &self.display_object }
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}
@ -147,7 +149,8 @@ impl Entry for GlyphHighlightedLabel {
fn new(app: &Application) -> Self {
let inner = Label::new(app);
let network = &inner.network;
let highlight_color = inner.style_watch.get_color(theme::widget::list_view::text::highlight);
let highlight_color =
inner.style_watch.get_color(theme::widget::list_view::text::highlight);
let label = &inner.label;
frp::extend! { network
@ -173,7 +176,9 @@ impl Entry for GlyphHighlightedLabel {
}
impl display::Object for GlyphHighlightedLabel {
fn display_object(&self) -> &display::object::Instance { self.inner.display_object() }
fn display_object(&self) -> &display::object::Instance {
self.inner.display_object()
}
}
@ -206,20 +211,34 @@ pub trait ModelProvider<E> : Debug {
#[derive(Debug, Shrinkwrap)]
pub struct AnyModelProvider<E>(Rc<dyn ModelProvider<E>>);
impl<E> Clone for AnyModelProvider<E> { fn clone (&self) -> Self { Self(self.0.clone()) }}
impl<E> CloneRef for AnyModelProvider<E> { fn clone_ref(&self) -> Self { Self(self.0.clone_ref()) }}
impl<E> Clone for AnyModelProvider<E> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<E> CloneRef for AnyModelProvider<E> {
fn clone_ref(&self) -> Self {
Self(self.0.clone_ref())
}
}
impl<E> AnyModelProvider<E> {
/// Create from typed provider.
pub fn new<T:ModelProvider<E>+'static>(provider:T) -> Self { Self(Rc::new(provider)) }
pub fn new<T: ModelProvider<E> + 'static>(provider: T) -> Self {
Self(Rc::new(provider))
}
}
impl<E, T: ModelProvider<E> + 'static> From<Rc<T>> for AnyModelProvider<E> {
fn from(provider:Rc<T>) -> Self { Self(provider) }
fn from(provider: Rc<T>) -> Self {
Self(provider)
}
}
impl<E> Default for AnyModelProvider<E> {
fn default() -> Self { Self::new(EmptyProvider) }
fn default() -> Self {
Self::new(EmptyProvider)
}
}
@ -232,16 +251,23 @@ impl<E> Default for AnyModelProvider<E> {
pub struct EmptyProvider;
impl<E> ModelProvider<E> for EmptyProvider {
fn entry_count(&self) -> usize { 0 }
fn get (&self, _:usize) -> Option<E::Model> where E : Entry { None }
fn entry_count(&self) -> usize {
0
}
fn get(&self, _: usize) -> Option<E::Model>
where E: Entry {
None
}
}
// === ModelProvider for Vectors ===
impl<E, T> ModelProvider<E> for Vec<T>
where E : Entry,
T : Debug + Clone + Into<E::Model> {
where
E: Entry,
T: Debug + Clone + Into<E::Model>,
{
fn entry_count(&self) -> usize {
self.len()
}
@ -277,7 +303,6 @@ impl<E:Debug> ModelProvider<E> for SingleMaskedProvider<E> {
}
impl<E> SingleMaskedProvider<E> {
/// Return the index to the unmasked underlying data. Will only be valid to use after
/// calling `clear_mask`.
///

View File

@ -37,14 +37,19 @@ pub struct DisplayedEntry<E:CloneRef> {
#[allow(missing_docs)]
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub enum IdAtYPosition {
AboveFirst, UnderLast, Entry(entry::Id)
AboveFirst,
UnderLast,
Entry(entry::Id),
}
impl IdAtYPosition {
/// Returns id of entry if present.
pub fn entry(&self) -> Option<entry::Id> {
if let Self::Entry(id) = self { Some(*id) }
else { None }
if let Self::Entry(id) = self {
Some(*id)
} else {
None
}
}
}
@ -63,7 +68,8 @@ pub struct List<E:CloneRef> {
}
impl<E: Entry> List<E>
where E::Model : Default {
where E::Model: Default
{
/// Entry List View constructor.
pub fn new(parent: impl AnyLogger, app: &Application) -> Self {
let app = app.clone_ref();
@ -87,7 +93,9 @@ where E::Model : Default {
}
/// Y position of entry with given id, relative to Entry List position.
pub fn position_y_of_entry(id:entry::Id) -> f32 { id as f32 * -entry::HEIGHT }
pub fn position_y_of_entry(id: entry::Id) -> f32 {
id as f32 * -entry::HEIGHT
}
/// Y range of entry with given id, relative to Entry List position.
pub fn y_range_of_entry(id: entry::Id) -> Range<f32> {
@ -110,9 +118,13 @@ where E::Model : Default {
pub fn entry_at_y_position(y: f32, entry_count: usize) -> IdAtYPosition {
use IdAtYPosition::*;
let all_entries_start = Self::y_range_of_all_entries(entry_count).start;
if y > entry::HEIGHT/2.0 { AboveFirst }
else if y < all_entries_start { UnderLast }
else { Entry((-y/entry::HEIGHT + 0.5) as entry::Id) }
if y > entry::HEIGHT / 2.0 {
AboveFirst
} else if y < all_entries_start {
UnderLast
} else {
Entry((-y / entry::HEIGHT + 0.5) as entry::Id)
}
}
/// Update displayed entries to show the given range.
@ -121,7 +133,8 @@ where E::Model : Default {
if range != self.entries_range.get() {
debug!(self.logger, "Update entries for {range:?}");
let provider = self.provider.get();
let current_entries:HashSet<entry::Id> = with(self.entries.borrow_mut(), |mut entries| {
let current_entries: HashSet<entry::Id> =
with(self.entries.borrow_mut(), |mut entries| {
entries.resize_with(range.len(), || self.create_new_entry());
entries.iter().filter_map(|entry| entry.id.get()).collect()
});
@ -130,7 +143,8 @@ where E::Model : Default {
// methods.
let models = missing.map(|id| (id, provider.get(id)));
with(self.entries.borrow(), |entries| {
let is_outdated = |e:&DisplayedEntry<E>| e.id.get().map_or(true, |i| !range.contains(&i));
let is_outdated =
|e: &DisplayedEntry<E>| e.id.get().map_or(true, |i| !range.contains(&i));
let outdated = entries.iter().filter(|e| is_outdated(e));
for (entry, (id, model)) in outdated.zip(models) {
Self::update_entry(&self.logger, entry, id, &model);
@ -141,14 +155,20 @@ where E::Model : Default {
}
/// Update displayed entries, giving new provider.
pub fn update_entries_new_provider
(&self, provider:impl Into<entry::AnyModelProvider<E>> + 'static, mut range:Range<entry::Id>) {
pub fn update_entries_new_provider(
&self,
provider: impl Into<entry::AnyModelProvider<E>> + 'static,
mut range: Range<entry::Id>,
) {
const MAX_SAFE_ENTRIES_COUNT: usize = 1000;
let provider = provider.into();
if provider.entry_count() > MAX_SAFE_ENTRIES_COUNT {
error!(self.logger, "ListView entry count exceed {MAX_SAFE_ENTRIES_COUNT} - so big \
error!(
self.logger,
"ListView entry count exceed {MAX_SAFE_ENTRIES_COUNT} - so big \
number of entries can cause visual glitches, e.g. https://github.com/enso-org/ide/\
issues/757 or https://github.com/enso-org/ide/issues/758");
issues/757 or https://github.com/enso-org/ide/issues/758"
);
}
range.end = range.end.min(provider.entry_count());
let models = range.clone().map(|id| (id, provider.get(id)));
@ -168,8 +188,11 @@ where E::Model : Default {
entry.entry.set_label_layer(&layer);
}
} else {
error!(self.logger, "Cannot set layer {label_layer:?} for labels: the layer does not \
exist in the scene");
error!(
self.logger,
"Cannot set layer {label_layer:?} for labels: the layer does not \
exist in the scene"
);
}
self.label_layer.set(label_layer);
}
@ -177,23 +200,31 @@ where E::Model : Default {
fn create_new_entry(&self) -> DisplayedEntry<E> {
let layers = &self.app.display.scene().layers;
let layer = layers.get_sublayer(self.label_layer.get()).unwrap_or_else(|| {
error!(self.logger, "Cannot set layer {self.label_layer:?} for labels: the layer does \
not exist in the scene");
error!(
self.logger,
"Cannot set layer {self.label_layer:?} for labels: the layer does \
not exist in the scene"
);
layers.main.clone_ref()
});
let entry = DisplayedEntry {
id : default(),
entry : E::new(&self.app)
};
let entry = DisplayedEntry { id: default(), entry: E::new(&self.app) };
entry.entry.set_label_layer(&layer);
entry.entry.set_position_x(entry::PADDING);
self.add_child(&entry.entry);
entry
}
fn update_entry(logger:&Logger, entry:&DisplayedEntry<E>, id:entry::Id, model:&Option<E::Model>) {
debug!(logger, "Setting new model {model:?} for entry {id}; \
old entry: {entry.id.get():?}.");
fn update_entry(
logger: &Logger,
entry: &DisplayedEntry<E>,
id: entry::Id,
model: &Option<E::Model>,
) {
debug!(
logger,
"Setting new model {model:?} for entry {id}; \
old entry: {entry.id.get():?}."
);
entry.id.set(Some(id));
match model {
Some(model) => entry.entry.update(model),
@ -207,5 +238,7 @@ where E::Model : Default {
}
impl<E: CloneRef> display::Object for List<E> {
fn display_object(&self) -> &display::object::Instance { &self.display_object }
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}

View File

@ -6,11 +6,11 @@ use crate::scrollbar;
use crate::scrollbar::Scrollbar;
use enso_frp as frp;
use ensogl_core::application::Application;
use ensogl_core::control::callback;
use ensogl_core::control::io::mouse;
use ensogl_core::display;
use ensogl_core::display::object::ObjectOps;
use ensogl_core::application::Application;
use ensogl_core::control::io::mouse;
use ensogl_core::control::callback;

View File

@ -3,18 +3,18 @@
use crate::prelude::*;
use enso_frp as frp;
use ensogl_core::Animation;
use ensogl_core::application::Application;
use ensogl_core::application;
use ensogl_core::application::Application;
use ensogl_core::data::color;
use ensogl_core::display::shape::*;
use ensogl_core::display::shape::StyleWatchFrp;
use ensogl_core::display::shape::*;
use ensogl_core::Animation;
use ensogl_theme as theme;
use crate::component;
use crate::selector::Bounds;
use crate::selector::model::Model;
use crate::selector;
use crate::selector::model::Model;
use crate::selector::Bounds;
use ensogl_core::animation::delayed::DelayedAnimation;
@ -71,9 +71,13 @@ ensogl_core::define_endpoints! {
}
impl Frp {
fn compute_target_alpha
(&recently_active:&bool, &dragging:&bool, &cursor_distance:&f32, &thumb_size:&f32, &max:&f32)
-> f32 {
fn compute_target_alpha(
&recently_active: &bool,
&dragging: &bool,
&cursor_distance: &f32,
&thumb_size: &f32,
&max: &f32,
) -> f32 {
let thumb_fills_bar = thumb_size >= max;
if thumb_fills_bar {
0.0
@ -277,7 +281,13 @@ impl component::Frp<Model> for Frp {
pub type Scrollbar = crate::component::Component<Model, Frp>;
impl application::View for Scrollbar {
fn label() -> &'static str { "Scrollbar" }
fn new(app:&Application) -> Self { Scrollbar::new(app) }
fn app(&self) -> &Application { &self.app }
fn label() -> &'static str {
"Scrollbar"
}
fn new(app: &Application) -> Self {
Scrollbar::new(app)
}
fn app(&self) -> &Application {
&self.app
}
}

View File

@ -40,9 +40,15 @@ use model::*;
pub type NumberPicker = crate::component::Component<Model, number::Frp>;
impl application::View for NumberPicker {
fn label() -> &'static str { "NumberPicker" }
fn new(app:&Application) -> Self { NumberPicker::new(app) }
fn app(&self) -> &Application { &self.app }
fn label() -> &'static str {
"NumberPicker"
}
fn new(app: &Application) -> Self {
NumberPicker::new(app)
}
fn app(&self) -> &Application {
&self.app
}
}
@ -63,7 +69,13 @@ impl application::View for NumberPicker {
pub type NumberRangePicker = crate::component::Component<Model, range::Frp>;
impl application::View for NumberRangePicker {
fn label() -> &'static str { "RangePicker" }
fn new(app:&Application) -> Self { NumberRangePicker::new(app) }
fn app(&self) -> &Application { &self.app }
fn label() -> &'static str {
"RangePicker"
}
fn new(app: &Application) -> Self {
NumberRangePicker::new(app)
}
fn app(&self) -> &Application {
&self.app
}
}

View File

@ -66,7 +66,9 @@ impl From<(f32,f32)> for Bounds {
/// ````
pub fn normalise_value((value, bounds): &(f32, Bounds)) -> f32 {
let width = bounds.width();
if width == 0.0 { return 0.0 }
if width == 0.0 {
return 0.0;
}
(value - bounds.start) / width
}
@ -86,7 +88,9 @@ pub fn absolute_value((bounds,normalised_value):&(Bounds,f32)) -> f32 {
/// For use in FRP `map` method, thus taking references.
#[allow(clippy::trivially_copy_pass_by_ref)]
pub fn position_to_normalised_value(pos: &Vector2, width: &f32) -> f32 {
if *width == 0.0 { return 0.0 }
if *width == 0.0 {
return 0.0;
}
((pos.x / (width / 2.0)) + 1.0) / 2.0
}
@ -303,8 +307,11 @@ mod tests {
fn test_bounds_in_bounds() {
let test = |start1, end1, start2, end2, expected| {
let result = bounds_in_bounds(Bounds::new(start1, start2), Bounds::new(start2, end2));
assert_eq!(result,expected,
"Testing whether ]{},{}[ in ]{},{}[", start1,end1,start2,end2);
assert_eq!(
result, expected,
"Testing whether ]{},{}[ in ]{},{}[",
start1, end1, start2, end2
);
};
test(0.0, 1.0, 0.0, 1.0, true);

View File

@ -7,11 +7,11 @@ use crate::prelude::*;
use crate::component;
use enso_frp as frp;
use ensogl_core::application::Application;
use ensogl_core::application;
use ensogl_core::application::Application;
use ensogl_core::display;
use ensogl_core::display::object::ObjectOps;
use ensogl_core::display::shape::StyleWatchFrp;
use ensogl_core::display;
use ensogl_text as text;
@ -94,14 +94,22 @@ impl component::Frp<Model> for Frp {
}
impl display::Object for Model {
fn display_object(&self) -> &display::object::Instance { self.root.display_object() }
fn display_object(&self) -> &display::object::Instance {
self.root.display_object()
}
}
/// Decimal aligned text label that shows the text representation of a floating point number.
pub type FloatLabel = component::Component<Model, Frp>;
impl application::View for FloatLabel {
fn label() -> &'static str { "FloatLabel" }
fn new(app:&Application) -> Self { FloatLabel::new(app) }
fn app(&self) -> &Application { &self.app }
fn label() -> &'static str {
"FloatLabel"
}
fn new(app: &Application) -> Self {
FloatLabel::new(app)
}
fn app(&self) -> &Application {
&self.app
}
}

View File

@ -12,8 +12,8 @@ use ensogl_theme as theme;
use crate::shadow;
use super::model::Model;
use super::shape::shape_is_dragged;
use super::shape::relative_shape_down_position;
use super::shape::shape_is_dragged;
@ -67,29 +67,31 @@ pub struct Frp {
}
impl Frp {
pub fn new
(model:&Model, style:&StyleWatchFrp, network:&Network, size:frp::Stream<Vector2>, mouse:&Mouse)
-> Frp {
pub fn new(
model: &Model,
style: &StyleWatchFrp,
network: &Network,
size: frp::Stream<Vector2>,
mouse: &Mouse,
) -> Frp {
let shadow = shadow::frp_from_style(style, theme::shadow);
let text_size = style.get_number(theme::text::size);
let is_dragging_left_overflow = shape_is_dragged(
network,&model.left_overflow.events,mouse);
let is_dragging_right_overflow = shape_is_dragged(
network,&model.right_overflow.events,mouse);
let is_dragging_track = shape_is_dragged(
network,&model.track.events, mouse);
let is_dragging_background = shape_is_dragged(
network,&model.background.events,mouse);
let is_dragging_left_handle = shape_is_dragged(
network,&model.track_handle_left.events,mouse);
let is_dragging_right_handle = shape_is_dragged(
network,&model.track_handle_right.events,mouse);
let is_dragging_left_overflow =
shape_is_dragged(network, &model.left_overflow.events, mouse);
let is_dragging_right_overflow =
shape_is_dragged(network, &model.right_overflow.events, mouse);
let is_dragging_track = shape_is_dragged(network, &model.track.events, mouse);
let is_dragging_background = shape_is_dragged(network, &model.background.events, mouse);
let is_dragging_left_handle =
shape_is_dragged(network, &model.track_handle_left.events, mouse);
let is_dragging_right_handle =
shape_is_dragged(network, &model.track_handle_right.events, mouse);
let background_click = relative_shape_down_position(
network,model.app.display.scene(),&model.background);
let track_click = relative_shape_down_position(
network,model.app.display.scene(),&model.track);
let background_click =
relative_shape_down_position(network, model.app.display.scene(), &model.background);
let track_click =
relative_shape_down_position(network, model.app.display.scene(), &model.track);
// Initialisation of components. Required for correct layout on startup.
model.label_right.set_position_y(text_size.value() / 2.0);
@ -142,8 +144,18 @@ impl Frp {
init_shadow_padding.emit(());
Frp {track_max_width,is_dragging_left_overflow,is_dragging_right_overflow,
is_dragging_track,is_dragging_background,is_dragging_left_handle,
is_dragging_right_handle,is_dragging_any,background_click,track_click,track_hover}
Frp {
track_max_width,
is_dragging_left_overflow,
is_dragging_right_overflow,
is_dragging_track,
is_dragging_background,
is_dragging_left_handle,
is_dragging_right_handle,
is_dragging_any,
background_click,
track_click,
track_hover,
}
}
}

View File

@ -11,9 +11,9 @@ use ensogl_text as text;
use crate::component;
use super::Bounds;
use super::shape::*;
use super::decimal_aligned::FloatLabel;
use super::shape::*;
use super::Bounds;
@ -120,10 +120,26 @@ impl component::Model for Model {
caption_center.remove_from_scene_layer(&scene.layers.main);
caption_center.add_to_scene_layer(&scene.layers.label);
Self{background,track,track_handle_left,track_handle_right,left_overflow,right_overflow,
label,label_left,label_right,caption_left,caption_center,root,background_color,
track_color,background_left_corner_roundness,background_right_corner_roundness,padding,
app}
Self {
background,
track,
track_handle_left,
track_handle_right,
left_overflow,
right_overflow,
label,
label_left,
label_right,
caption_left,
caption_center,
root,
background_color,
track_color,
background_left_corner_roundness,
background_right_corner_roundness,
padding,
app,
}
}
}
@ -274,8 +290,10 @@ impl Model {
if value {
self.background.show_shadow.set(1.0);
self.background.color.set(self.background_color.as_ref().clone().into_inner().into());
let left_corner_roundness = if self.background_left_corner_roundness.get() { 1.0 } else { 0.0 };
let right_corner_roundness = if self.background_right_corner_roundness.get() { 1.0 } else { 0.0 };
let left_corner_roundness =
if self.background_left_corner_roundness.get() { 1.0 } else { 0.0 };
let right_corner_roundness =
if self.background_right_corner_roundness.get() { 1.0 } else { 0.0 };
self.track.corner_right.set(right_corner_roundness);
self.track.corner_left.set(left_corner_roundness);
} else {
@ -288,5 +306,7 @@ impl Model {
}
impl display::Object for Model {
fn display_object(&self) -> &display::object::Instance { &self.root }
fn display_object(&self) -> &display::object::Instance {
&self.root
}
}

View File

@ -2,21 +2,21 @@
use crate::prelude::*;
use enso_frp as frp;
use ensogl_core::data::color;
use ensogl_core::application::Application;
use ensogl_core::display::shape::*;
use ensogl_core::data::color;
use ensogl_core::display::shape::StyleWatchFrp;
use ensogl_core::display::shape::*;
use ensogl_theme as theme;
use crate::component;
use crate::selector::shape::*;
use super::Bounds;
use super::bounds::absolute_value;
use super::bounds::clamp_with_overflow;
use super::bounds::normalise_value;
use super::bounds::position_to_normalised_value;
use super::shape::relative_shape_down_position;
use super::model::Model;
use super::shape::relative_shape_down_position;
use super::Bounds;
use crate::component;
use crate::selector::shape::*;
@ -56,10 +56,10 @@ impl component::Frp<Model> for Frp {
let track_shape_system = scene.shapes.shape_system(PhantomData::<track::Shape>);
track_shape_system.shape_system.set_pointer_events(false);
let background_click = relative_shape_down_position(
network,model.app.display.scene(),&model.background);
let track_click = relative_shape_down_position(
network,model.app.display.scene(),&model.track);
let background_click =
relative_shape_down_position(network, model.app.display.scene(), &model.background);
let track_click =
relative_shape_down_position(network, model.app.display.scene(), &model.track);
let style_track_color = style.get_color(theme::component::slider::track::color);

View File

@ -2,19 +2,19 @@
use crate::prelude::*;
use enso_frp as frp;
use ensogl_core::data::color;
use ensogl_core::application::Application;
use ensogl_core::display::shape::*;
use ensogl_core::data::color;
use ensogl_core::display::shape::StyleWatchFrp;
use ensogl_core::display::shape::*;
use ensogl_theme as theme;
use crate::component;
use super::Model;
use super::Bounds;
use super::bounds::absolute_value;
use super::bounds::normalise_value;
use super::bounds::should_clamp_with_overflow;
use super::Bounds;
use super::Model;
@ -131,6 +131,5 @@ impl component::Frp<Model> for Frp {
frp.set_left_corner_round(true);
frp.set_right_corner_round(true);
frp.set_track_color(style_track_color.value());
}
}

View File

@ -26,8 +26,7 @@ struct Background {
}
impl Background {
fn new(corner_left:&Var<f32>, corner_right:&Var<f32>, style:&StyleWatch)
-> Background {
fn new(corner_left: &Var<f32>, corner_right: &Var<f32>, style: &StyleWatch) -> Background {
let sprite_width: Var<Pixels> = "input_size.x".into();
let sprite_height: Var<Pixels> = "input_size.y".into();
@ -36,7 +35,8 @@ impl Background {
let corner_radius = &height / 2.0;
let rect_left = Rect((&width / 2.0, &height)).corners_radius(&corner_radius * corner_left);
let rect_left = rect_left.translate_x(-&width / 4.0);
let rect_right = Rect((&width/2.0,&height)).corners_radius(&corner_radius*corner_right);
let rect_right =
Rect((&width / 2.0, &height)).corners_radius(&corner_radius * corner_right);
let rect_right = rect_right.translate_x(&width / 4.0);
let rect_center = Rect((&corner_radius * 2.0, &height));
@ -137,7 +137,7 @@ struct OverflowShape {
#[allow(dead_code)]
// This field is not used but should stay as part of the API for future use.
pub height: Var<Pixels>,
pub shape : AnyShape
pub shape: AnyShape,
}
impl OverflowShape {
@ -207,8 +207,11 @@ use ensogl_core::display::Scene;
/// Return whether a dragging action has been started from the shape passed to this function. A
/// dragging action is started by a mouse down on the shape, followed by a movement of the mouse.
/// Dragging is ended by a mouse up.
pub fn shape_is_dragged
(network:&Network, shape:&ShapeViewEvents, mouse:&Mouse) -> enso_frp::Stream<bool> {
pub fn shape_is_dragged(
network: &Network,
shape: &ShapeViewEvents,
mouse: &Mouse,
) -> enso_frp::Stream<bool> {
enso_frp::extend! { network
mouse_up <- mouse.up.constant(());
mouse_down <- mouse.down.constant(());
@ -221,10 +224,10 @@ pub fn shape_is_dragged
/// Returns the position of a mouse down on a shape. The position is given in the shape's local
/// coordinate system
pub fn relative_shape_down_position<T:'static+display::Object+CloneRef>
( network : &Network
, scene : &Scene
, shape : &ShapeView<T>
pub fn relative_shape_down_position<T: 'static + display::Object + CloneRef>(
network: &Network,
scene: &Scene,
shape: &ShapeView<T>,
) -> enso_frp::Stream<Vector2> {
let mouse = &scene.mouse.frp;
enso_frp::extend! { network

View File

@ -2,10 +2,10 @@
use crate::prelude::*;
use ensogl_core::data::color;
use ensogl_core::display::DomSymbol;
use ensogl_core::display::shape::*;
use ensogl_core::display::shape::AnyShape;
use ensogl_core::display::shape::*;
use ensogl_core::display::style;
use ensogl_core::display::DomSymbol;
use ensogl_core::frp;
use ensogl_core::system::web::StyleSetter;
use ensogl_theme as theme;
@ -20,7 +20,7 @@ pub struct Parameters {
spread: f32,
exponent: f32,
offset_x: f32,
offset_y : f32
offset_y: f32,
}
/// Loads shadow parameters from the given style, at the given path. The structure of the style
@ -34,7 +34,7 @@ pub fn parameters_from_style_path(style:&StyleWatch,path:impl Into<style::Path>)
spread: style.get_number(&path.sub("spread")),
exponent: style.get_number(&path.sub("exponent")),
offset_x: style.get_number(&path.sub("offset_x")),
offset_y: style.get_number(&path.sub("offset_y"))
offset_y: style.get_number(&path.sub("offset_y")),
}
}
@ -53,7 +53,11 @@ pub fn from_shape(base_shape:AnyShape, style:&StyleWatch) -> AnyShape {
/// Return a shadow for the given shape. Exact appearance will depend on the theme parameters.
/// The color will be multiplied with the given alpha value, which is useful for fade-in/out
/// animations.
pub fn from_shape_with_alpha(base_shape:AnyShape,alpha:&Var<f32>,style:&StyleWatch) -> AnyShape {
pub fn from_shape_with_alpha(
base_shape: AnyShape,
alpha: &Var<f32>,
style: &StyleWatch,
) -> AnyShape {
let parameters = parameters_from_style_path(style, theme::shadow);
from_shape_with_parameters_and_alpha(base_shape, parameters, alpha)
}
@ -66,9 +70,11 @@ pub fn from_shape_with_parameters(base_shape:AnyShape,parameters:Parameters) ->
/// Return a shadow for the given shape, shadow parameters and alpha. As in `from_shape_with_alpha`,
/// the shadow colors will be multiplied with the given alpha value.
pub fn from_shape_with_parameters_and_alpha
(base_shape:AnyShape,parameters:Parameters,alpha:&Var<f32>)
-> AnyShape {
pub fn from_shape_with_parameters_and_alpha(
base_shape: AnyShape,
parameters: Parameters,
alpha: &Var<f32>,
) -> AnyShape {
let grow = Var::<f32>::from(parameters.size);
let shadow = base_shape.grow(grow);
let shadow = shadow.translate((parameters.offset_x.px(), parameters.offset_y.px()));
@ -79,9 +85,14 @@ pub fn from_shape_with_parameters_and_alpha
let fading_color = Var::<color::Rgba>::from(parameters.fading);
let fading_color = fading_color.multiply_alpha(alpha);
let shadow_color = color::gradient::Linear::<Var<color::LinearRgba>>
::new(fading_color.into_linear(),base_color.into_linear());
let shadow_color = shadow_color.sdf_sampler().size(parameters.size).spread(parameters.spread)
let shadow_color = color::gradient::Linear::<Var<color::LinearRgba>>::new(
fading_color.into_linear(),
base_color.into_linear(),
);
let shadow_color = shadow_color
.sdf_sampler()
.size(parameters.size)
.spread(parameters.spread)
.exponent(parameters.exponent);
let shadow = shadow.fill(shadow_color);
shadow.into()
@ -109,7 +120,7 @@ pub struct ParametersFrp {
pub spread: frp::Sampler<f32>,
pub exponent: frp::Sampler<f32>,
pub offset_x: frp::Sampler<f32>,
pub offset_y : frp::Sampler<f32>
pub offset_y: frp::Sampler<f32>,
}
/// Return FRP endpoints for the parameters that define a shadow.
@ -122,6 +133,6 @@ pub fn frp_from_style(style:&StyleWatchFrp,path:impl Into<style::Path>) -> Param
spread: style.get_number(&path.sub("spread")),
exponent: style.get_number(&path.sub("exponent")),
offset_x: style.get_number(&path.sub("offset_x")),
offset_y : style.get_number(&path.sub("offset_y"))
offset_y: style.get_number(&path.sub("offset_y")),
}
}

View File

@ -13,7 +13,6 @@ use ensogl_core::display::shape::system::DynamicShapeInternals;
// =================
// === Colorable ===
// =================

View File

@ -16,8 +16,8 @@ pub use loops::*;
// === Utils ===
// =============
use std::ops::Mul;
use std::ops::Add;
use std::ops::Mul;
/// A generic trait constraint for interpolable types.
pub trait Interpolable<T: Copy> = Mul<f32, Output = T> + Add<T, Output = T> + Copy;

View File

@ -26,7 +26,8 @@ pub trait AnyFnEasing = 'static + Fn(f32) -> f32;
pub trait CloneableFnEasing = 'static + Clone + Fn(f32) -> f32;
macro_rules! define_in_out_easing_fn {
(fn $tname:ident $name:ident $lambda:expr) => { paste::item! {
(fn $tname:ident $name:ident $lambda:expr) => {
paste::item! {
/// A $name-in function type.
pub type [<$tname In>] = impl Clone + Fn(f32) -> f32;
/// A $name-out function type.
@ -49,7 +50,8 @@ macro_rules! define_in_out_easing_fn {
// impl Default for [<$tname In>] { fn default() -> Self { [<$name _in>]() } }
// impl Default for [<$tname Out>] { fn default() -> Self { [<$name _out>]() } }
// impl Default for [<$tname InOut>] { fn default() -> Self { [<$name _in_out>]() } }
}};
}
};
}
macro_rules! define_in_out_easing_fns {
@ -87,10 +89,14 @@ define_in_out_easing_fns! {
pub type Linear = impl Clone + Fn(f32) -> f32;
/// Linear transition.
pub fn linear() -> Linear { |t| { t } }
pub fn linear() -> Linear {
|t| t
}
/// A back-in transition with params.
pub fn back_in_params(t:f32, overshoot:f32) -> f32 { t * t * ((overshoot + 1.0) * t - overshoot) }
pub fn back_in_params(t: f32, overshoot: f32) -> f32 {
t * t * ((overshoot + 1.0) * t - overshoot)
}
/// A back-out transition with params.
pub fn back_out_params(t: f32, overshoot: f32) -> f32 {
@ -191,7 +197,11 @@ pub struct AnimatorData<T,F,OnStep,OnEnd> {
}
impl<T: Value, F, OnStep, OnEnd> AnimatorData<T, F, OnStep, OnEnd>
where F:AnyFnEasing, OnStep:Callback<T>, OnEnd:Callback<EndStatus> {
where
F: AnyFnEasing,
OnStep: Callback<T>,
OnEnd: Callback<EndStatus>,
{
fn new(start: T, end: T, tween_fn: F, callback: OnStep, on_end: OnEnd) -> Self {
let duration = Cell::new(1000.0);
let value = Cell::new(start);
@ -216,7 +226,11 @@ where F:AnyFnEasing, OnStep:Callback<T>, OnEnd:Callback<EndStatus> {
}
impl<T: Value, F, OnStep, OnEnd> Animator<T, F, OnStep, OnEnd>
where F:AnyFnEasing, OnStep:Callback<T>, OnEnd:Callback<EndStatus> {
where
F: AnyFnEasing,
OnStep: Callback<T>,
OnEnd: Callback<EndStatus>,
{
/// Constructor.
pub fn new_not_started(start: T, end: T, tween_fn: F, callback: OnStep, on_end: OnEnd) -> Self {
let data = Rc::new(AnimatorData::new(start, end, tween_fn, callback, on_end));
@ -306,7 +320,11 @@ where F:AnyFnEasing, OnStep:Callback<T>, OnEnd:Callback<EndStatus> {
#[allow(missing_docs)]
impl<T: Value, F, OnStep, OnEnd> Animator<T, F, OnStep, OnEnd>
where F:AnyFnEasing, OnStep:Callback<T>, OnEnd:Callback<EndStatus> {
where
F: AnyFnEasing,
OnStep: Callback<T>,
OnEnd: Callback<EndStatus>,
{
pub fn start_value(&self) -> T {
self.data.start_value.get()
}
@ -388,8 +406,13 @@ pub type AnimationStep<T,F,OnStep,OnEnd> = animation::Loop<Step<T,F,OnStep,OnEnd
/// Callback for an animation step.
pub type Step<T, F, OnStep, OnEnd> = impl Fn(animation::TimeInfo);
fn step<T:Value,F,OnStep,OnEnd>(easing:&Animator<T,F,OnStep,OnEnd>) -> Step<T,F,OnStep,OnEnd>
where F:AnyFnEasing, OnStep:Callback<T>, OnEnd:Callback<EndStatus> {
fn step<T: Value, F, OnStep, OnEnd>(
easing: &Animator<T, F, OnStep, OnEnd>,
) -> Step<T, F, OnStep, OnEnd>
where
F: AnyFnEasing,
OnStep: Callback<T>,
OnEnd: Callback<EndStatus>, {
let data = easing.data.clone_ref();
let animation_loop = easing.animation_loop.downgrade();
move |time: animation::TimeInfo| {

View File

@ -1,7 +1,7 @@
//! FRP bindings to the animation engine.
pub mod hysteretic;
pub mod delayed;
pub mod hysteretic;
use crate::prelude::*;
@ -45,7 +45,8 @@ pub struct Animation<T:mix::Mixable+frp::Data> {
#[allow(missing_docs)]
impl<T: mix::Mixable + frp::Data> Animation<T>
where mix::Repr<T> : inertia::Value {
where mix::Repr<T>: inertia::Value
{
/// Constructor. The initial value of the animation is set to `default`.
pub fn new(network: &frp::Network) -> Self {
frp::extend! { network
@ -127,7 +128,8 @@ pub struct DEPRECATED_Animation<T:mix::Mixable> {
#[allow(missing_docs)]
impl<T: mix::Mixable + frp::Data> DEPRECATED_Animation<T>
where mix::Repr<T> : inertia::Value {
where mix::Repr<T>: inertia::Value
{
/// Constructor.
pub fn new(network: &frp::Network) -> Self {
frp::extend! { network

View File

@ -16,7 +16,6 @@
//! the time the cursor is between icons is less than the `end_delay_duration`. Instead, the hiding
//! will only start iof the cursos has left any icon triggering the pop-up for longer than the
//! `end_delay_duration`.
//!
use crate::prelude::*;
use crate::Animation;

View File

@ -51,8 +51,11 @@ impl Easing {
Self { frp }.init(network, &animator)
}
fn init
(self, network:&frp::Network, animator:&easing::DynAnimator<f32,easing::QuadInOut>) -> Self {
fn init(
self,
network: &frp::Network,
animator: &easing::DynAnimator<f32, easing::QuadInOut>,
) -> Self {
let frp = &self.frp;
frp::extend! { network
eval frp.set_duration ((t) animator.set_duration(*t));

View File

@ -62,7 +62,8 @@ pub struct RawLoop<Callback> {
}
impl<Callback> RawLoop<Callback>
where Callback : RawLoopCallback {
where Callback: RawLoopCallback
{
/// Create and start a new animation loop.
pub fn new(callback: Callback) -> Self {
let data = Rc::new(RefCell::new(RawLoopData::new(callback)));
@ -135,7 +136,8 @@ pub struct Loop<Callback> {
}
impl<Callback> Loop<Callback>
where Callback : LoopCallback {
where Callback: LoopCallback
{
/// Constructor.
pub fn new(callback: Callback) -> Self {
let time_info = Rc::new(Cell::new(TimeInfo::new()));
@ -146,8 +148,13 @@ where Callback : LoopCallback {
/// Callback for an animation frame.
pub type OnFrame<Callback> = impl FnMut(f32);
fn on_frame<Callback>(mut callback:Callback, time_info_ref:Rc<Cell<TimeInfo>>) -> OnFrame<Callback>
where Callback : LoopCallback {
fn on_frame<Callback>(
mut callback: Callback,
time_info_ref: Rc<Cell<TimeInfo>>,
) -> OnFrame<Callback>
where
Callback: LoopCallback,
{
move |current_time: f32| {
let time_info = time_info_ref.get();
let start = if time_info.start == 0.0 { current_time } else { time_info.start };
@ -200,7 +207,7 @@ impl<Callback:FnMut<(TimeInfo,)>> FnMut<(TimeInfo,)> for FixedFrameRateSampler<C
self.time_buffer += time.frame;
loop {
if self.time_buffer < 0.0 {
break
break;
} else {
self.time_buffer -= self.frame_time;
let start = time.start;
@ -224,7 +231,8 @@ impl<Callback:FnMut<(TimeInfo,)>> FnMut<(TimeInfo,)> for FixedFrameRateSampler<C
pub type FixedFrameRateLoop<Callback> = Loop<FixedFrameRateSampler<Callback>>;
impl<Callback> FixedFrameRateLoop<Callback>
where Callback:LoopCallback {
where Callback: LoopCallback
{
/// Constructor.
pub fn new_with_fixed_frame_rate(frame_rate: f32, callback: Callback) -> Self {
Self::new(FixedFrameRateSampler::new(frame_rate, callback))
@ -265,8 +273,7 @@ impl Default for DynamicLoop {
fn default() -> Self {
let data = Rc::new(RefCell::new(DynamicLoopData::default()));
let weak = Rc::downgrade(&data);
let raw_loop : Loop<Box<dyn FnMut(TimeInfo)>> =
Loop::new(Box::new(move |time| {
let raw_loop: Loop<Box<dyn FnMut(TimeInfo)>> = Loop::new(Box::new(move |time| {
weak.upgrade().for_each(|data| {
let mut data_mut = data.borrow_mut();
data_mut.on_before_frame.run_all(time);

View File

@ -16,8 +16,9 @@ use crate::data::function::Fn1;
/// The type of the value of the simulation. In particular, the Value could be `f32`
/// (1-dimensional simulation), or `Vector3<f32>` (3-dimensional simulation).
pub trait Value
= 'static + Copy + Default
pub trait Value = 'static
+ Copy
+ Default
+ PartialEq
+ Normalize
+ Magnitude<Output = f32>
@ -34,7 +35,7 @@ macro_rules! define_f32_opr_mods {
($name:ident $opr:ident $f:ident) => {
define_f32_opr_mods_lhs! {$name $opr $f}
define_f32_opr_mods_rhs! {$name $opr $f}
}
};
}
macro_rules! define_f32_opr_mods_lhs {
@ -66,7 +67,7 @@ macro_rules! define_f32_opr_mods_lhs {
$name { value: self.$f(rhs.value) }
}
}
}
};
}
macro_rules! define_f32_opr_mods_rhs {
@ -98,7 +99,7 @@ macro_rules! define_f32_opr_mods_rhs {
$name { value: self.value.$f(rhs) }
}
}
}
};
}
macro_rules! define_self_opr_mods {
@ -130,7 +131,7 @@ macro_rules! define_self_opr_mods {
$name { value: self.value.$f(rhs.value) }
}
}
}
};
}
macro_rules! define_property {
@ -178,7 +179,7 @@ define_property! { Mass = 30.0 }
#[allow(missing_docs)]
pub struct Thresholds {
pub distance: f32,
pub speed : f32
pub speed: f32,
}
impl Default for Thresholds {
@ -223,19 +224,19 @@ pub struct SimulationData<T> {
// We store the current value as an offset from the target rather than an absolute value. This
// reduces numerical errors when animating floating point numbers: The offset will become very
// small towards the end of the animation. Small floating point numbers offer higher precision
// than large ones, because more digits can be used behind the point, for the fractional part of
// the number. This higher precision helps us to avoid non-termination that could otherwise
// happen due to rounding errors in our `step` function.
// than large ones, because more digits can be used behind the point, for the fractional part
// of the number. This higher precision helps us to avoid non-termination that could
// otherwise happen due to rounding errors in our `step` function.
//
// For example: The precision of `f32` values is so low that we can only represent every second
// integer above 16 777 216. If we simulate values that large and represented the simulation's
// state by its current total value then this internal state would have to jump over those gaps.
// The animation would either become to fast (if we rounded the steps up) or slow down too early
// (if we rounded the steps down). Generally, it would be difficult to handle the rounding
// errors gracefully. By representing the state as an offset, we achieve the highest possible
// precision as the animation approaches its target. Large rounding errors might only happen
// when the simulation is still far away from the target. But in those situations, high
// precision is not as important.
// state by its current total value then this internal state would have to jump over those
// gaps. The animation would either become to fast (if we rounded the steps up) or slow
// down too early (if we rounded the steps down). Generally, it would be difficult to
// handle the rounding errors gracefully. By representing the state as an offset, we
// achieve the highest possible precision as the animation approaches its target. Large
// rounding errors might only happen when the simulation is still far away from the target.
// But in those situations, high precision is not as important.
offset_from_target: T,
target_value: T,
velocity: T,
@ -300,14 +301,30 @@ impl<T:Value> SimulationData<T> {
#[allow(missing_docs)]
impl<T: Value> SimulationData<T> {
pub fn value (&self) -> T { self.target_value + self.offset_from_target }
pub fn target_value (&self) -> T { self.target_value }
pub fn velocity (&self) -> T { self.velocity }
pub fn mass (&self) -> Mass { self.mass }
pub fn spring (&self) -> Spring { self.spring }
pub fn drag (&self) -> Drag { self.drag }
pub fn thresholds (&self) -> Thresholds { self.thresholds }
pub fn active (&self) -> bool { self.active }
pub fn value(&self) -> T {
self.target_value + self.offset_from_target
}
pub fn target_value(&self) -> T {
self.target_value
}
pub fn velocity(&self) -> T {
self.velocity
}
pub fn mass(&self) -> Mass {
self.mass
}
pub fn spring(&self) -> Spring {
self.spring
}
pub fn drag(&self) -> Drag {
self.drag
}
pub fn thresholds(&self) -> Thresholds {
self.thresholds
}
pub fn active(&self) -> bool {
self.active
}
}
@ -315,11 +332,21 @@ impl<T:Value> SimulationData<T> {
#[allow(missing_docs)]
impl<T: Value> SimulationData<T> {
pub fn set_velocity (&mut self, velocity:T) { self.velocity = velocity; }
pub fn set_mass (&mut self, mass:Mass) { self.mass = mass; }
pub fn set_spring (&mut self, spring:Spring) { self.spring = spring; }
pub fn set_drag (&mut self, drag:Drag) { self.drag = drag; }
pub fn set_thresholds (&mut self, thresholds:Thresholds) { self.thresholds = thresholds; }
pub fn set_velocity(&mut self, velocity: T) {
self.velocity = velocity;
}
pub fn set_mass(&mut self, mass: Mass) {
self.mass = mass;
}
pub fn set_spring(&mut self, spring: Spring) {
self.spring = spring;
}
pub fn set_drag(&mut self, drag: Drag) {
self.drag = drag;
}
pub fn set_thresholds(&mut self, thresholds: Thresholds) {
self.thresholds = thresholds;
}
pub fn set_value(&mut self, value: T) {
self.active = true;
@ -382,7 +409,7 @@ impl<T:Value> SimulationData<T> {
#[derive(Derivative, Default)]
#[derivative(Debug(bound = "T:Copy+Debug"))]
pub struct SimulationDataCell<T> {
data : Cell<SimulationData<T>>
data: Cell<SimulationData<T>>,
}
impl<T: Value> SimulationDataCell<T> {
@ -435,51 +462,87 @@ impl<T:Value> SimulationDataCell<T> {
#[allow(missing_docs)]
impl<T: Value> SimulationDataCell<T> {
pub fn set_drag(&self, drag: Drag) {
self.data.update(|mut sim| {sim.set_drag(drag); sim});
self.data.update(|mut sim| {
sim.set_drag(drag);
sim
});
}
pub fn update_drag<F: FnOnce(Drag) -> Drag>(&self, f: F) {
self.data.update(|mut sim| {sim.update_drag(f); sim});
self.data.update(|mut sim| {
sim.update_drag(f);
sim
});
}
pub fn set_spring(&self, spring: Spring) {
self.data.update(|mut sim| {sim.set_spring(spring); sim});
self.data.update(|mut sim| {
sim.set_spring(spring);
sim
});
}
pub fn update_spring<F: FnOnce(Spring) -> Spring>(&self, f: F) {
self.data.update(|mut sim| {sim.update_spring(f); sim});
self.data.update(|mut sim| {
sim.update_spring(f);
sim
});
}
pub fn set_mass(&self, mass: Mass) {
self.data.update(|mut sim| {sim.set_mass(mass); sim});
self.data.update(|mut sim| {
sim.set_mass(mass);
sim
});
}
pub fn update_mass<F: FnOnce(Mass) -> Mass>(&self, f: F) {
self.data.update(|mut sim| {sim.update_mass(f); sim});
self.data.update(|mut sim| {
sim.update_mass(f);
sim
});
}
pub fn set_velocity(&self, velocity: T) {
self.data.update(|mut sim| {sim.set_velocity(velocity); sim});
self.data.update(|mut sim| {
sim.set_velocity(velocity);
sim
});
}
pub fn set_value(&self, value: T) {
self.data.update(|mut sim| {sim.set_value(value); sim});
self.data.update(|mut sim| {
sim.set_value(value);
sim
});
}
pub fn set_target_value(&self, target_value: T) {
self.data.update(|mut sim| {sim.set_target_value(target_value); sim});
self.data.update(|mut sim| {
sim.set_target_value(target_value);
sim
});
}
pub fn update_target_value<F: FnOnce(T) -> T>(&self, f: F) {
self.data.update(|mut sim| {sim.update_target_value(f); sim});
self.data.update(|mut sim| {
sim.update_target_value(f);
sim
});
}
pub fn set_precision(&self, precision: f32) {
self.data.update(|mut sim| {sim.set_precision(precision); sim});
self.data.update(|mut sim| {
sim.set_precision(precision);
sim
});
}
pub fn skip(&self) {
self.data.update(|mut sim| {sim.skip(); sim});
self.data.update(|mut sim| {
sim.skip();
sim
});
}
}
@ -521,7 +584,12 @@ impl<T,OnStep,OnStart,OnEnd> Deref for SimulatorData<T,OnStep,OnStart,OnEnd> {
}
impl<T, OnStep, OnStart, OnEnd> SimulatorData<T, OnStep, OnStart, OnEnd>
where T:Value, OnStep:Callback1<T>, OnStart:Callback0, OnEnd:Callback1<EndStatus> {
where
T: Value,
OnStep: Callback1<T>,
OnStart: Callback0,
OnEnd: Callback1<EndStatus>,
{
/// Constructor.
pub fn new(on_step: OnStep, on_start: OnStart, on_end: OnEnd) -> Self {
let simulation = SimulationDataCell::new();
@ -569,7 +637,12 @@ impl<T,OnStep,OnStart,OnEnd> Deref for Simulator<T,OnStep,OnStart,OnEnd> {
}
impl<T, OnStep, OnStart, OnEnd> Simulator<T, OnStep, OnStart, OnEnd>
where T:Value, OnStep:Callback1<T>, OnStart:Callback0, OnEnd:Callback1<EndStatus> {
where
T: Value,
OnStep: Callback1<T>,
OnStart: Callback0,
OnEnd: Callback1<EndStatus>,
{
/// Constructor.
pub fn new(callback: OnStep, on_start: OnStart, on_end: OnEnd) -> Self {
let data = Rc::new(SimulatorData::new(callback, on_start, on_end));
@ -589,7 +662,12 @@ impl<T,OnStep,OnStart,OnEnd> Debug for Simulator<T,OnStep,OnStart,OnEnd> {
#[allow(missing_docs)]
impl<T, OnStep, OnStart, OnEnd> Simulator<T, OnStep, OnStart, OnEnd>
where T:Value, OnStep:Callback1<T>, OnStart:Callback0, OnEnd:Callback1<EndStatus> {
where
T: Value,
OnStep: Callback1<T>,
OnStart: Callback0,
OnEnd: Callback1<EndStatus>,
{
pub fn set_value(&self, value: T) {
self.simulation.set_value(value);
self.start();
@ -611,7 +689,12 @@ where T:Value, OnStep:Callback1<T>, OnStart:Callback0, OnEnd:Callback1<EndStatus
// === Private API ===
impl<T, OnStep, OnStart, OnEnd> Simulator<T, OnStep, OnStart, OnEnd>
where T:Value, OnStep:Callback1<T>, OnStart:Callback0, OnEnd:Callback1<EndStatus> {
where
T: Value,
OnStep: Callback1<T>,
OnStart: Callback0,
OnEnd: Callback1<EndStatus>,
{
fn init(self) -> Self {
self.start();
self
@ -700,9 +783,14 @@ pub type FixedFrameRateAnimationStep<T,OnStep,OnStart,OnEnd> =
/// Callback for an animation step.
pub type Step<T, OnStep, OnStart, OnEnd> = impl Fn(animation::TimeInfo);
fn step<T,OnStep,OnStart,OnEnd>(simulator:&Simulator<T,OnStep,OnStart,OnEnd>)
-> Step<T,OnStep,OnStart,OnEnd>
where T:Value, OnStep:Callback1<T>, OnStart:Callback0, OnEnd:Callback1<EndStatus> {
fn step<T, OnStep, OnStart, OnEnd>(
simulator: &Simulator<T, OnStep, OnStart, OnEnd>,
) -> Step<T, OnStep, OnStart, OnEnd>
where
T: Value,
OnStep: Callback1<T>,
OnStart: Callback0,
OnEnd: Callback1<EndStatus>, {
let data = simulator.data.clone_ref();
let animation_loop = simulator.animation_loop.downgrade();
move |time: animation::TimeInfo| {
@ -725,12 +813,19 @@ where T:Value, OnStep:Callback1<T>, OnStart:Callback0, OnEnd:Callback1<EndStatus
/// forced, which means that it was forced by the user (for example by using the `stop` function).
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
#[allow(missing_docs)]
pub enum EndStatus { Normal, Forced }
pub enum EndStatus {
Normal,
Forced,
}
#[allow(missing_docs)]
impl EndStatus {
pub fn is_normal(self) -> bool { self == Self::Normal }
pub fn is_forced(self) -> bool { self == Self::Forced }
pub fn is_normal(self) -> bool {
self == Self::Normal
}
pub fn is_forced(self) -> bool {
self == Self::Forced
}
}
impl Default for EndStatus {

View File

@ -2,18 +2,18 @@
pub mod args;
pub mod command;
pub mod frp;
pub mod shortcut;
pub mod view;
pub mod frp;
pub use view::View;
use crate::prelude::*;
use crate::control::callback;
use crate::display;
use crate::display::style::theme;
use crate::display::world::World;
use crate::display;
use crate::gui::cursor::Cursor;
use crate::system::web;
use ensogl_system_web::StyleSetter;
@ -46,7 +46,8 @@ impl Application {
let display = World::new(dom);
let scene = display.scene();
let commands = command::Registry::create(&logger);
let shortcuts = shortcut::Registry::new(&logger,&scene.mouse.frp,&scene.keyboard.frp,&commands);
let shortcuts =
shortcut::Registry::new(&logger, &scene.mouse.frp, &scene.keyboard.frp, &commands);
let views = view::Registry::create(&logger, &display, &commands, &shortcuts);
let themes = theme::Manager::from(&display.scene().style_sheet);
let cursor = Cursor::new(display.scene());

View File

@ -10,7 +10,8 @@ use crate::prelude::*;
// =================
/// Marker trait used to disambiguate overlapping impls of [`ArgReader`].
#[marker] pub trait ArgMarker {}
#[marker]
pub trait ArgMarker {}
/// Trait used to convert provided string arguments to the desired type.
#[allow(missing_docs)]
@ -28,7 +29,8 @@ pub trait ArgReaderFromString : Sized {
}
impl<T> ArgReaderFromString for T
where String:TryInto<T> {
where String: TryInto<T>
{
fn read_arg_from_string(str: String) -> Option<Self> {
str.try_into().ok()
}
@ -41,7 +43,9 @@ impl<T> ArgReaderFromString for T {
}
impl<T> ArgMarker for T where T: TryFrom<String> {}
impl<T> ArgReader for T where T : ArgMarker {
impl<T> ArgReader for T
where T: ArgMarker
{
default fn read_arg(str: String) -> Option<Self> {
ArgReaderFromString::read_arg_from_string(str)
}

View File

@ -1,8 +1,8 @@
//! Definition of commands, labeled FPR endpoints useful when implementing actions which can be
//! altered at runtime, like a keyboard shortcut management.
use crate::prelude::*;
use crate::frp;
use crate::prelude::*;
use crate::application::shortcut;
use crate::application::shortcut::Shortcut;
@ -36,31 +36,38 @@ pub trait View : FrpNetworkProvider + DerefToCommandApi {
}
/// Add a new shortcut targeting the self object.
fn self_shortcut
( action_type : shortcut::ActionType
, pattern : impl Into<String>
, command : impl Into<shortcut::Command>
fn self_shortcut(
action_type: shortcut::ActionType,
pattern: impl Into<String>,
command: impl Into<shortcut::Command>,
) -> Shortcut {
Shortcut::new(shortcut::Rule::new(action_type, pattern), Self::label(), command)
}
/// Add a new shortcut targeting the self object.
fn self_shortcut_when
( action_type : shortcut::ActionType
, pattern : impl Into<String>
, command : impl Into<shortcut::Command>
, condition : impl Into<shortcut::Condition>
fn self_shortcut_when(
action_type: shortcut::ActionType,
pattern: impl Into<String>,
command: impl Into<shortcut::Command>,
condition: impl Into<shortcut::Condition>,
) -> Shortcut {
Shortcut::new_when(shortcut::Rule::new(action_type,pattern),Self::label(),command,condition)
Shortcut::new_when(
shortcut::Rule::new(action_type, pattern),
Self::label(),
command,
condition,
)
}
/// Disable the command in this component instance.
fn disable_command(&self, name:impl AsRef<str>) where Self:Sized {
fn disable_command(&self, name: impl AsRef<str>)
where Self: Sized {
self.app().commands.disable_command(self, name)
}
/// Enable the command in this component instance.
fn enable_command(&self, name:impl AsRef<str>) where Self:Sized {
fn enable_command(&self, name: impl AsRef<str>)
where Self: Sized {
self.app().commands.enable_command(self, name)
}
}
@ -111,8 +118,12 @@ impl Command {
/// Use the `define_endpoints!` macro to auto-derive it.
#[allow(missing_docs)]
pub trait CommandApi: Sized {
fn command_api(&self) -> Rc<RefCell<HashMap<String,Command>>> { default() }
fn status_api(&self) -> Rc<RefCell<HashMap<String,frp::Sampler<bool>>>> { default() }
fn command_api(&self) -> Rc<RefCell<HashMap<String, Command>>> {
default()
}
fn status_api(&self) -> Rc<RefCell<HashMap<String, frp::Sampler<bool>>>> {
default()
}
}
@ -189,10 +200,12 @@ impl Registry {
let was_registered = self.name_map.borrow().get(label).is_some();
if !was_registered {
self.register::<T>();
warning!(&self.logger,
warning!(
&self.logger,
"The command provider '{label}' was created but never registered. You should \
always register available command providers as soon as possible to spread the \
information about their API.");
information about their API."
);
};
let id = instance.id();
self.name_map.borrow_mut().get_mut(label).unwrap().push(instance.clone_ref());
@ -201,11 +214,11 @@ impl Registry {
/// Queries the command map by command name and applies the provided function to the result.
/// Emits warnings in case the command could not be found.
fn with_command_mut<T:View>
( &self
, target : &T
, name : impl AsRef<str>
, f : impl Fn(&mut Command)
fn with_command_mut<T: View>(
&self,
target: &T,
name: impl AsRef<str>,
f: impl Fn(&mut Command),
) {
let name = name.as_ref();
let id = T::network(target).id();
@ -213,8 +226,8 @@ impl Registry {
None => warning!(&self.logger, "The provided component ID is invalid {id}."),
Some(instance) => match instance.command_map.borrow_mut().get_mut(name) {
None => warning!(&self.logger, "The command name {name} is invalid."),
Some(command) => f(command)
}
Some(command) => f(command),
},
}
}

View File

@ -416,7 +416,7 @@ macro_rules! build_status_map {
($map:ident $field:ident (bool) $frp:expr) => {
$map.insert(stringify!($field).into(), $frp.clone_ref());
};
($($ts:tt)*) => {}
($($ts:tt)*) => {};
}
/// Internal helper of `define_endpoints` macro.
@ -425,7 +425,7 @@ macro_rules! build_command_map {
($map:ident $field:ident () $frp:expr) => {
$map.insert(stringify!($field).into(), Command::new($frp.clone_ref()));
};
($($ts:tt)*) => {}
($($ts:tt)*) => {};
}
/// Defines a method which is an alias to FRP emit method. Used internally by the `define_endpoints`
@ -441,11 +441,7 @@ macro_rules! define_endpoints_emit_alias {
($field:ident ($t1:ty,$t2:ty)) => {
#[allow(missing_docs)]
pub fn $field
( &self
, t1:impl IntoParam<$t1>
, t2:impl IntoParam<$t2>
) {
pub fn $field(&self, t1: impl IntoParam<$t1>, t2: impl IntoParam<$t2>) {
let t1 = t1.into_param();
let t2 = t2.into_param();
self.$field.emit((t1, t2));
@ -454,11 +450,11 @@ macro_rules! define_endpoints_emit_alias {
($field:ident ($t1:ty,$t2:ty,$t3:ty)) => {
#[allow(missing_docs)]
pub fn $field
( &self
, t1:impl IntoParam<$t1>
, t2:impl IntoParam<$t2>
, t3:impl IntoParam<$t3>
pub fn $field(
&self,
t1: impl IntoParam<$t1>,
t2: impl IntoParam<$t2>,
t3: impl IntoParam<$t3>,
) {
let t1 = t1.into_param();
let t2 = t2.into_param();
@ -469,12 +465,12 @@ macro_rules! define_endpoints_emit_alias {
($field:ident ($t1:ty,$t2:ty,$t3:ty,$t4:ty)) => {
#[allow(missing_docs)]
pub fn $field
( &self
, t1:impl IntoParam<$t1>
, t2:impl IntoParam<$t2>
, t3:impl IntoParam<$t3>
, t4:impl IntoParam<$t4>
pub fn $field(
&self,
t1: impl IntoParam<$t1>,
t2: impl IntoParam<$t2>,
t3: impl IntoParam<$t3>,
t4: impl IntoParam<$t4>,
) {
let t1 = t1.into_param();
let t2 = t2.into_param();
@ -486,13 +482,13 @@ macro_rules! define_endpoints_emit_alias {
($field:ident ($t1:ty,$t2:ty,$t3:ty,$t4:ty,$t5:ty)) => {
#[allow(missing_docs)]
pub fn $field
( &self
, t1:impl IntoParam<$t1>
, t2:impl IntoParam<$t2>
, t3:impl IntoParam<$t3>
, t4:impl IntoParam<$t4>
, t5:impl IntoParam<$t5>
pub fn $field(
&self,
t1: impl IntoParam<$t1>,
t2: impl IntoParam<$t2>,
t3: impl IntoParam<$t3>,
t4: impl IntoParam<$t4>,
t5: impl IntoParam<$t5>,
) {
let t1 = t1.into_param();
let t2 = t2.into_param();

View File

@ -4,9 +4,9 @@ use crate::prelude::*;
use super::command;
use crate::frp;
use crate::frp::io::keyboard;
use crate::frp::io::mouse::Mouse;
use crate::frp;
use enso_shortcuts as shortcuts;
use enso_shortcuts::traits::*;
@ -92,11 +92,11 @@ impl Condition {
/// Split the input on the provided `separator`, process each chunk with `f`, and fold results
/// using the `cons`.
fn split_parse
( input : &str
, separator : char
, cons : impl Fn(Self,Self) -> Self
, f : impl Fn(&str) -> Self
fn split_parse(
input: &str,
separator: char,
cons: impl Fn(Self, Self) -> Self,
f: impl Fn(&str) -> Self,
) -> Self {
input.split(separator).map(|t| t.trim()).map(f).fold1(cons).unwrap_or(Self::Never)
}
@ -108,8 +108,10 @@ impl Condition {
#[allow(clippy::redundant_closure)] // Rust TC does not agree.
fn parse(s: impl AsRef<str>) -> Self {
let s = s.as_ref().trim();
if s.is_empty() { Self::Always } else {
Self::split_parse(s,'|',Self::or,|s|
if s.is_empty() {
Self::Always
} else {
Self::split_parse(s, '|', Self::or, |s| {
Self::split_parse(s, '&', Self::and, |s| {
if let Some(expr) = s.strip_prefix('!') {
Self::not(Self::when(expr.trim()))
@ -117,7 +119,7 @@ impl Condition {
Self::when(s)
}
})
)
})
}
}
}
@ -151,8 +153,11 @@ impl Action {
}
/// Constructor.
pub fn new_when
(target:impl Into<String>, command:impl Into<Command>, condition:impl Into<Condition>) -> Self {
pub fn new_when(
target: impl Into<String>,
command: impl Into<Command>,
condition: impl Into<Condition>,
) -> Self {
let target = target.into();
let condition = condition.into();
let command = command.into();
@ -176,10 +181,10 @@ pub struct Shortcut {
impl Shortcut {
/// Constructor. Version without condition checker.
pub fn new
( rule : impl Into<Rule>
, target : impl Into<String>
, command : impl Into<Command>
pub fn new(
rule: impl Into<Rule>,
target: impl Into<String>,
command: impl Into<Command>,
) -> Self {
let action = Action::new(target, command);
let rule = rule.into();
@ -187,11 +192,11 @@ impl Shortcut {
}
/// Constructor.
pub fn new_when
( rule : impl Into<Rule>
, target : impl Into<String>
, command : impl Into<Command>
, condition : impl Into<Condition>
pub fn new_when(
rule: impl Into<Rule>,
target: impl Into<String>,
command: impl Into<Command>,
condition: impl Into<Condition>,
) -> Self {
let action = Action::new_when(target, command, condition);
let rule = rule.into();
@ -239,9 +244,12 @@ impl Deref for Registry {
impl Registry {
/// Constructor.
pub fn new
(logger:&Logger, mouse:&Mouse, keyboard:&keyboard::Keyboard, cmd_registry:&command::Registry)
-> Self {
pub fn new(
logger: &Logger,
mouse: &Mouse,
keyboard: &keyboard::Keyboard,
cmd_registry: &command::Registry,
) -> Self {
let model = RegistryModel::new(logger, mouse, keyboard, cmd_registry);
let mouse = &model.mouse;
@ -259,11 +267,11 @@ impl Registry {
impl RegistryModel {
/// Constructor.
pub fn new
( logger : impl AnyLogger
, mouse : &Mouse
, keyboard : &keyboard::Keyboard
, command_registry : &command::Registry
pub fn new(
logger: impl AnyLogger,
mouse: &Mouse,
keyboard: &keyboard::Keyboard,
command_registry: &command::Registry,
) -> Self {
let logger = Logger::new_sub(logger, "ShortcutRegistry");
let keyboard = keyboard.clone_ref();
@ -284,9 +292,14 @@ impl RegistryModel {
if Self::condition_checker(&rule.condition, &instance.status_map) {
let command_name = &rule.command.name;
match instance.command_map.borrow().get(command_name) {
Some(cmd) => if cmd.enabled { targets.push(cmd.frp.clone_ref()) },
None => warning!(&self.logger,
"Command {command_name} was not found on {target}."),
Some(cmd) =>
if cmd.enabled {
targets.push(cmd.frp.clone_ref())
},
None => warning!(
&self.logger,
"Command {command_name} was not found on {target}."
),
}
}
}
@ -298,8 +311,10 @@ impl RegistryModel {
}
}
fn condition_checker
(condition:&Condition, status:&Rc<RefCell<HashMap<String,frp::Sampler<bool>>>>) -> bool {
fn condition_checker(
condition: &Condition,
status: &Rc<RefCell<HashMap<String, frp::Sampler<bool>>>>,
) -> bool {
use Condition::*;
match condition {
Always => true,
@ -315,6 +330,10 @@ impl RegistryModel {
impl Add<Shortcut> for &Registry {
type Output = ();
fn add(self, shortcut: Shortcut) {
self.model.shortcuts_registry.add(shortcut.rule.tp,&shortcut.rule.pattern,shortcut.clone());
self.model.shortcuts_registry.add(
shortcut.rule.tp,
&shortcut.rule.pattern,
shortcut.clone(),
);
}
}

View File

@ -2,10 +2,10 @@
use crate::prelude::*;
use crate::display::world::World;
use super::command;
use super::shortcut;
use super::Application;
use crate::display::world::World;
pub use command::View;
@ -29,11 +29,11 @@ pub struct Registry {
impl Registry {
/// Constructor.
pub fn create
( logger : impl AnyLogger
, display : &World
, command_registry : &command::Registry
, shortcut_registry : &shortcut::Registry
pub fn create(
logger: impl AnyLogger,
display: &World,
command_registry: &command::Registry,
shortcut_registry: &shortcut::Registry,
) -> Self {
let logger = Logger::new_sub(logger, "view_registry");
let display = display.clone_ref();
@ -58,10 +58,12 @@ impl Registry {
let label = V::label();
let was_registered = self.definitions.borrow().get(label).is_some();
if !was_registered {
warning!(&self.logger,
warning!(
&self.logger,
"The view '{label}' was created but never registered, performing automatic \
registration. You should always register available views as soon as possible to \
enable their default shortcuts and spread the information about their API.");
enable their default shortcuts and spread the information about their API."
);
self.register::<V>();
}
let view = V::new(app);

View File

@ -9,12 +9,12 @@ use crate::system::web;
use std::cell::RefCell;
use std::rc::Rc;
use wasm_bindgen::prelude::Closure;
use wasm_bindgen::JsCast;
use wasm_bindgen::JsValue;
use wasm_bindgen::prelude::Closure;
pub use event::*;
pub use crate::frp::io::mouse::*;
pub use event::*;
@ -29,7 +29,7 @@ pub use crate::frp::io::mouse::*;
#[derivative(Clone(bound = ""))]
#[derivative(Default(bound = ""))]
pub struct EventDispatcher<T> {
rc: Rc<RefCell<callback::Registry1<T>>>
rc: Rc<RefCell<callback::Registry1<T>>>,
}
impl<T> EventDispatcher<T> {
@ -57,7 +57,7 @@ pub struct MouseManager {
#[shrinkwrap(main_field)]
dispatchers: MouseManagerDispatchers,
closures: Rc<MouseManagerClosures>,
dom : web::dom::WithKnownShape<web::EventTarget>
dom: web::dom::WithKnownShape<web::EventTarget>,
}
/// A JavaScript callback closure for any mouse event.
@ -158,13 +158,12 @@ pub struct MouseFrpCallbackHandles {
on_move: callback::Handle,
on_down: callback::Handle,
on_up: callback::Handle,
on_wheel : callback::Handle
on_wheel: callback::Handle,
}
// FIXME: This is obsolete. Use mouse bindings from scene instead.
/// Bind FRP graph to MouseManager.
pub fn bind_frp_to_mouse(frp:&Mouse, mouse_manager:&MouseManager)
-> MouseFrpCallbackHandles {
pub fn bind_frp_to_mouse(frp: &Mouse, mouse_manager: &MouseManager) -> MouseFrpCallbackHandles {
let dom_shape = mouse_manager.dom.clone_ref().shape();
let on_move = enclose!((frp.position => frp) move |e:&OnMove| {
let position = Vector2(e.client_x() as f32,e.client_y() as f32);
@ -178,6 +177,6 @@ pub fn bind_frp_to_mouse(frp:&Mouse, mouse_manager:&MouseManager)
on_move: mouse_manager.on_move.add(on_move),
on_down: mouse_manager.on_down.add(on_down),
on_up: mouse_manager.on_up.add(on_up),
on_wheel : mouse_manager.on_wheel.add(on_wheel)
on_wheel: mouse_manager.on_wheel.add(on_wheel),
}
}

View File

@ -2,8 +2,8 @@
use crate::prelude::*;
use enso_frp::io::mouse;
use crate::system::web::dom::Shape;
use enso_frp::io::mouse;
use wasm_bindgen::JsCast;

View File

@ -15,15 +15,15 @@
//! make them more pleasant to work with, however, the equations you will fnd will probably work on
//! different value ranges. Read documentation for each color space very carefully.
pub mod animation;
pub mod component;
pub mod data;
pub mod gradient;
pub mod mix;
pub mod space;
pub mod animation;
pub use self::data::*;
pub use animation::Animation;
pub use component::*;
pub use mix::mix;
pub use self::data::*;
pub use space::*;

View File

@ -3,8 +3,8 @@
//! discontinuities of the polar coordinates of Lcha (i.e., a transition from hue 1 to 359 would go
//! through all hues instead of taking the shorter trip "backwards").
use crate::prelude::*;
use super::*;
use crate::prelude::*;
use enso_frp as frp;
@ -28,8 +28,8 @@ crate::define_endpoints! {
}
/// The `Animation` provides color better animations for colors than the raw
/// `component::DEPRECATED_Animation<_>`, as it allows controlling the alpha channel separately which is
/// important for nice fade outs.
/// `component::DEPRECATED_Animation<_>`, as it allows controlling the alpha channel separately
/// which is important for nice fade outs.
#[derive(Clone, CloneRef, Debug)]
#[allow(missing_docs)]
pub struct Animation {

View File

@ -17,7 +17,7 @@ use nalgebra::Vector4;
#[derive(Clone, Copy, Debug)]
#[allow(missing_docs)]
pub struct Components<T> {
pub tuple : T
pub tuple: T,
}
/// Smart constructor.
@ -61,11 +61,16 @@ pub type ComponentsOf<T> = Components<ComponentsReprOf<T>>;
// === Generics ===
impl<T:KnownLast> KnownLast for Components<T> { type Last = Last<T>; }
impl<T:KnownInit> KnownInit for Components<T> { type Init = Components<Init<T>>; }
impl<T: KnownLast> KnownLast for Components<T> {
type Last = Last<T>;
}
impl<T: KnownInit> KnownInit for Components<T> {
type Init = Components<Init<T>>;
}
impl<T, X> PushBack<X> for Components<T>
where T:PushBack<X> {
where T: PushBack<X>
{
type Output = Components<<T as PushBack<X>>::Output>;
fn push_back(self, t: X) -> Self::Output {
Components(self.tuple.push_back(t))
@ -73,7 +78,8 @@ impl<T,X> PushBack<X> for Components<T>
}
impl<T> PopBack for Components<T>
where T:PopBack {
where T: PopBack
{
fn pop_back(self) -> (Self::Last, Self::Init) {
let (last, init) = self.tuple.pop_back();
let init = Components(init);
@ -216,9 +222,15 @@ define_operators_for_component_refs! { Add::add, Sub::sub, Mul::mul, Div::div }
// === Vector Conversions ===
// ==========================
impl<T:Scalar> HasComponentsRepr for Vector2<T> { type ComponentsRepr = (T,T); }
impl<T:Scalar> HasComponentsRepr for Vector3<T> { type ComponentsRepr = (T,T,T); }
impl<T:Scalar> HasComponentsRepr for Vector4<T> { type ComponentsRepr = (T,T,T,T); }
impl<T: Scalar> HasComponentsRepr for Vector2<T> {
type ComponentsRepr = (T, T);
}
impl<T: Scalar> HasComponentsRepr for Vector3<T> {
type ComponentsRepr = (T, T, T);
}
impl<T: Scalar> HasComponentsRepr for Vector4<T> {
type ComponentsRepr = (T, T, T, T);
}
impl<T: Scalar> From<Vector2<T>> for ComponentsOf<Vector2<T>> {
fn from(t: Vector2<T>) -> Self {

View File

@ -5,8 +5,8 @@ use crate::prelude::*;
use enso_generics::*;
use super::component::*;
use super::component::HasComponents;
use super::component::*;
use nalgebra::Vector3;
use nalgebra::Vector4;
@ -30,7 +30,7 @@ use nalgebra::Vector4;
#[derive(Clone, Copy, Default, PartialEq)]
pub struct Color<D> {
/// The underlying color representation. It is either `Alpha` or a color space instance.
pub data : D
pub data: D,
}
/// Smart constructor.
@ -70,8 +70,12 @@ impl<D> DerefMut for Color<D> {
/// Type family for accessing color models.
#[allow(missing_docs)]
pub trait HasModel { type Model; }
impl<M> HasModel for Color<M> { type Model = M; }
pub trait HasModel {
type Model;
}
impl<M> HasModel for Color<M> {
type Model = M;
}
/// Accessor for `HasModel::Model`.
pub type Model<T> = <T as HasModel>::Model;
@ -93,7 +97,8 @@ impl<D:ComponentMap> ComponentMap for Color<D> {
// === Conversions ===
impl<D1, D2> From<&Color<D1>> for Color<D2>
where Color<D1> : Clone + Into<Color<D2>> {
where Color<D1>: Clone + Into<Color<D2>>
{
fn from(color: &Color<D1>) -> Self {
color.clone().into()
}
@ -107,70 +112,82 @@ impl<C> From<Color<C>> for Color<Alpha<C>> {
}
impl<D> From<Color<D>> for ComponentsOf<Color<D>>
where D:HasComponents {
where D: HasComponents
{
fn from(color: Color<D>) -> Self {
color.data.into()
}
}
impl<D> From<ComponentsOf<D>> for Color<D>
where D:HasComponentsRepr, ComponentsOf<D>:Into<D> {
where
D: HasComponentsRepr,
ComponentsOf<D>: Into<D>,
{
fn from(components: ComponentsOf<D>) -> Self {
Self { data: components.into() }
}
}
impl<D> From<Color<D>> for Vector3<f32>
where Color<D> : HasComponents<ComponentsRepr=(f32,f32,f32)> {
where Color<D>: HasComponents<ComponentsRepr = (f32, f32, f32)>
{
fn from(value: Color<D>) -> Self {
Into::<Vector3<f32>>::into(value.into_components())
}
}
impl<D> From<Color<D>> for Vector4<f32>
where Color<D> : HasComponents<ComponentsRepr=(f32,f32,f32,f32)> {
where Color<D>: HasComponents<ComponentsRepr = (f32, f32, f32, f32)>
{
fn from(value: Color<D>) -> Self {
Into::<Vector4<f32>>::into(value.into_components())
}
}
impl<D> From<&Color<D>> for Vector3<f32>
where Color<D> : HasComponents<ComponentsRepr=(f32,f32,f32)> + Copy {
where Color<D>: HasComponents<ComponentsRepr = (f32, f32, f32)> + Copy
{
fn from(value: &Color<D>) -> Self {
Into::<Vector3<f32>>::into(value.into_components())
}
}
impl<D> From<&Color<D>> for Vector4<f32>
where Color<D> : HasComponents<ComponentsRepr=(f32,f32,f32,f32)> + Copy {
where Color<D>: HasComponents<ComponentsRepr = (f32, f32, f32, f32)> + Copy
{
fn from(value: &Color<D>) -> Self {
Into::<Vector4<f32>>::into(value.into_components())
}
}
impl<D> From<Vector3<f32>> for Color<D>
where D : HasComponents<ComponentsRepr=(f32,f32,f32)> {
where D: HasComponents<ComponentsRepr = (f32, f32, f32)>
{
fn from(t: Vector3<f32>) -> Self {
Self::from(t.into_components())
}
}
impl<D> From<Vector4<f32>> for Color<D>
where D : HasComponents<ComponentsRepr=(f32,f32,f32,f32)> {
where D: HasComponents<ComponentsRepr = (f32, f32, f32, f32)>
{
fn from(t: Vector4<f32>) -> Self {
Self::from(t.into_components())
}
}
impl<D> From<&Vector3<f32>> for Color<D>
where D : Copy + HasComponents<ComponentsRepr=(f32,f32,f32)> {
where D: Copy + HasComponents<ComponentsRepr = (f32, f32, f32)>
{
fn from(t: &Vector3<f32>) -> Self {
Self::from((*t).into_components())
}
}
impl<D> From<&Vector4<f32>> for Color<D>
where D : Copy + HasComponents<ComponentsRepr=(f32,f32,f32,f32)> {
where D: Copy + HasComponents<ComponentsRepr = (f32, f32, f32, f32)>
{
fn from(t: &Vector4<f32>) -> Self {
Self::from((*t).into_components())
}
@ -249,20 +266,29 @@ pub struct Alpha<C> {
// === Component Generics ===
impl<C> HasComponentsRepr for Alpha<C>
where C:HasComponentsRepr, ComponentsReprOf<C>:PushBack<f32> {
where
C: HasComponentsRepr,
ComponentsReprOf<C>: PushBack<f32>,
{
type ComponentsRepr = <ComponentsReprOf<C> as PushBack<f32>>::Output;
}
impl<C> From<Alpha<C>> for ComponentsOf<Alpha<C>>
where C:HasComponents, ComponentsReprOf<C>:PushBack<f32> {
where
C: HasComponents,
ComponentsReprOf<C>: PushBack<f32>,
{
fn from(t: Alpha<C>) -> Self {
t.opaque.data.into().push_back(t.alpha)
}
}
impl<C> From<ComponentsOf<Alpha<C>>> for Alpha<C>
where C:HasComponents, ComponentsReprOf<C>:PushBack<f32>,
<ComponentsReprOf<C> as PushBack<f32>>::Output : PopBack<Last=f32,Init=ComponentsReprOf<C>> {
where
C: HasComponents,
ComponentsReprOf<C>: PushBack<f32>,
<ComponentsReprOf<C> as PushBack<f32>>::Output: PopBack<Last = f32, Init = ComponentsReprOf<C>>,
{
fn from(components: ComponentsOf<Self>) -> Self {
let (alpha, init) = components.pop_back();
let opaque = from_components(init);

View File

@ -2,8 +2,8 @@
use crate::prelude::*;
use crate::system::gpu::shader::glsl::Glsl;
use crate::system::gpu::shader::glsl::traits::*;
use crate::system::gpu::shader::glsl::Glsl;
@ -18,7 +18,7 @@ pub struct ControlPoint<Color> {
/// Offset of the control point in [0..1] range.
pub offset: f32,
/// Color of this control point.
pub color : Color
pub color: Color,
}
impl<Color> ControlPoint<Color> {
@ -102,7 +102,7 @@ pub struct SdfSampler<Gradient> {
/// The gradient slope modifier. Defines how fast the gradient values change.
pub slope: Slope,
/// The underlying gradient.
pub gradient : Gradient
pub gradient: Gradient,
}
impl<Gradient> SdfSampler<Gradient> {

View File

@ -1,7 +1,7 @@
//! Color mixing utilities.
use crate::prelude::*;
use super::*;
use crate::prelude::*;
use crate::data::mix;
use crate::data::mix::Mixable;
@ -33,7 +33,9 @@ macro_rules! define_mix_impls {
macro_rules! define_mix_impl_repr {
($tp:ty => $via_tp:ty [$repr:ident]) => {
impl Mixable for $tp { type Repr = $repr; }
impl Mixable for $tp {
type Repr = $repr;
}
impl From<$tp> for mix::Space<$tp> {
fn from(value: $tp) -> mix::Space<$tp> {
@ -46,7 +48,7 @@ macro_rules! define_mix_impl_repr {
<$via_tp>::from(t.value).into()
}
}
}
};
}

View File

@ -14,11 +14,11 @@
#![allow(clippy::unreadable_literal)]
#![allow(clippy::excessive_precision)]
use super::def::*;
use super::super::component::*;
use super::super::data::*;
use super::white_point::traits::*;
use super::def::*;
use super::white_point;
use super::white_point::traits::*;
@ -101,7 +101,7 @@ macro_rules! color_convert_via {
<Color<Alpha<$src>>>::from(src).into()
}
}
}
};
}
@ -113,13 +113,19 @@ macro_rules! color_convert_via {
/// More info: http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
fn into_linear(x: f32) -> f32 {
if x <= 0.04045 { x / 12.92 }
else { ((x + 0.055) / 1.055).powf(2.4) }
if x <= 0.04045 {
x / 12.92
} else {
((x + 0.055) / 1.055).powf(2.4)
}
}
fn from_linear(x: f32) -> f32 {
if x <= 0.0031308 { x * 12.92 }
else { x.powf(1.0/2.4) * 1.055 - 0.055 }
if x <= 0.0031308 {
x * 12.92
} else {
x.powf(1.0 / 2.4) * 1.055 - 0.055
}
}
color_conversion! {

View File

@ -1,8 +1,8 @@
//! This module contains definitions of various color spaces, including `Rgb`, `Hsl`, `Lch`, etc.
use crate::prelude::*;
use super::super::data::*;
use super::super::component::*;
use super::super::data::*;
use crate::prelude::*;
@ -17,12 +17,15 @@ macro_rules! define_color_parsing {
fn from_str(s: &str) -> Result<Self, Self::Err> {
let (head, args) = generic_parse(s)?;
if &head != stringify!($name) {
return Err(ParseError::new(format!("No '{}' header found.",stringify!($name))))
return Err(ParseError::new(format!(
"No '{}' header found.",
stringify!($name)
)));
}
Ok($name::from_slice(&args))
}
}
}
};
}
macro_rules! define_color_spaces {
@ -73,8 +76,12 @@ macro_rules! define_color_spaces {
}
impl<C> From<AnyFormat> for Color<C>
where Rgb: Into<Color<C>>, Rgba: Into<Color<C>>,
Lch: Into<Color<C>>, Lcha: Into<Color<C>> {
where
Rgb: Into<Color<C>>,
Rgba: Into<Color<C>>,
Lch: Into<Color<C>>,
Lcha: Into<Color<C>>,
{
fn from(c: AnyFormat) -> Self {
match c {
AnyFormat::Rgb(t) => t.into(),
@ -85,7 +92,7 @@ where Rgb: Into<Color<C>>, Rgba: Into<Color<C>>,
// it requires a lot more conversions than we support currently. To be implemented
// one day.
// https://github.com/enso-org/ide/issues/1404
_ => panic!("Not implemented.")
_ => panic!("Not implemented."),
}
}
}
@ -465,7 +472,9 @@ impl LabData {
None
} else {
let mut hue = self.b.atan2(self.a) * 180.0 / std::f32::consts::PI;
if hue < 0.0 { hue += 360.0 }
if hue < 0.0 {
hue += 360.0
}
Some(hue)
}
}
@ -485,46 +494,110 @@ pub(crate) const LCH_MAX_CHROMA_IN_SRGB_IN_STD_EQUATIONS : usize = 120;
#[allow(missing_docs)]
impl Lch {
pub fn pink_hue () -> f32 { 0.0 } // approx. 0.0 degrees
pub fn red_hue () -> f32 { 0.111 } // approx. 40.0 degrees
pub fn orange_hue () -> f32 { 0.18 } // approx. 65.0 degrees
pub fn yellow_hue () -> f32 { 0.236 } // approx. 85.0 degrees
pub fn olive_hue () -> f32 { 0.291 } // approx. 105.0 degrees
pub fn green_hue () -> f32 { 0.378 } // approx. 136.0 degrees
pub fn blue_green_hue () -> f32 { 0.6 } // approx. 216.0 degrees
pub fn blue_hue () -> f32 { 0.672 } // approx. 242.0 degrees
pub fn violet_hue () -> f32 { 0.847 } // approx. 305.0 degrees
pub fn pink_hue() -> f32 {
0.0
} // approx. 0.0 degrees
pub fn red_hue() -> f32 {
0.111
} // approx. 40.0 degrees
pub fn orange_hue() -> f32 {
0.18
} // approx. 65.0 degrees
pub fn yellow_hue() -> f32 {
0.236
} // approx. 85.0 degrees
pub fn olive_hue() -> f32 {
0.291
} // approx. 105.0 degrees
pub fn green_hue() -> f32 {
0.378
} // approx. 136.0 degrees
pub fn blue_green_hue() -> f32 {
0.6
} // approx. 216.0 degrees
pub fn blue_hue() -> f32 {
0.672
} // approx. 242.0 degrees
pub fn violet_hue() -> f32 {
0.847
} // approx. 305.0 degrees
}
#[allow(missing_docs)]
impl Lch {
pub fn white () -> Lch { Lch::new(1.0,0.0,0.0) }
pub fn black () -> Lch { Lch::new(0.0,0.0,0.0) }
pub fn pink (l:f32, c:f32) -> Lch { Lch::new(l,c,Lch::pink_hue()) }
pub fn red (l:f32, c:f32) -> Lch { Lch::new(l,c,Lch::red_hue()) }
pub fn orange (l:f32, c:f32) -> Lch { Lch::new(l,c,Lch::orange_hue()) }
pub fn yellow (l:f32, c:f32) -> Lch { Lch::new(l,c,Lch::yellow_hue()) }
pub fn olive (l:f32, c:f32) -> Lch { Lch::new(l,c,Lch::olive_hue()) }
pub fn green (l:f32, c:f32) -> Lch { Lch::new(l,c,Lch::green_hue()) }
pub fn blue_green (l:f32, c:f32) -> Lch { Lch::new(l,c,Lch::blue_green_hue()) }
pub fn blue (l:f32, c:f32) -> Lch { Lch::new(l,c,Lch::blue_hue()) }
pub fn violet (l:f32, c:f32) -> Lch { Lch::new(l,c,Lch::violet_hue()) }
pub fn white() -> Lch {
Lch::new(1.0, 0.0, 0.0)
}
pub fn black() -> Lch {
Lch::new(0.0, 0.0, 0.0)
}
pub fn pink(l: f32, c: f32) -> Lch {
Lch::new(l, c, Lch::pink_hue())
}
pub fn red(l: f32, c: f32) -> Lch {
Lch::new(l, c, Lch::red_hue())
}
pub fn orange(l: f32, c: f32) -> Lch {
Lch::new(l, c, Lch::orange_hue())
}
pub fn yellow(l: f32, c: f32) -> Lch {
Lch::new(l, c, Lch::yellow_hue())
}
pub fn olive(l: f32, c: f32) -> Lch {
Lch::new(l, c, Lch::olive_hue())
}
pub fn green(l: f32, c: f32) -> Lch {
Lch::new(l, c, Lch::green_hue())
}
pub fn blue_green(l: f32, c: f32) -> Lch {
Lch::new(l, c, Lch::blue_green_hue())
}
pub fn blue(l: f32, c: f32) -> Lch {
Lch::new(l, c, Lch::blue_hue())
}
pub fn violet(l: f32, c: f32) -> Lch {
Lch::new(l, c, Lch::violet_hue())
}
}
#[allow(missing_docs)]
impl Lcha {
pub fn transparent () -> Lcha { Lcha::new(0.0,0.0,0.0,0.0) }
pub fn white () -> Lcha { Lch::white () . into() }
pub fn black () -> Lcha { Lch::black () . into() }
pub fn pink (l:f32, c:f32) -> Lcha { Lch::pink (l,c) . into() }
pub fn red (l:f32, c:f32) -> Lcha { Lch::red (l,c) . into() }
pub fn orange (l:f32, c:f32) -> Lcha { Lch::orange (l,c) . into() }
pub fn yellow (l:f32, c:f32) -> Lcha { Lch::yellow (l,c) . into() }
pub fn olive (l:f32, c:f32) -> Lcha { Lch::olive (l,c) . into() }
pub fn green (l:f32, c:f32) -> Lcha { Lch::green (l,c) . into() }
pub fn blue_green (l:f32, c:f32) -> Lcha { Lch::blue_green (l,c) . into() }
pub fn blue (l:f32, c:f32) -> Lcha { Lch::blue (l,c) . into() }
pub fn violet (l:f32, c:f32) -> Lcha { Lch::violet (l,c) . into() }
pub fn transparent() -> Lcha {
Lcha::new(0.0, 0.0, 0.0, 0.0)
}
pub fn white() -> Lcha {
Lch::white().into()
}
pub fn black() -> Lcha {
Lch::black().into()
}
pub fn pink(l: f32, c: f32) -> Lcha {
Lch::pink(l, c).into()
}
pub fn red(l: f32, c: f32) -> Lcha {
Lch::red(l, c).into()
}
pub fn orange(l: f32, c: f32) -> Lcha {
Lch::orange(l, c).into()
}
pub fn yellow(l: f32, c: f32) -> Lcha {
Lch::yellow(l, c).into()
}
pub fn olive(l: f32, c: f32) -> Lcha {
Lch::olive(l, c).into()
}
pub fn green(l: f32, c: f32) -> Lcha {
Lch::green(l, c).into()
}
pub fn blue_green(l: f32, c: f32) -> Lcha {
Lch::blue_green(l, c).into()
}
pub fn blue(l: f32, c: f32) -> Lcha {
Lch::blue(l, c).into()
}
pub fn violet(l: f32, c: f32) -> Lcha {
Lch::violet(l, c).into()
}
/// Convert the color to JavaScript representation.
pub fn to_javascript_string(self) -> String {
@ -576,16 +649,109 @@ impl Lcha {
/// 0 12.5 25.0 37.5 50.0 62.5 75.0 75.5 100.0
/// LIGHTNESS
/// ```
pub const LCH_MAX_LIGHTNESS_CHROMA_IN_SRGB_CORRELATION : &[(usize,usize)] =
&[(0,0),(1,1),(2,2),(3,5),(4,5),(5,6),(6,8),(7,9),(8,10),(9,11),(10,12),(11,13),(12,13),(13,14)
,(14,14),(15,15),(16,15),(17,16),(18,16),(19,17),(20,17),(21,18),(22,18),(23,18),(24,19)
,(25,19),(26,20),(27,20),(28,21),(29,21),(30,22),(31,22),(32,23),(33,23),(34,24),(35,24)
,(36,25),(37,25),(38,26),(39,26),(40,27),(41,27),(42,28),(43,28),(44,29),(45,29),(46,30)
,(47,30),(48,31),(49,31),(50,32),(51,32),(52,33),(53,33),(54,34),(55,34),(56,35),(57,35)
,(58,36),(59,36),(60,36),(61,37),(62,37),(63,38),(64,38),(65,39),(66,39),(67,40),(68,40)
,(69,41),(70,41),(71,42),(72,42),(73,41),(74,39),(75,38),(76,36),(77,35),(78,33),(79,31)
,(80,30),(81,28),(82,27),(83,25),(84,24),(85,22),(86,20),(87,19),(88,17),(89,16),(90,14)
,(91,12),(92,11),(93,9),(94,8),(95,6),(96,5),(97,4),(98,2),(99,1),(100,0)];
pub const LCH_MAX_LIGHTNESS_CHROMA_IN_SRGB_CORRELATION: &[(usize, usize)] = &[
(0, 0),
(1, 1),
(2, 2),
(3, 5),
(4, 5),
(5, 6),
(6, 8),
(7, 9),
(8, 10),
(9, 11),
(10, 12),
(11, 13),
(12, 13),
(13, 14),
(14, 14),
(15, 15),
(16, 15),
(17, 16),
(18, 16),
(19, 17),
(20, 17),
(21, 18),
(22, 18),
(23, 18),
(24, 19),
(25, 19),
(26, 20),
(27, 20),
(28, 21),
(29, 21),
(30, 22),
(31, 22),
(32, 23),
(33, 23),
(34, 24),
(35, 24),
(36, 25),
(37, 25),
(38, 26),
(39, 26),
(40, 27),
(41, 27),
(42, 28),
(43, 28),
(44, 29),
(45, 29),
(46, 30),
(47, 30),
(48, 31),
(49, 31),
(50, 32),
(51, 32),
(52, 33),
(53, 33),
(54, 34),
(55, 34),
(56, 35),
(57, 35),
(58, 36),
(59, 36),
(60, 36),
(61, 37),
(62, 37),
(63, 38),
(64, 38),
(65, 39),
(66, 39),
(67, 40),
(68, 40),
(69, 41),
(70, 41),
(71, 42),
(72, 42),
(73, 41),
(74, 39),
(75, 38),
(76, 36),
(77, 35),
(78, 33),
(79, 31),
(80, 30),
(81, 28),
(82, 27),
(83, 25),
(84, 24),
(85, 22),
(86, 20),
(87, 19),
(88, 17),
(89, 16),
(90, 14),
(91, 12),
(92, 11),
(93, 9),
(94, 8),
(95, 6),
(96, 5),
(97, 4),
(98, 2),
(99, 1),
(100, 0),
];
lazy_static! {
/// Map from LCH lightness to max chroma, so every hue value will be included in the sRGB color
@ -646,7 +812,7 @@ fn lch_lightness_to_max_chroma_in_srgb(l:f32) -> f32 {
#[derive(Debug, Clone)]
#[allow(missing_docs)]
pub struct ParseError {
pub reason:String
pub reason: String,
}
impl ParseError {
@ -677,8 +843,7 @@ fn generic_parse(s:&str) -> Result<(String,Vec<f32>),ParseError> {
let mut splitter = s.splitn(2, '(');
match splitter.next() {
None => Err(ParseError::new("Empty input.")),
Some(head) => {
match splitter.next() {
Some(head) => match splitter.next() {
None => Err(ParseError::new("No arguments provided.")),
Some(rest) => {
let head = uppercase_first_letter(&head.to_lowercase());
@ -692,7 +857,6 @@ fn generic_parse(s:&str) -> Result<(String,Vec<f32>),ParseError> {
Ok((head, args))
}
}
}
}
},
}
}

View File

@ -9,8 +9,8 @@
//! Note that this module implements currently only `D65` white point. In case other will be needed
//! they can be easily ported from the Rust `Palette` library implementation.
use super::def::*;
use super::super::component::*;
use super::def::*;
/// Common traits.

View File

@ -28,7 +28,7 @@ pub trait AddMut<T> {
#[derive(Debug)]
pub struct CachingIterator<T: Clone, It: Iterator<Item = T>> {
last: Option<T>,
iter : It
iter: It,
}
impl<T: Clone, It: Iterator<Item = T>> Iterator for CachingIterator<T, It> {
@ -58,10 +58,7 @@ impl<T : Clone, It : Iterator<Item=T>> IntoCachingIterator for It {
type Iter = Self;
fn cache_last_value(self) -> CachingIterator<Self::Item, Self::Iter> {
CachingIterator {
last : None,
iter : self
}
CachingIterator { last: None, iter: self }
}
}

View File

@ -24,29 +24,57 @@ pub mod traits {
use super::*;
// === Arg ===
pub trait HasArg { type Arg; }
pub trait HasArg {
type Arg;
}
pub type Arg<T> = <T as HasArg>::Arg;
// === Global Operations ===
pub trait HasCheckAll { fn check_all (&self) -> bool; }
pub trait HasUnsetAll { fn unset_all (&mut self); }
pub trait HasCheckAll {
fn check_all(&self) -> bool;
}
pub trait HasUnsetAll {
fn unset_all(&mut self);
}
// === Arity-0 Operations ===
pub trait HasCheck0 { fn check (&self) -> bool; }
pub trait HasSet0 { fn set (&mut self); }
pub trait HasUnset0 { fn unset (&mut self); }
pub trait HasCheck0 {
fn check(&self) -> bool;
}
pub trait HasSet0 {
fn set(&mut self);
}
pub trait HasUnset0 {
fn unset(&mut self);
}
// === Arity-1 Operations ===
pub trait HasCheck1 : HasArg { fn check (& self, arg: &Self::Arg) -> bool; }
pub trait HasSet1 : HasArg { fn set (&mut self, arg: Self::Arg); }
pub trait HasUnset1 : HasArg { fn unset (&mut self, arg: &Self::Arg); }
pub trait HasCheck1: HasArg {
fn check(&self, arg: &Self::Arg) -> bool;
}
pub trait HasSet1: HasArg {
fn set(&mut self, arg: Self::Arg);
}
pub trait HasUnset1: HasArg {
fn unset(&mut self, arg: &Self::Arg);
}
// === Shared Operations ===
pub trait SharedHasUnsetAll { fn unset_all (&self); }
pub trait SharedHasSet0 { fn set (&self); }
pub trait SharedHasUnset0 { fn unset (&self); }
pub trait SharedHasSet1 : HasArg { fn set (&self, arg: Self::Arg); }
pub trait SharedHasUnset1 : HasArg { fn unset (&self, arg:&Self::Arg); }
pub trait SharedHasUnsetAll {
fn unset_all(&self);
}
pub trait SharedHasSet0 {
fn set(&self);
}
pub trait SharedHasUnset0 {
fn unset(&self);
}
pub trait SharedHasSet1: HasArg {
fn set(&self, arg: Self::Arg);
}
pub trait SharedHasUnset1: HasArg {
fn unset(&self, arg: &Self::Arg);
}
// === Type Aliases ===
pub trait DirtyFlagOps = Debug + HasCheckAll + HasUnsetAll;
@ -93,36 +121,35 @@ impl<OnMut,T:Default> DirtyFlag<T,OnMut> {
// === Arguments ===
impl<T:HasArg,OnMut>
HasArg for DirtyFlag<T,OnMut> {
impl<T: HasArg, OnMut> HasArg for DirtyFlag<T, OnMut> {
type Arg = Arg<T>;
}
// === Global Operations ===
impl<T:HasCheckAll,OnMut>
HasCheckAll for DirtyFlag<T,OnMut> {
fn check_all(&self) -> bool { self.data.check_all() }
impl<T: HasCheckAll, OnMut> HasCheckAll for DirtyFlag<T, OnMut> {
fn check_all(&self) -> bool {
self.data.check_all()
}
}
impl<T:HasUnsetAll,OnMut>
HasUnsetAll for DirtyFlag<T,OnMut> {
fn unset_all(&mut self) { self.data.unset_all() }
impl<T: HasUnsetAll, OnMut> HasUnsetAll for DirtyFlag<T, OnMut> {
fn unset_all(&mut self) {
self.data.unset_all()
}
}
// === Check ===
impl<T:DirtyFlagOps0,OnMut>
HasCheck0 for DirtyFlag<T,OnMut> {
impl<T: DirtyFlagOps0, OnMut> HasCheck0 for DirtyFlag<T, OnMut> {
fn check(&self) -> bool {
self.data.check()
}
}
impl<T:DirtyFlagOps1,OnMut>
HasCheck1 for DirtyFlag<T,OnMut> {
impl<T: DirtyFlagOps1, OnMut> HasCheck1 for DirtyFlag<T, OnMut> {
fn check(&self, arg: &Self::Arg) -> bool {
self.data.check(arg)
}
@ -131,8 +158,7 @@ HasCheck1 for DirtyFlag<T,OnMut> {
// === Set ===
impl<T:DirtyFlagOps0,OnMut:FnMut0>
HasSet0 for DirtyFlag<T,OnMut> {
impl<T: DirtyFlagOps0, OnMut: FnMut0> HasSet0 for DirtyFlag<T, OnMut> {
fn set(&mut self) {
let is_set = self.data.check_all();
if !is_set {
@ -144,15 +170,16 @@ HasSet0 for DirtyFlag<T,OnMut> {
}
}
impl<T:DirtyFlagOps1,OnMut:FnMut0>
HasSet1 for DirtyFlag<T,OnMut> {
impl<T: DirtyFlagOps1, OnMut: FnMut0> HasSet1 for DirtyFlag<T, OnMut> {
fn set(&mut self, arg: Self::Arg) {
let first_set = !self.check_all();
let is_set = self.data.check(&arg);
if !is_set {
self.data.set(arg);
debug!(self.logger, "Setting to {self.data:?}.", || {
if first_set { self.on_set.call(); }
if first_set {
self.on_set.call();
}
})
}
}
@ -161,17 +188,16 @@ HasSet1 for DirtyFlag<T,OnMut> {
// === Unset ===
impl<T:HasUnset0,OnMut>
HasUnset0 for DirtyFlag<T,OnMut> {
impl<T: HasUnset0, OnMut> HasUnset0 for DirtyFlag<T, OnMut> {
fn unset(&mut self) {
info!(self.logger, "Unsetting.");
self.data.unset()
}
}
impl<T:HasUnset1,OnMut>
HasUnset1 for DirtyFlag<T,OnMut>
where Arg<T>:Display {
impl<T: HasUnset1, OnMut> HasUnset1 for DirtyFlag<T, OnMut>
where Arg<T>: Display
{
fn unset(&mut self, arg: &Self::Arg) {
info!(self.logger, "Unsetting {arg}.");
self.data.unset(arg)
@ -192,14 +218,13 @@ HasUnset1 for DirtyFlag<T,OnMut>
#[derivative(Debug(bound = "T:Debug"))]
#[derivative(Clone(bound = ""))]
pub struct SharedDirtyFlag<T, OnMut> {
rc: Rc<RefCell<DirtyFlag<T,OnMut>>>
rc: Rc<RefCell<DirtyFlag<T, OnMut>>>,
}
// === API ===
impl<T:Default,OnMut>
SharedDirtyFlag<T,OnMut> {
impl<T: Default, OnMut> SharedDirtyFlag<T, OnMut> {
pub fn new(logger: Logger, on_set: OnMut) -> Self {
Self { rc: Rc::new(RefCell::new(DirtyFlag::new(logger, on_set))) }
}
@ -209,22 +234,19 @@ SharedDirtyFlag<T,OnMut> {
}
}
impl<T,OnMut>
SharedDirtyFlag<T,OnMut> {
impl<T, OnMut> SharedDirtyFlag<T, OnMut> {
pub fn clone_ref(&self) -> Self {
self.clone()
}
}
impl<T,OnMut>
SharedDirtyFlag<T,OnMut> {
impl<T, OnMut> SharedDirtyFlag<T, OnMut> {
pub fn set_callback(&self, on_set: OnMut) {
self.rc.borrow_mut().on_set = on_set;
}
}
impl<T,OnMut>
From<Rc<RefCell<DirtyFlag<T,OnMut>>>> for SharedDirtyFlag<T,OnMut> {
impl<T, OnMut> From<Rc<RefCell<DirtyFlag<T, OnMut>>>> for SharedDirtyFlag<T, OnMut> {
fn from(rc: Rc<RefCell<DirtyFlag<T, OnMut>>>) -> Self {
Self { rc }
}
@ -240,15 +262,13 @@ impl<T:HasArg,OnMut> HasArg for SharedDirtyFlag<T,OnMut> {
// === Global Operations ===
impl<T:HasUnsetAll,OnMut>
SharedHasUnsetAll for SharedDirtyFlag<T,OnMut> {
impl<T: HasUnsetAll, OnMut> SharedHasUnsetAll for SharedDirtyFlag<T, OnMut> {
fn unset_all(&self) {
self.rc.borrow_mut().unset_all()
}
}
impl<T:HasCheckAll,OnMut>
HasCheckAll for SharedDirtyFlag<T,OnMut> {
impl<T: HasCheckAll, OnMut> HasCheckAll for SharedDirtyFlag<T, OnMut> {
fn check_all(&self) -> bool {
self.rc.borrow().check_all()
}
@ -256,39 +276,43 @@ HasCheckAll for SharedDirtyFlag<T,OnMut> {
// === Check ===
impl<T:DirtyFlagOps0,OnMut>
HasCheck0 for SharedDirtyFlag<T,OnMut> {
fn check (&self) -> bool { self.rc.borrow().check() }
impl<T: DirtyFlagOps0, OnMut> HasCheck0 for SharedDirtyFlag<T, OnMut> {
fn check(&self) -> bool {
self.rc.borrow().check()
}
}
impl<T:DirtyFlagOps1,OnMut>
HasCheck1 for SharedDirtyFlag<T,OnMut> {
fn check (&self, arg:&Arg<T>) -> bool { self.rc.borrow().check(arg) }
impl<T: DirtyFlagOps1, OnMut> HasCheck1 for SharedDirtyFlag<T, OnMut> {
fn check(&self, arg: &Arg<T>) -> bool {
self.rc.borrow().check(arg)
}
}
// === Set ===
impl<T:DirtyFlagOps0,OnMut:FnMut0>
SharedHasSet0 for SharedDirtyFlag<T,OnMut> {
fn set (&self) { self.rc.borrow_mut().set() }
impl<T: DirtyFlagOps0, OnMut: FnMut0> SharedHasSet0 for SharedDirtyFlag<T, OnMut> {
fn set(&self) {
self.rc.borrow_mut().set()
}
}
impl<T:DirtyFlagOps1,OnMut:FnMut0>
SharedHasSet1 for SharedDirtyFlag<T,OnMut> {
fn set (&self, arg: Arg<T>) { self.rc.borrow_mut().set(arg) }
impl<T: DirtyFlagOps1, OnMut: FnMut0> SharedHasSet1 for SharedDirtyFlag<T, OnMut> {
fn set(&self, arg: Arg<T>) {
self.rc.borrow_mut().set(arg)
}
}
// === Unset ===
impl<T:HasUnset0,OnMut>
SharedHasUnset0 for SharedDirtyFlag<T,OnMut> {
impl<T: HasUnset0, OnMut> SharedHasUnset0 for SharedDirtyFlag<T, OnMut> {
fn unset(&self) {
self.rc.borrow_mut().unset()
}
}
impl<T:HasUnset1,OnMut>
SharedHasUnset1 for SharedDirtyFlag<T,OnMut> where Arg<T>:Display {
impl<T: HasUnset1, OnMut> SharedHasUnset1 for SharedDirtyFlag<T, OnMut>
where Arg<T>: Display
{
fn unset(&self, arg: &Self::Arg) {
self.rc.borrow_mut().unset(arg)
}
@ -312,12 +336,34 @@ pub type SharedBool <OnMut=()> = SharedDirtyFlag <BoolData,OnMut>;
pub trait BoolCtx<OnMut> = where OnMut: FnMut0;
#[derive(Clone, Copy, Debug, Display, Default)]
pub struct BoolData { is_dirty: bool }
impl HasCheckAll for BoolData { fn check_all (&self) -> bool { self.is_dirty } }
impl HasUnsetAll for BoolData { fn unset_all (&mut self) { self.is_dirty = false } }
impl HasCheck0 for BoolData { fn check (& self) -> bool { self.is_dirty } }
impl HasSet0 for BoolData { fn set (&mut self) { self.is_dirty = true } }
impl HasUnset0 for BoolData { fn unset (&mut self) { self.is_dirty = false } }
pub struct BoolData {
is_dirty: bool,
}
impl HasCheckAll for BoolData {
fn check_all(&self) -> bool {
self.is_dirty
}
}
impl HasUnsetAll for BoolData {
fn unset_all(&mut self) {
self.is_dirty = false
}
}
impl HasCheck0 for BoolData {
fn check(&self) -> bool {
self.is_dirty
}
}
impl HasSet0 for BoolData {
fn set(&mut self) {
self.is_dirty = true
}
}
impl HasUnset0 for BoolData {
fn unset(&mut self) {
self.is_dirty = false
}
}
@ -334,11 +380,23 @@ pub trait RangeCtx <OnMut> = where OnMut:FnMut0;
pub trait RangeIx = PartialOrd + Copy + Debug;
#[derive(Debug, Default)]
pub struct RangeData<Ix=usize> { pub range: Option<RangeInclusive<Ix>> }
pub struct RangeData<Ix = usize> {
pub range: Option<RangeInclusive<Ix>>,
}
impl<Ix> HasArg for RangeData<Ix> { type Arg = Ix; }
impl<Ix> HasCheckAll for RangeData<Ix> { fn check_all(&self) -> bool { self.range.is_some() } }
impl<Ix> HasUnsetAll for RangeData<Ix> { fn unset_all(&mut self) { self.range = None } }
impl<Ix> HasArg for RangeData<Ix> {
type Arg = Ix;
}
impl<Ix> HasCheckAll for RangeData<Ix> {
fn check_all(&self) -> bool {
self.range.is_some()
}
}
impl<Ix> HasUnsetAll for RangeData<Ix> {
fn unset_all(&mut self) {
self.range = None
}
}
impl<Ix: RangeIx> HasCheck1 for RangeData<Ix> {
fn check(&self, ix: &Ix) -> bool {
@ -350,11 +408,14 @@ impl<Ix:RangeIx> HasSet1 for RangeData<Ix> {
fn set(&mut self, ix: Ix) {
self.range = match &self.range {
None => Some(ix..=ix),
Some(r) => {
if ix < *r.start() { Some (ix ..= *r.end()) }
else if ix > *r.end() { Some (*r.start() ..= ix) }
else { Some (r.clone()) }
}
Some(r) =>
if ix < *r.start() {
Some(ix..=*r.end())
} else if ix > *r.end() {
Some(*r.start()..=ix)
} else {
Some(r.clone())
},
};
}
}
@ -365,8 +426,12 @@ impl<Ix:RangeIx> HasUnset1 for RangeData<Ix> {
impl<Ix: RangeIx> Display for RangeData<Ix> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.range.as_ref().map(|t|
format!("[{:?}...{:?}]",t.start(),t.end()))
write!(
f,
"{}",
self.range
.as_ref()
.map(|t| format!("[{:?}...{:?}]", t.start(), t.end()))
.unwrap_or_else(|| "false".into())
)
}
@ -390,11 +455,23 @@ pub trait SetItem = Eq + Hash + Debug;
#[derive(Derivative, Shrinkwrap)]
#[derivative(Debug(bound = "Item:SetItem"))]
#[derivative(Default(bound = "Item:SetItem"))]
pub struct SetData<Item> { pub set: FxHashSet<Item> }
pub struct SetData<Item> {
pub set: FxHashSet<Item>,
}
impl<Item> HasArg for SetData<Item> { type Arg = Item; }
impl<Item> HasCheckAll for SetData<Item> { fn check_all(&self) -> bool { !self.set.is_empty() } }
impl<Item> HasUnsetAll for SetData<Item> { fn unset_all(&mut self) { self.set.clear(); } }
impl<Item> HasArg for SetData<Item> {
type Arg = Item;
}
impl<Item> HasCheckAll for SetData<Item> {
fn check_all(&self) -> bool {
!self.set.is_empty()
}
}
impl<Item> HasUnsetAll for SetData<Item> {
fn unset_all(&mut self) {
self.set.clear();
}
}
impl<Item: SetItem> HasCheck1 for SetData<Item> {
fn check(&self, a: &Item) -> bool {
@ -441,11 +518,23 @@ pub trait VectorItem = Debug + PartialEq;
#[derive(Derivative, Debug, Shrinkwrap)]
#[derivative(Default(bound = ""))]
pub struct VectorData<Item> { pub vec: Vec<Item> }
pub struct VectorData<Item> {
pub vec: Vec<Item>,
}
impl<Item> HasArg for VectorData<Item> { type Arg = Item; }
impl<Item> HasCheckAll for VectorData<Item> { fn check_all(&self) -> bool { !self.vec.is_empty() } }
impl<Item> HasUnsetAll for VectorData<Item> { fn unset_all(&mut self) { self.vec.clear(); } }
impl<Item> HasArg for VectorData<Item> {
type Arg = Item;
}
impl<Item> HasCheckAll for VectorData<Item> {
fn check_all(&self) -> bool {
!self.vec.is_empty()
}
}
impl<Item> HasUnsetAll for VectorData<Item> {
fn unset_all(&mut self) {
self.vec.clear();
}
}
impl<Item: PartialEq> HasCheck1 for VectorData<Item> {
fn check(&self, a: &Item) -> bool {
@ -507,7 +596,7 @@ pub type SharedBitField <Prim,OnMut> = SharedEnum <Prim,usize,OnMut>;
#[derivative(Default(bound = "Prim:Default"))]
pub struct EnumData<Prim = u32, T = usize> {
pub bits: Prim,
phantom : PhantomData<T>
phantom: PhantomData<T>,
}
impl<Prim, T> HasArg for EnumData<Prim, T> {

View File

@ -41,7 +41,8 @@
/// }
///
/// impl<T, T1> FnMut1<T1> for Option<T>
/// where T: FnMut1<T1> {
/// where T: FnMut1<T1>
/// {
/// type Output = Option<T::Output>;
/// fn call(&mut self, t1: T1) -> Self::Output {
/// match self {
@ -52,14 +53,14 @@
/// }
///
/// impl<F, T, T1> FnMut1<T1> for F
/// where F: FnMut(T1) -> T {
/// where F: FnMut(T1) -> T
/// {
/// type Output = T;
/// fn call(&mut self, t1: T1) -> Self::Output {
/// self(t1)
/// }
/// }
/// ```
///
macro_rules! define_fn {
($( [$($mut:ident)?] $fn_name:ident $name:ident $(<$($arg:ident),*>)?; )*) => {$(

View File

@ -14,7 +14,7 @@ use crate::prelude::*;
/// Strongly typed value representation in the mix space.
#[allow(missing_docs)]
pub struct Space<T: Mixable> {
pub value : Repr<T>
pub value: Repr<T>,
}
impl<T: Mixable> Space<T> {
@ -25,7 +25,10 @@ impl<T:Mixable> Space<T> {
}
impl<T: Mixable> Debug for Space<T>
where T:Mixable, Repr<T>:Debug {
where
T: Mixable,
Repr<T>: Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Space({:?})", self.value)
}

View File

@ -1,8 +1,8 @@
#![allow(missing_docs)]
use crate::prelude::*;
use crate::data::function::traits::FnMut0;
use crate::data::function::traits::FnMut1;
use crate::prelude::*;
@ -24,16 +24,14 @@ pub struct Observable<T,OnMut,OnResize> {
pub on_resize: OnResize,
}
impl<T:Default,OnMut,OnResize>
Observable<T,OnMut,OnResize> {
impl<T: Default, OnMut, OnResize> Observable<T, OnMut, OnResize> {
pub fn new(on_mut: OnMut, on_resize: OnResize) -> Self {
let data = default();
Self { data, on_mut, on_resize }
}
}
impl<T:Index<Ix>,OnMut,OnResize,Ix>
Index<Ix> for Observable<T,OnMut,OnResize> {
impl<T: Index<Ix>, OnMut, OnResize, Ix> Index<Ix> for Observable<T, OnMut, OnResize> {
type Output = <T as Index<Ix>>::Output;
#[inline]
fn index(&self, index: Ix) -> &Self::Output {
@ -41,8 +39,9 @@ Index<Ix> for Observable<T,OnMut,OnResize> {
}
}
impl<T:IndexMut<Ix>, OnMut: FnMut1<Ix> ,OnResize, Ix:Copy>
IndexMut<Ix> for Observable<T,OnMut,OnResize> {
impl<T: IndexMut<Ix>, OnMut: FnMut1<Ix>, OnResize, Ix: Copy> IndexMut<Ix>
for Observable<T, OnMut, OnResize>
{
#[inline]
fn index_mut(&mut self, index: Ix) -> &mut Self::Output {
self.on_mut.call(index);
@ -50,8 +49,7 @@ IndexMut<Ix> for Observable<T,OnMut,OnResize> {
}
}
impl <T:Extend<S>,S,OnMut,OnResize:FnMut0>
Extend<S> for Observable<T,OnMut,OnResize> {
impl<T: Extend<S>, S, OnMut, OnResize: FnMut0> Extend<S> for Observable<T, OnMut, OnResize> {
#[inline]
fn extend<I: IntoIterator<Item = S>>(&mut self, iter: I) {
self.on_resize.call();

View File

@ -10,9 +10,9 @@ use js_sys::ArrayBuffer;
use js_sys::WebAssembly::Memory;
use std::collections::VecDeque;
use std::f64;
use wasm_bindgen::JsCast;
use wasm_bindgen::prelude::*;
use wasm_bindgen;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
@ -140,7 +140,7 @@ impl Config {
/// as to use `Drop` to clean the HTML when not used anymore.
#[derive(Clone, Debug, Shrinkwrap)]
pub struct Dom {
rc : Rc<DomData>
rc: Rc<DomData>,
}
/// Internal representation of `Dom`.
@ -231,7 +231,9 @@ impl Default for Monitor {
impl Monitor {
/// Cnstructor.
pub fn new() -> Self { default() }
pub fn new() -> Self {
default()
}
/// Modify the Monitor's config and update the view.
pub fn mod_config<F: FnOnce(&mut Config)>(&mut self, f: F) {
@ -326,8 +328,19 @@ impl Monitor {
let width = self.width;
let height = self.height;
let shift = -(self.config.plot_step_size);
dom.context.draw_image_with_html_canvas_element_and_sw_and_sh_and_dx_and_dy_and_dw_and_dh
(&dom.canvas,0.0,0.0,width,height,shift,0.0,self.width,self.height).unwrap();
dom.context
.draw_image_with_html_canvas_element_and_sw_and_sh_and_dx_and_dy_and_dw_and_dh(
&dom.canvas,
0.0,
0.0,
width,
height,
shift,
0.0,
self.width,
self.height,
)
.unwrap();
}
fn clear_labels_area(&mut self, dom: &Dom) {
@ -366,7 +379,6 @@ impl Monitor {
// =============
// === Panel ===
// =============
@ -375,13 +387,12 @@ impl Monitor {
/// a `Sampler` under the hood, which defines both its behavior and its look and feel.
#[derive(Clone, Debug)]
pub struct Panel {
rc: Rc<RefCell<PanelData>>
rc: Rc<RefCell<PanelData>>,
}
impl Panel {
/// Creates a new, empty Panel with a given sampler.
pub fn new<S:Sampler+'static>
(config:SamplerConfig, sampler:S) -> Self {
pub fn new<S: Sampler + 'static>(config: SamplerConfig, sampler: S) -> Self {
let rc = Rc::new(RefCell::new(PanelData::new(config, sampler)));
Self { rc }
}
@ -416,7 +427,11 @@ impl Panel {
/// It affects the way they are visually displayed.
#[derive(Copy, Clone, Debug)]
#[allow(missing_docs)]
pub enum ValueCheck {Correct,Warning,Error}
pub enum ValueCheck {
Correct,
Warning,
Error,
}
impl Default for ValueCheck {
fn default() -> Self {
@ -430,13 +445,21 @@ impl ValueCheck {
/// Construct the check by comparing the provided value to two threshold values.
pub fn from_threshold(warn_threshold: f64, err_threshold: f64, value: f64) -> Self {
if warn_threshold > err_threshold {
if value >= warn_threshold { ValueCheck::Correct }
else if value >= err_threshold { ValueCheck::Warning }
else { ValueCheck::Error }
if value >= warn_threshold {
ValueCheck::Correct
} else if value >= err_threshold {
ValueCheck::Warning
} else {
if value <= warn_threshold { ValueCheck::Correct }
else if value <= err_threshold { ValueCheck::Warning }
else { ValueCheck::Error }
ValueCheck::Error
}
} else {
if value <= warn_threshold {
ValueCheck::Correct
} else if value <= err_threshold {
ValueCheck::Warning
} else {
ValueCheck::Error
}
}
}
}
@ -463,27 +486,39 @@ pub trait Sampler: Debug {
fn value(&self) -> f64;
/// Check whether the newest value is correct, or should be displayed as warning or error.
fn check(&self) -> ValueCheck { ValueCheck::Correct }
fn check(&self) -> ValueCheck {
ValueCheck::Correct
}
/// Returns the maximum expected value in order to set proper scaling of the monitor plots.
/// If the real value will be bigger than this parameter, it will be clamped.
fn max_value(&self) -> Option<f64> { None }
fn max_value(&self) -> Option<f64> {
None
}
/// Returns the minimum expected value in order to set proper scaling of the monitor plots.
/// If the real value will be smaller than this parameter, it will be clamped.
fn min_value(&self) -> Option<f64> { None }
fn min_value(&self) -> Option<f64> {
None
}
/// Returns the maximum expected value in order to set proper scaling of the monitor plots.
/// If the real value will be bigger than this parameter, the graphs will be re-scaled
/// automatically.
fn min_size(&self) -> Option<f64> { None }
fn min_size(&self) -> Option<f64> {
None
}
/// Returns the number describing the amount of last values which should be consideration
/// when displaying the final value. The final value will be the average of # previous values.
fn smooth_range(&self) -> usize { 2 }
fn smooth_range(&self) -> usize {
2
}
/// The number of digits after the dot which should be displayed in the monitor panel.
fn precision(&self) -> usize { 2 }
fn precision(&self) -> usize {
2
}
// === Utils ===
@ -514,7 +549,7 @@ pub struct PanelData {
draw_offset: f64,
value_check: ValueCheck,
precision: usize,
sampler : Box<dyn Sampler>
sampler: Box<dyn Sampler>,
}
@ -522,8 +557,7 @@ pub struct PanelData {
impl PanelData {
/// Constructor.
pub fn new<S:Sampler+'static>
(config:SamplerConfig, sampler:S) -> Self {
pub fn new<S: Sampler + 'static>(config: SamplerConfig, sampler: S) -> Self {
let label = sampler.label().into();
let performance = web::performance();
let min_value = f64::INFINITY;
@ -536,8 +570,21 @@ impl PanelData {
let value_check = default();
let sampler = Box::new(sampler);
let precision = sampler.precision();
Self {label,performance,config,min_value,max_value,begin_value,value,last_values
,norm_value,draw_offset,value_check,precision,sampler}
Self {
label,
performance,
config,
min_value,
max_value,
begin_value,
value,
last_values,
norm_value,
draw_offset,
value_check,
precision,
sampler,
}
}
}
@ -565,13 +612,21 @@ impl PanelData {
/// Clamp the measured values to the `max_value` and `min_value`.
fn clamp_value(&mut self) {
if let Some(max_value) = self.sampler.max_value() {
if self.value > max_value { self.value = max_value; }
if self.value > max_value {
self.value = max_value;
}
}
if let Some(min_value) = self.sampler.min_value() {
if self.value > min_value { self.value = min_value; }
if self.value > min_value {
self.value = min_value;
}
}
if self.value > self.max_value {
self.max_value = self.value;
}
if self.value < self.min_value {
self.min_value = self.value;
}
if self.value > self.max_value { self.max_value = self.value; }
if self.value < self.min_value { self.min_value = self.value; }
}
/// Smooth the final value based on the last measured values.
@ -589,7 +644,9 @@ impl PanelData {
fn normalize_value(&mut self) {
let mut size = self.max_value - self.min_value;
if let Some(min_size) = self.sampler.min_size() {
if size < min_size { size = min_size; }
if size < min_size {
size = min_size;
}
}
self.norm_value = (self.value - self.min_value) / size;
}
@ -645,7 +702,7 @@ impl PanelData {
let color = match self.value_check {
ValueCheck::Correct => &self.config.label_color_ok,
ValueCheck::Warning => &self.config.label_color_warn,
ValueCheck::Error => &self.config.label_color_err
ValueCheck::Error => &self.config.label_color_err,
};
dom.context.set_fill_style(color);
dom.context.fill_text(&display_value, self.config.results_width, y_pos).unwrap();
@ -662,7 +719,7 @@ impl PanelData {
let color = match self.value_check {
ValueCheck::Correct => &self.config.plot_color_ok,
ValueCheck::Warning => &self.config.plot_color_warn,
ValueCheck::Error => &self.config.plot_color_err
ValueCheck::Error => &self.config.plot_color_err,
};
dom.context.set_fill_style(color);
dom.context.fill_rect(0.0, y_pos, self.config.plot_step_size, bar_height);
@ -689,22 +746,32 @@ pub struct FrameTime {
impl FrameTime {
/// Constructor
pub fn new() -> Self { default() }
pub fn new() -> Self {
default()
}
}
const FRAME_TIME_WARNING_THRESHOLD: f64 = 1000.0 / 55.0;
const FRAME_TIME_ERROR_THRESHOLD: f64 = 1000.0 / 25.0;
impl Sampler for FrameTime {
fn label (&self) -> &str { "Frame time (ms)" }
fn value (&self) -> f64 { self.value }
fn check (&self) -> ValueCheck { self.value_check }
fn begin (&mut self, time:f64) { self.begin_time = time; }
fn label(&self) -> &str {
"Frame time (ms)"
}
fn value(&self) -> f64 {
self.value
}
fn check(&self) -> ValueCheck {
self.value_check
}
fn begin(&mut self, time: f64) {
self.begin_time = time;
}
fn end(&mut self, time: f64) {
let end_time = time;
self.value = end_time - self.begin_time;
self.value_check = self.check_by_threshold
(FRAME_TIME_WARNING_THRESHOLD, FRAME_TIME_ERROR_THRESHOLD);
self.value_check =
self.check_by_threshold(FRAME_TIME_WARNING_THRESHOLD, FRAME_TIME_ERROR_THRESHOLD);
}
}
@ -724,17 +791,27 @@ pub struct Fps {
impl Fps {
/// Constructor.
pub fn new() -> Self { default() }
pub fn new() -> Self {
default()
}
}
const FPS_WARNING_THRESHOLD: f64 = 55.0;
const FPS_ERROR_THRESHOLD: f64 = 25.0;
impl Sampler for Fps {
fn label (&self) -> &str { "Frames per second" }
fn value (&self) -> f64 { self.value }
fn check (&self) -> ValueCheck { self.value_check }
fn max_value (&self) -> Option<f64> { Some(60.0) }
fn label(&self) -> &str {
"Frames per second"
}
fn value(&self) -> f64 {
self.value
}
fn check(&self) -> ValueCheck {
self.value_check
}
fn max_value(&self) -> Option<f64> {
Some(60.0)
}
fn begin(&mut self, time: f64) {
if self.begin_time > 0.0 {
let end_time = time;
@ -760,23 +837,33 @@ pub struct WasmMemory {
impl WasmMemory {
/// Constructor.
pub fn new() -> Self { default() }
pub fn new() -> Self {
default()
}
}
const WASM_MEM_WARNING_THRESHOLD: f64 = 50.0;
const WASM_MEM_ERROR_THRESHOLD: f64 = 100.0;
impl Sampler for WasmMemory {
fn label (&self) -> &str { "WASM memory usage (Mb)" }
fn value (&self) -> f64 { self.value }
fn check (&self) -> ValueCheck { self.value_check }
fn min_size (&self) -> Option<f64> { Some(100.0) }
fn label(&self) -> &str {
"WASM memory usage (Mb)"
}
fn value(&self) -> f64 {
self.value
}
fn check(&self) -> ValueCheck {
self.value_check
}
fn min_size(&self) -> Option<f64> {
Some(100.0)
}
fn end(&mut self, _time: f64) {
let memory: Memory = wasm_bindgen::memory().dyn_into().unwrap();
let buffer: ArrayBuffer = memory.buffer().dyn_into().unwrap();
self.value = (buffer.byte_length() as f64) / (1024.0 * 1024.0);
self.value_check = self.check_by_threshold
(WASM_MEM_WARNING_THRESHOLD,WASM_MEM_ERROR_THRESHOLD);
self.value_check =
self.check_by_threshold(WASM_MEM_WARNING_THRESHOLD, WASM_MEM_ERROR_THRESHOLD);
}
}
@ -791,7 +878,6 @@ impl Sampler for WasmMemory {
macro_rules! stats_sampler {
( $label:tt, $name:ident, $stats_method:ident, $t1:expr, $t2:expr, $precision:expr
, $value_divisor:expr) => {
/// Sampler implementation.
#[derive(Debug, Default)]
pub struct $name {
@ -806,13 +892,22 @@ macro_rules! stats_sampler {
}
impl Sampler for $name {
fn label (&self) -> &str { $label }
fn value (&self) -> f64 { self.stats.$stats_method() as f64 / $value_divisor }
fn min_size (&self) -> Option<f64> { Some($t1) }
fn precision (&self) -> usize { $precision }
fn check (&self) -> ValueCheck { self.check_by_threshold($t1,$t2) }
fn label(&self) -> &str {
$label
}
fn value(&self) -> f64 {
self.stats.$stats_method() as f64 / $value_divisor
}
fn min_size(&self) -> Option<f64> {
Some($t1)
}
fn precision(&self) -> usize {
$precision
}
fn check(&self) -> ValueCheck {
self.check_by_threshold($t1, $t2)
}
}
};
}
@ -827,4 +922,12 @@ stats_sampler!("Sprite system count" , SpriteSystemCount , sprite_system_cou
stats_sampler!("Symbol count", SymbolCount, symbol_count, 100.0, 500.0, 0, 1.0);
stats_sampler!("Sprite count", SpriteCount, sprite_count, 100_000.0, 500_000.0, 0, 1.0);
stats_sampler!("Shader count", ShaderCount, shader_count, 100.0, 500.0, 0, 1.0);
stats_sampler!("Shader compile count" , ShaderCompileCount , shader_compile_count , 10.0 , 100.0 , 0 , 1.0);
stats_sampler!(
"Shader compile count",
ShaderCompileCount,
shader_compile_count,
10.0,
100.0,
0,
1.0
);

View File

@ -13,7 +13,7 @@ use crate::prelude::*;
/// Structure containing all the gathered stats.
#[derive(Debug, Clone, CloneRef)]
pub struct Stats {
rc: Rc<RefCell<StatsData>>
rc: Rc<RefCell<StatsData>>,
}
impl Default for Stats {

View File

@ -3,13 +3,13 @@
pub mod camera;
pub mod layout;
pub mod object;
pub mod navigation;
pub mod object;
pub mod render;
pub mod scene;
pub mod shape;
pub mod symbol;
pub mod style;
pub mod symbol;
pub mod world;
@ -26,11 +26,11 @@ pub mod traits {
/// Common types.
pub mod types {
use super::*;
pub use object::Object;
pub use scene::Scene;
pub use scene::dom::DomScene;
pub use super::symbol::*;
pub use super::traits::*;
use super::*;
pub use object::Object;
pub use scene::dom::DomScene;
pub use scene::Scene;
}
pub use types::*;

View File

@ -3,11 +3,11 @@
use crate::prelude::*;
use crate::control::callback;
use crate::data::dirty;
use crate::data::dirty::traits::*;
use crate::display;
use crate::display::scene::Scene;
use crate::data::dirty::traits::*;
use crate::control::callback;
use nalgebra::Perspective3;
@ -54,11 +54,11 @@ pub enum Projection {
/// Perspective projection.
Perspective {
/// Field of view.
fov : f32
fov: f32,
},
/// Orthographic projection.
Orthographic
Orthographic,
}
impl Default for Projection {
@ -79,7 +79,7 @@ impl Default for Projection {
#[allow(missing_docs)]
pub struct Clipping {
pub near: f32,
pub far : f32
pub far: f32,
}
impl Default for Clipping {
@ -102,7 +102,7 @@ impl Default for Clipping {
#[derive(Clone, CloneRef, Debug)]
pub struct Dirty {
projection: ProjectionDirty,
transform : TransformDirty
transform: TransformDirty,
}
impl Dirty {
@ -190,8 +190,19 @@ impl Camera2dData {
display_object.set_on_updated(f_!(dirty.transform.set()));
display_object.mod_position(|p| p.z = 1.0);
dirty.projection.set();
Self {display_object,screen,zoom,z_zoom_1,projection,clipping,matrix,dirty
,zoom_update_registry,screen_update_registry}.init()
Self {
display_object,
screen,
zoom,
z_zoom_1,
projection,
clipping,
matrix,
dirty,
zoom_update_registry,
screen_update_registry,
}
.init()
}
fn init(mut self) -> Self {
@ -221,7 +232,7 @@ impl Camera2dData {
let far = self.clipping.far;
*Perspective3::new(aspect, *fov, near, far).as_matrix()
}
_ => unimplemented!()
_ => unimplemented!(),
};
}
@ -229,7 +240,7 @@ impl Camera2dData {
match &self.projection {
Projection::Perspective { .. } =>
Perspective3::from_matrix_unchecked(self.matrix.projection).inverse(),
_ => unimplemented!()
_ => unimplemented!(),
}
}
@ -291,7 +302,7 @@ impl Camera2dData {
self.z_zoom_1 = z_zoom_1;
self.mod_position_keep_zoom(|t| t.z = z_zoom_1 / zoom);
}
_ => unimplemented!()
_ => unimplemented!(),
};
let dimensions = Vector2::new(width, height);
self.screen_update_registry.run_all(&dimensions);
@ -350,8 +361,8 @@ impl Camera2dData {
/// drawing elements and scaling the view. By default, the `alignment` is set to center, which
/// defines the origin center at the center of the screen. When scaling the view, objects placed
/// in the center of the view will not move visually. If you set the alignment to bottom-left
/// corner, you will get a view which behaves like a window in window-based GUIs. When scaling
/// the window, the left-bottom corner will stay in place.
/// corner, you will get a view which behaves like a window in window-based GUIs. When scaling the
/// window, the left-bottom corner will stay in place.
#[derive(Clone, CloneRef, Debug)]
pub struct Camera2d {
display_object: display::object::Instance,

View File

@ -20,12 +20,20 @@ pub struct Alignment {
/// Horizontal alignments.
#[derive(Clone, Copy, Debug)]
#[allow(missing_docs)]
pub enum Horizontal {Left,Center,Right}
pub enum Horizontal {
Left,
Center,
Right,
}
/// Vertical alignments.
#[derive(Clone, Copy, Debug)]
#[allow(missing_docs)]
pub enum Vertical {Top,Center,Bottom}
pub enum Vertical {
Top,
Center,
Bottom,
}
// === Smart Constructors ===
@ -38,22 +46,48 @@ impl Alignment {
Self { horizontal, vertical }
}
pub fn center () -> Self { Self::new( Horizontal::Center , Vertical::Center ) }
pub fn bottom_left () -> Self { Self::new( Horizontal::Left , Vertical::Bottom ) }
pub fn bottom_right () -> Self { Self::new( Horizontal::Right , Vertical::Bottom ) }
pub fn bottom_center () -> Self { Self::new( Horizontal::Center , Vertical::Bottom ) }
pub fn top_left () -> Self { Self::new( Horizontal::Left , Vertical::Top ) }
pub fn top_right () -> Self { Self::new( Horizontal::Right , Vertical::Top ) }
pub fn top_center () -> Self { Self::new( Horizontal::Center , Vertical::Top ) }
pub fn center_left () -> Self { Self::new( Horizontal::Left , Vertical::Center ) }
pub fn center_right () -> Self { Self::new( Horizontal::Right , Vertical::Center ) }
pub fn center() -> Self {
Self::new(Horizontal::Center, Vertical::Center)
}
pub fn bottom_left() -> Self {
Self::new(Horizontal::Left, Vertical::Bottom)
}
pub fn bottom_right() -> Self {
Self::new(Horizontal::Right, Vertical::Bottom)
}
pub fn bottom_center() -> Self {
Self::new(Horizontal::Center, Vertical::Bottom)
}
pub fn top_left() -> Self {
Self::new(Horizontal::Left, Vertical::Top)
}
pub fn top_right() -> Self {
Self::new(Horizontal::Right, Vertical::Top)
}
pub fn top_center() -> Self {
Self::new(Horizontal::Center, Vertical::Top)
}
pub fn center_left() -> Self {
Self::new(Horizontal::Left, Vertical::Center)
}
pub fn center_right() -> Self {
Self::new(Horizontal::Right, Vertical::Center)
}
}
// === Defaults ===
impl Default for Horizontal { fn default() -> Self { Self::Left } }
impl Default for Vertical { fn default() -> Self { Self::Bottom } }
impl Default for Horizontal {
fn default() -> Self {
Self::Left
}
}
impl Default for Vertical {
fn default() -> Self {
Self::Bottom
}
}
impl Default for Alignment {
fn default() -> Self {
let horizontal = default();
@ -62,6 +96,18 @@ impl Default for Alignment {
}
}
impl From<&Horizontal> for Horizontal { fn from(t:&Horizontal) -> Self { *t } }
impl From<&Vertical> for Vertical { fn from(t:&Vertical) -> Self { *t } }
impl From<&Alignment> for Alignment { fn from(t:&Alignment) -> Self { *t } }
impl From<&Horizontal> for Horizontal {
fn from(t: &Horizontal) -> Self {
*t
}
}
impl From<&Vertical> for Vertical {
fn from(t: &Vertical) -> Self {
*t
}
}
impl From<&Alignment> for Alignment {
fn from(t: &Alignment) -> Self {
*t
}
}

View File

@ -38,9 +38,15 @@ impl NavigatorModel {
let min_zoom = 10.0;
let max_zoom = 10000.0;
let disable_events = Rc::new(Cell::new(true));
let (simulator,resize_callback,_events) = Self::start_navigator_events
(scene,camera,min_zoom,max_zoom,Rc::clone(&zoom_speed),Rc::clone(&pan_speed),
Rc::clone(&disable_events));
let (simulator, resize_callback, _events) = Self::start_navigator_events(
scene,
camera,
min_zoom,
max_zoom,
Rc::clone(&zoom_speed),
Rc::clone(&pan_speed),
Rc::clone(&disable_events),
);
Self { _events, simulator, resize_callback, zoom_speed, pan_speed, disable_events }
}
@ -55,14 +61,14 @@ impl NavigatorModel {
simulator
}
fn start_navigator_events
( scene : &Scene
, camera : &Camera2d
, min_zoom : f32
, max_zoom : f32
, zoom_speed : SharedSwitch<f32>
, pan_speed : SharedSwitch<f32>
, disable_events : Rc<Cell<bool>>
fn start_navigator_events(
scene: &Scene,
camera: &Camera2d,
min_zoom: f32,
max_zoom: f32,
zoom_speed: SharedSwitch<f32>,
pan_speed: SharedSwitch<f32>,
disable_events: Rc<Cell<bool>>,
) -> (physics::inertia::DynSimulator<Vector3>, callback::Handle, NavigatorEvents) {
let simulator = Self::create_simulator(camera);
let panning_callback = enclose!((scene,camera,mut simulator,pan_speed) move |pan: PanEvent| {
@ -81,7 +87,7 @@ impl NavigatorModel {
simulator.set_value(position);
simulator.set_target_value(position);
simulator.set_velocity(default());
})
}),
);
let zoom_callback = enclose!((scene,camera,simulator) move |zoom:ZoomEvent| {
@ -109,9 +115,18 @@ impl NavigatorModel {
position += direction * zoom_factor;
simulator.set_target_value(position);
});
(simulator,resize_callback, NavigatorEvents::new(&scene.mouse.mouse_manager,
panning_callback,zoom_callback,
zoom_speed,pan_speed,disable_events))
(
simulator,
resize_callback,
NavigatorEvents::new(
&scene.mouse.mouse_manager,
panning_callback,
zoom_callback,
zoom_speed,
pan_speed,
disable_events,
),
)
}
pub fn enable(&self) {
@ -145,7 +160,6 @@ impl Navigator {
let model = Rc::new(NavigatorModel::new(scene, camera));
Navigator { model }
}
}
@ -157,8 +171,7 @@ impl Navigator {
type SharedSwitch<T> = Rc<Cell<Switch<T>>>;
/// Normalize a `point` in (0..dimension.x, 0..dimension.y) to (0..1, 0..1).
fn normalize_point2
(point:Vector2<f32>, dimension:Vector2<f32>) -> Vector2<f32> {
fn normalize_point2(point: Vector2<f32>, dimension: Vector2<f32>) -> Vector2<f32> {
Vector2::new(point.x / dimension.x, point.y / dimension.y)
}

View File

@ -1,12 +1,12 @@
use crate::prelude::*;
use crate::control::callback;
use crate::control::io::mouse;
use crate::control::io::mouse::MouseManager;
use crate::control::callback;
use crate::display::navigation::navigator::SharedSwitch;
use nalgebra::Vector2;
use nalgebra::zero;
use nalgebra::Vector2;
@ -19,7 +19,7 @@ pub trait FnZoomEvent = FnMut(ZoomEvent) + 'static;
/// A struct holding zoom event information, such as the focus point and the amount of zoom.
pub struct ZoomEvent {
pub focus: Vector2<f32>,
pub amount : f32
pub amount: f32,
}
impl ZoomEvent {
@ -39,7 +39,7 @@ pub trait FnPanEvent = FnMut(PanEvent) + 'static;
/// A struct holding pan event information.
pub struct PanEvent {
pub movement : Vector2<f32>
pub movement: Vector2<f32>,
}
impl PanEvent {
@ -57,7 +57,7 @@ impl PanEvent {
#[derive(PartialEq, Clone, Copy, Debug)]
enum MovementType {
Pan,
Zoom { focus : Vector2<f32> }
Zoom { focus: Vector2<f32> },
}
@ -89,16 +89,17 @@ struct NavigatorEventsProperties {
#[derive(Debug)]
struct NavigatorEventsData {
properties : RefCell<NavigatorEventsProperties>
properties: RefCell<NavigatorEventsProperties>,
}
impl NavigatorEventsData {
fn new
( pan_callback:Box<dyn FnPanEvent>
, zoom_callback:Box<dyn FnZoomEvent>
, zoom_speed:SharedSwitch<f32>
, pan_speed:SharedSwitch<f32>
, disable_events:Rc<Cell<bool>>) -> Rc<Self> {
fn new(
pan_callback: Box<dyn FnPanEvent>,
zoom_callback: Box<dyn FnZoomEvent>,
zoom_speed: SharedSwitch<f32>,
pan_speed: SharedSwitch<f32>,
disable_events: Rc<Cell<bool>>,
) -> Rc<Self> {
let mouse_position = zero();
let last_mouse_position = zero();
let movement_type = None;
@ -111,7 +112,6 @@ impl NavigatorEventsData {
mouse_position,
pan_callback,
zoom_callback,
});
Rc::new(Self { properties })
}
@ -189,14 +189,22 @@ pub struct NavigatorEvents {
#[derivative(Debug = "ignore")]
mouse_leave: Option<callback::Handle>,
#[derivative(Debug = "ignore")]
wheel_zoom : Option<callback::Handle>
wheel_zoom: Option<callback::Handle>,
}
impl NavigatorEvents {
pub fn new
<P,Z>(mouse_manager:&MouseManager, pan_callback:P, zoom_callback:Z,
zoom_speed:SharedSwitch<f32>,pan_speed:SharedSwitch<f32>,disable_events:Rc<Cell<bool>>) -> Self
where P : FnPanEvent, Z : FnZoomEvent {
pub fn new<P, Z>(
mouse_manager: &MouseManager,
pan_callback: P,
zoom_callback: Z,
zoom_speed: SharedSwitch<f32>,
pan_speed: SharedSwitch<f32>,
disable_events: Rc<Cell<bool>>,
) -> Self
where
P: FnPanEvent,
Z: FnZoomEvent,
{
let mouse_manager = mouse_manager.clone_ref();
let pan_callback = Box::new(pan_callback);
let zoom_callback = Box::new(zoom_callback);
@ -205,17 +213,15 @@ impl NavigatorEvents {
let mouse_down = default();
let wheel_zoom = default();
let mouse_leave = default();
let data = NavigatorEventsData::new
(pan_callback,zoom_callback,zoom_speed,pan_speed,disable_events);
let mut event_handler = Self {
data,
mouse_manager,
mouse_down,
mouse_up,
mouse_move,
mouse_leave,
wheel_zoom
};
let data = NavigatorEventsData::new(
pan_callback,
zoom_callback,
zoom_speed,
pan_speed,
disable_events,
);
let mut event_handler =
Self { data, mouse_manager, mouse_down, mouse_up, mouse_move, mouse_leave, wheel_zoom };
event_handler.initialize_mouse_events();
event_handler
@ -267,14 +273,12 @@ impl NavigatorEvents {
event.prevent_default();
}
match event.button() {
mouse::MiddleButton => {
data.set_movement_type(Some(MovementType::Pan))
},
mouse::MiddleButton => data.set_movement_type(Some(MovementType::Pan)),
mouse::SecondaryButton => {
let focus = event.position_relative_to_event_handler();
data.set_movement_type(Some(MovementType::Zoom { focus }))
},
_ => ()
}
_ => (),
}
}
});
@ -324,7 +328,7 @@ impl NavigatorEvents {
let zoom_amount = movement_to_zoom(movement);
let zoom_event = ZoomEvent::new(focus, zoom_amount, zoom_speed);
data.on_zoom(zoom_event);
},
}
MovementType::Pan => {
let pan_event = PanEvent::new(movement);
data.on_pan(pan_event);

View File

@ -6,11 +6,11 @@ use crate::prelude::*;
use super::transform;
use crate::data::dirty::traits::*;
use crate::data::dirty;
use crate::display::scene::Scene;
use crate::data::dirty::traits::*;
use crate::display::scene::layer::Layer;
use crate::display::scene::layer::WeakLayer;
use crate::display::scene::Scene;
use data::opt_vec::OptVec;
use nalgebra::Matrix4;
@ -31,7 +31,7 @@ use transform::CachedTransform;
#[allow(missing_docs)]
pub struct ParentBind<Host> {
pub parent: WeakInstance<Host>,
pub index : usize
pub index: usize,
}
impl<Host> ParentBind<Host> {
@ -69,20 +69,32 @@ pub struct Callbacks<Host> {
impl<Host> Callbacks<Host> {
fn on_updated(&self, model: &Model<Host>) {
if let Some(f) = &*self.on_updated.borrow() { f(model) }
if let Some(f) = &*self.on_updated.borrow() {
f(model)
}
}
fn on_show(&self, host: &Host, layers: &[WeakLayer]) {
if let Some(f) = &*self.on_show.borrow() { f(host,layers) }
if let Some(f) = &*self.on_show.borrow() {
f(host, layers)
}
}
fn on_hide(&self, host: &Host) {
if let Some(f) = &*self.on_hide.borrow() { f(host) }
if let Some(f) = &*self.on_hide.borrow() {
f(host)
}
}
fn on_scene_layers_changed
(&self, host:&Host, old_layers:&[WeakLayer], new_layers:&[WeakLayer]) {
if let Some(f) = &*self.on_scene_layers_changed.borrow() { f(host,old_layers,new_layers) }
fn on_scene_layers_changed(
&self,
host: &Host,
old_layers: &[WeakLayer],
new_layers: &[WeakLayer],
) {
if let Some(f) = &*self.on_scene_layers_changed.borrow() {
f(host, old_layers, new_layers)
}
}
}
@ -217,8 +229,18 @@ impl<Host> Model<Host> {
let host = default();
let assigned_layers = default();
let layers = default();
Self {host,assigned_layers,layers,dirty,callbacks,parent_bind,children,transform
,visible,logger}
Self {
host,
assigned_layers,
layers,
dirty,
callbacks,
parent_bind,
children,
transform,
visible,
logger,
}
}
/// Checks whether the object is visible.
@ -278,13 +300,13 @@ impl<Host> Model<Host> {
impl<Host> Model<Host> {
/// Updates object transformations by providing a new origin location. See docs of `update` to
/// learn more.
fn update_with_origin
( &self
, host : &Host
, parent_origin : Matrix4<f32>
, parent_origin_changed : bool
, parent_layers_changed : bool
, parent_layers : &[WeakLayer]
fn update_with_origin(
&self,
host: &Host,
parent_origin: Matrix4<f32>,
parent_origin_changed: bool,
parent_layers_changed: bool,
parent_layers: &[WeakLayer],
) {
// === Scene Layers Update ===
let has_new_parent = self.dirty.parent.check();
@ -307,9 +329,13 @@ impl<Host> Model<Host> {
parent_layers_changed
};
let new_layers_opt = layers_changed.as_some_from(||
if has_assigned_layers {assigned_layers} else {parent_layers}
);
let new_layers_opt = layers_changed.as_some_from(|| {
if has_assigned_layers {
assigned_layers
} else {
parent_layers
}
});
if let Some(new_layers) = new_layers_opt {
debug!(self.logger, "Scene layers changed.", || {
let old_layers = mem::replace(&mut *self.layers.borrow_mut(), new_layers.to_vec());
@ -340,10 +366,15 @@ impl<Host> Model<Host> {
if !self.children.borrow().is_empty() {
debug!(self.logger, "Updating all children.", || {
self.children.borrow().iter().for_each(|weak_child| {
weak_child.upgrade().for_each(|child|
child.update_with_origin
(host,new_origin,true,layers_changed,new_layers)
);
weak_child.upgrade().for_each(|child| {
child.update_with_origin(
host,
new_origin,
true,
layers_changed,
new_layers,
)
});
});
})
}
@ -352,10 +383,19 @@ impl<Host> Model<Host> {
if self.dirty.children.check_all() {
debug!(self.logger, "Updating dirty children.", || {
self.dirty.children.take().iter().for_each(|ix| {
self.children.borrow().safe_index(*ix).and_then(|t|t.upgrade())
.for_each(|child|
child.update_with_origin
(host,new_origin,false,layers_changed,new_layers))
self.children
.borrow()
.safe_index(*ix)
.and_then(|t| t.upgrade())
.for_each(|child| {
child.update_with_origin(
host,
new_origin,
false,
layers_changed,
new_layers,
)
})
});
})
}
@ -410,8 +450,11 @@ impl<Host> Model<Host> {
info!(self.logger, "Showing.");
let this_scene_layers = self.assigned_layers.borrow();
let this_scene_layers_slice = this_scene_layers.as_slice();
let layers = if this_scene_layers_slice.is_empty()
{ parent_layers } else { this_scene_layers_slice };
let layers = if this_scene_layers_slice.is_empty() {
parent_layers
} else {
this_scene_layers_slice
};
self.visible.set(true);
self.callbacks.on_show(host, layers);
self.children.borrow().iter().for_each(|child| {
@ -551,7 +594,10 @@ impl<Host> Model<Host> {
// ==========
/// Globally unique identifier of a display object.
#[derive(Clone,CloneRef,Copy,Debug,Default,Display,Eq,From,Hash,Into,PartialEq,Ord,PartialOrd)]
#[derive(
Clone, CloneRef, Copy, Debug, Default, Display, Eq, From, Hash, Into, PartialEq, Ord,
PartialOrd
)]
pub struct Id(usize);
@ -595,7 +641,7 @@ pub struct Id(usize);
#[derive(CloneRef)]
#[derivative(Clone(bound = ""))]
pub struct Instance<Host = Scene> {
rc : Rc<Model<Host>>
rc: Rc<Model<Host>>,
}
impl<Host> Deref for Instance<Host> {
@ -629,7 +675,9 @@ impl<Host> Instance<Host> {
/// Get the layers where this object is displayed. May be equal to layers it was explicitly
/// assigned, or layers inherited from the parent.
pub fn _display_layers(&self) -> Vec<WeakLayer> { self.layers.borrow().clone() }
pub fn _display_layers(&self) -> Vec<WeakLayer> {
self.layers.borrow().clone()
}
/// Add this object to the provided scene layer and remove it from all other layers. Do not use
/// this method explicitly. Use layers' methods instead.
@ -708,7 +756,11 @@ impl<Host> Instance<Host> {
pub fn child_index<T: Object<Host>>(&self, child: &T) -> Option<usize> {
let child = child.display_object();
child.parent_bind.borrow().as_ref().and_then(|bind| {
if bind.parent().as_ref() == Some(self) { Some(bind.index) } else { None }
if bind.parent().as_ref() == Some(self) {
Some(bind.index)
} else {
None
}
})
}
}
@ -759,7 +811,7 @@ impl<Host> Debug for Instance<Host> {
#[derivative(Clone(bound = ""))]
#[derivative(Debug(bound = ""))]
pub struct WeakInstance<Host> {
weak : Weak<Model<Host>>
weak: Weak<Model<Host>>,
}
impl<Host> WeakInstance<Host> {
@ -843,7 +895,9 @@ pub trait ObjectOps<Host=Scene> : Object<Host> {
/// Get the layers where this object is displayed. May be equal to layers it was explicitly
/// assigned, or layers inherited from the parent.
fn display_layers(&self) -> Vec<WeakLayer> { self.display_object()._display_layers() }
fn display_layers(&self) -> Vec<WeakLayer> {
self.display_object()._display_layers()
}
/// Add another display object as a child to this display object. Children will inherit all
/// transformations of their parents.
@ -1118,19 +1172,25 @@ pub trait ObjectOps<Host=Scene> : Object<Host> {
/// with base implementation `From<T> for T`.
#[derive(CloneRef)]
pub struct Any<Host = Scene> {
wrapped : Rc<dyn Object<Host>>
wrapped: Rc<dyn Object<Host>>,
}
impl<Host> Clone for Any<Host> {
fn clone(&self) -> Self { Self {wrapped:self.wrapped.clone()} }
fn clone(&self) -> Self {
Self { wrapped: self.wrapped.clone() }
}
}
impl<Host> Debug for Any<Host> {
fn fmt(&self, f:&mut fmt::Formatter) -> fmt::Result { write!(f, "display::object::Any") }
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "display::object::Any")
}
}
impl<Host> Object<Host> for Any<Host> {
fn display_object(&self) -> &Instance<Host> { self.wrapped.display_object() }
fn display_object(&self) -> &Instance<Host> {
self.wrapped.display_object()
}
}
@ -1251,11 +1311,15 @@ mod tests {
impl Deref for TestedNode {
type Target = Instance<()>;
fn deref(&self) -> &Self::Target { &self.node }
fn deref(&self) -> &Self::Target {
&self.node
}
}
impl Object<()> for TestedNode {
fn display_object(&self) -> &Instance<()> { &self.node }
fn display_object(&self) -> &Instance<()> {
&self.node
}
}
impl TestedNode {
@ -1293,8 +1357,12 @@ mod tests {
assert_eq!(self.hide_counter.get(), 0);
}
fn check_if_still_shown(&self) { self.check_if_visibility_did_not_changed(true) }
fn check_if_still_hidden(&self) { self.check_if_visibility_did_not_changed(false) }
fn check_if_still_shown(&self) {
self.check_if_visibility_did_not_changed(true)
}
fn check_if_still_hidden(&self) {
self.check_if_visibility_did_not_changed(false)
}
}
#[test]
@ -1418,7 +1486,6 @@ mod tests {
#[test]
fn deep_hierarchy_test() {
// === Init ===
let world = Instance::<()>::new(Logger::new("world"));

View File

@ -11,10 +11,19 @@ use crate::prelude::*;
/// Defines the order in which particular axis coordinates are processed. Used for example to define
/// the rotation order in `DisplayObject`.
#[derive(Clone, Copy, Debug)]
pub enum AxisOrder {XYZ,XZY,YXZ,YZX,ZXY,ZYX}
pub enum AxisOrder {
XYZ,
XZY,
YXZ,
YZX,
ZXY,
ZYX,
}
impl Default for AxisOrder {
fn default() -> Self { Self::XYZ }
fn default() -> Self {
Self::XYZ
}
}
@ -32,11 +41,13 @@ pub enum TransformOrder {
RotateScaleTranslate,
RotateTranslateScale,
TranslateRotateScale,
TranslateScaleRotate
TranslateScaleRotate,
}
impl Default for TransformOrder {
fn default() -> Self { Self::ScaleRotateTranslate }
fn default() -> Self {
Self::ScaleRotateTranslate
}
}
@ -71,7 +82,9 @@ impl Default for Transform {
impl Transform {
/// Creates a new transformation object.
pub fn new() -> Self { default() }
pub fn new() -> Self {
default()
}
/// Computes transformation matrix from the provided scale, rotation, and
/// translation components, based on the transformation and rotation orders.

View File

@ -105,12 +105,12 @@ impl DerefMut for ComposerPass {
impl ComposerPass {
/// Constructor
#[allow(clippy::borrowed_box)]
pub fn new
( context : &Context
, variables : &UniformScope
, mut pass : Box<dyn pass::Definition>
, width : i32
, height : i32
pub fn new(
context: &Context,
variables: &UniformScope,
mut pass: Box<dyn pass::Definition>,
width: i32,
height: i32,
) -> Self {
let instance = pass::Instance::new(context, variables, width, height);
pass.initialize(&instance);

View File

@ -2,8 +2,8 @@
use crate::prelude::*;
use crate::system::gpu::*;
use crate::system::gpu::data::texture::class::TextureOps;
use crate::system::gpu::*;
@ -48,12 +48,7 @@ pub struct Instance {
impl Instance {
/// Constructor
#[allow(clippy::borrowed_box)]
pub fn new
( context : &Context
, variables : &UniformScope
, width : i32
, height : i32
) -> Self {
pub fn new(context: &Context, variables: &UniformScope, width: i32, height: i32) -> Self {
let variables = variables.clone_ref();
let context = context.clone();
Self { variables, context, width, height }
@ -69,7 +64,9 @@ impl Instance {
let format = output.internal_format;
let item_type = output.item_type;
let params = Some(output.texture_parameters);
uniform::get_or_add_gpu_texture_dyn(context,variables,&name,format,item_type,args,params)
uniform::get_or_add_gpu_texture_dyn(
context, variables, &name, format, item_type, args, params,
)
}
/// Create a new framebuffer from the provided textures.
@ -86,7 +83,13 @@ impl Instance {
let gl_texture = Some(&gl_texture);
let level = 0;
draw_buffers.push(&attachment_point.into());
context.framebuffer_texture_2d(target,attachment_point,texture_target,gl_texture,level);
context.framebuffer_texture_2d(
target,
attachment_point,
texture_target,
gl_texture,
level,
);
}
context.draw_buffers(&draw_buffers);
context.bind_framebuffer(target, None);
@ -113,8 +116,12 @@ pub struct OutputDefinition {
impl OutputDefinition {
/// Constructor.
pub fn new<Name:Str,F:Into<texture::AnyInternalFormat>,T:Into<texture::AnyItemType>>
(name:Name, internal_format:F, item_type:T, texture_parameters:texture::Parameters) -> Self {
pub fn new<Name: Str, F: Into<texture::AnyInternalFormat>, T: Into<texture::AnyItemType>>(
name: Name,
internal_format: F,
item_type: T,
texture_parameters: texture::Parameters,
) -> Self {
let name = name.into();
let internal_format = internal_format.into();
let item_type = item_type.into();

View File

@ -1,16 +1,16 @@
//! Root module for render passes definitions.
pub mod symbols;
pub mod pixel_read;
pub mod screen;
pub mod symbols;
/// Common types.
pub mod types {
use super::*;
pub use symbols::*;
pub use pixel_read::*;
pub use screen::*;
pub use symbols::*;
}
pub use types::*;

View File

@ -3,8 +3,8 @@
use crate::prelude::*;
use crate::display::render::pass;
use crate::system::gpu::*;
use crate::system::gpu::data::texture::class::TextureOps;
use crate::system::gpu::*;
use crate::system::js::*;
use web_sys::WebGlBuffer;
@ -29,12 +29,12 @@ pub struct PixelReadPassData<T:JsTypedArrayItem> {
impl<T: JsTypedArrayItem> PixelReadPassData<T> {
/// Constructor.
pub fn new
( buffer : WebGlBuffer
, framebuffer : WebGlFramebuffer
, format : texture::AnyFormat
, item_type : texture::AnyItemType
, js_array : JsTypedArray<T>
pub fn new(
buffer: WebGlBuffer,
framebuffer: WebGlFramebuffer,
format: texture::AnyFormat,
item_type: texture::AnyItemType,
js_array: JsTypedArray<T>,
) -> Self {
Self { buffer, framebuffer, format, item_type, js_array }
}
@ -96,7 +96,7 @@ impl<T:JsTypedArrayItem> PixelReadPass<T> {
let texture = match variables.get("pass_id").unwrap() {
uniform::AnyUniform::Texture(t) => t,
_ => panic!("Pass internal error. Unmatched types.")
_ => panic!("Pass internal error. Unmatched types."),
};
let format = texture.get_format();
let item_type = texture.get_item_type();
@ -108,7 +108,13 @@ impl<T:JsTypedArrayItem> PixelReadPass<T> {
let gl_texture = Some(&gl_texture);
let level = 0;
context.bind_framebuffer(target, Some(&framebuffer));
context.framebuffer_texture_2d(target,attachment_point,texture_target,gl_texture,level);
context.framebuffer_texture_2d(
target,
attachment_point,
texture_target,
gl_texture,
level,
);
let data = PixelReadPassData::new(buffer, framebuffer, format, item_type, js_array);
self.data = Some(data);
@ -125,7 +131,9 @@ impl<T:JsTypedArrayItem> PixelReadPass<T> {
let offset = 0;
context.bind_framebuffer(Context::FRAMEBUFFER, Some(&data.framebuffer));
context.bind_buffer(Context::PIXEL_PACK_BUFFER, Some(&data.buffer));
context.read_pixels_with_i32(position.x,position.y,width,height,format,typ,offset).unwrap();
context
.read_pixels_with_i32(position.x, position.y, width, height, format, typ, offset)
.unwrap();
let condition = Context::SYNC_GPU_COMMANDS_COMPLETE;
let flags = 0;
let sync = context.fence_sync(condition, flags).unwrap();

View File

@ -3,12 +3,12 @@
use crate::prelude::*;
use crate::display::render::pass;
use crate::display::scene::layer;
use crate::display::scene;
use crate::display::scene::layer;
use crate::display::scene::Scene;
use crate::display::symbol::registry::SymbolRegistry;
use crate::system::gpu::*;
use crate::display::symbol::MaskComposer;
use crate::system::gpu::*;
@ -24,11 +24,7 @@ struct Framebuffers {
}
impl Framebuffers {
fn new
( composed : pass::Framebuffer
, mask : pass::Framebuffer
, layer : pass::Framebuffer
) -> Self {
fn new(composed: pass::Framebuffer, mask: pass::Framebuffer, layer: pass::Framebuffer) -> Self {
Self { composed, mask, layer }
}
}
@ -46,19 +42,19 @@ pub struct SymbolsRenderPass {
impl SymbolsRenderPass {
/// Constructor.
pub fn new
( logger : impl AnyLogger
, scene : &Scene
, symbol_registry : &SymbolRegistry
, layers : &scene::HardcodedLayers
pub fn new(
logger: impl AnyLogger,
scene: &Scene,
symbol_registry: &SymbolRegistry,
layers: &scene::HardcodedLayers,
) -> Self {
let logger = Logger::new_sub(logger, "SymbolsRenderPass");
let symbol_registry = symbol_registry.clone_ref();
let layers = layers.clone_ref();
let framebuffers = default();
let scene = scene.clone_ref();
let mask_composer = MaskComposer::new
(&scene,"pass_mask_color","pass_layer_color","pass_layer_id");
let mask_composer =
MaskComposer::new(&scene, "pass_mask_color", "pass_layer_color", "pass_layer_id");
Self { logger, symbol_registry, layers, framebuffers, scene, mask_composer }
}
}
@ -106,8 +102,11 @@ impl pass::Definition for SymbolsRenderPass {
let mut scissor_stack = default();
self.render_layer(instance, &self.layers.root.clone(), &mut scissor_stack, false);
if !scissor_stack.is_empty() {
warning!(&self.logger,"The scissor stack was not cleaned properly. \
This is an internal bug that may lead to visual artifacts. Please report it.");
warning!(
&self.logger,
"The scissor stack was not cleaned properly. \
This is an internal bug that may lead to visual artifacts. Please report it."
);
}
instance.context.bind_framebuffer(Context::FRAMEBUFFER, None);
}
@ -122,7 +121,13 @@ impl SymbolsRenderPass {
instance.context.disable(web_sys::WebGl2RenderingContext::SCISSOR_TEST);
}
fn render_layer(&mut self, instance:&pass::Instance, layer:&layer::Layer, scissor_stack:&mut Vec<layer::ScissorBox>, parent_masked:bool) {
fn render_layer(
&mut self,
instance: &pass::Instance,
layer: &layer::Layer,
scissor_stack: &mut Vec<layer::ScissorBox>,
parent_masked: bool,
) {
let framebuffers = self.framebuffers.as_ref().unwrap();
let parent_scissor_box = scissor_stack.first().copied();
let layer_scissor_box = layer.scissor_box();
@ -131,7 +136,9 @@ impl SymbolsRenderPass {
let first_scissor_usage = scissor_box_changed && parent_scissor_box.is_none();
if let Some(scissor_box) = scissor_box {
if scissor_box_changed {
if first_scissor_usage { self.enable_scissor_test(instance) }
if first_scissor_usage {
self.enable_scissor_test(instance)
}
scissor_stack.push(scissor_box);
let position = scissor_box.position();
let size = scissor_box.size();
@ -145,7 +152,10 @@ impl SymbolsRenderPass {
let nested_masking = is_masked && parent_masked;
if nested_masking {
warning!(&self.logger,"Nested layer masking is not supported yet. Skipping nested masks.");
warning!(
&self.logger,
"Nested layer masking is not supported yet. Skipping nested masks."
);
} else if let Some(mask) = layer_mask {
framebuffers.mask.bind();
let arr = vec![0.0, 0.0, 0.0, 0.0];
@ -174,7 +184,9 @@ impl SymbolsRenderPass {
if scissor_box_changed {
scissor_stack.pop();
if first_scissor_usage { self.disable_scissor_test(instance) }
if first_scissor_usage {
self.disable_scissor_test(instance)
}
}
}
}

View File

@ -13,31 +13,31 @@ use crate::prelude::*;
use crate::animation;
use crate::control::callback;
use crate::control::io::mouse::MouseManager;
use crate::control::io::mouse;
use crate::data::dirty::traits::*;
use crate::control::io::mouse::MouseManager;
use crate::data::dirty;
use crate::data::dirty::traits::*;
use crate::debug::stats::Stats;
use crate::display;
use crate::display::camera::Camera2d;
use crate::display::render;
use crate::display::scene::dom::DomScene;
use crate::display::shape::ShapeSystemInstance;
use crate::display::shape::system::ShapeSystemOf;
use crate::display::shape::system::StaticShapeSystemInstance;
use crate::display::style::data::DataMatch;
use crate::display::shape::ShapeSystemInstance;
use crate::display::style;
use crate::display::style::data::DataMatch;
use crate::display::symbol::registry::SymbolRegistry;
use crate::display::symbol::Symbol;
use crate::display::symbol::SymbolId;
use crate::display::symbol::registry::SymbolRegistry;
use crate::display;
use crate::system::gpu::data::attribute;
use crate::system::gpu::data::uniform::Uniform;
use crate::system::gpu::data::uniform::UniformScope;
use crate::system::gpu::shader::Context;
use crate::system::web;
use crate::system::web::IgnoreContextMenuHandle;
use crate::system::web::NodeInserter;
use crate::system::web::StyleSetter;
use crate::system::web;
use enso_frp as frp;
use enso_frp::io::js::CurrentJsEvent;
@ -55,7 +55,6 @@ pub trait MouseTarget : Debug + 'static {
// =====================
// === ShapeRegistry ===
// =====================
@ -132,21 +131,17 @@ enum DecodingResult{
/// Values had to be truncated.
Truncated(u8, u8, u8),
/// Values have been encoded successfully.
Ok(u8,u8,u8)
Ok(u8, u8, u8),
}
/// Mouse target. Contains a path to an object pointed by mouse.
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum PointerTarget {
Background,
Symbol {
symbol_id : SymbolId,
instance_id : attribute::InstanceIndex,
}
Symbol { symbol_id: SymbolId, instance_id: attribute::InstanceIndex },
}
impl PointerTarget {
/// Encode two u32 values into three u8 values.
///
/// This is the same encoding that is used in the `fragment_runner`. This encoding is lossy and
@ -202,23 +197,24 @@ impl PointerTarget {
Self::Symbol { symbol_id, instance_id } => {
match Self::encode(*symbol_id, (*instance_id) as u32) {
DecodingResult::Truncated(pack0, pack1, pack2) => {
warning!(logger,"Target values too big to encode: \
({symbol_id},{instance_id}).");
warning!(
logger,
"Target values too big to encode: \
({symbol_id},{instance_id})."
);
Vector4::new(pack0.into(), pack1.into(), pack2.into(), 1)
},
DecodingResult::Ok(pack0,pack1,pack2) => {
Vector4::new(pack0.into(),pack1.into(),pack2.into(),1)
},
}
},
DecodingResult::Ok(pack0, pack1, pack2) =>
Vector4::new(pack0.into(), pack1.into(), pack2.into(), 1),
}
}
}
}
fn from_internal(v: Vector4<u32>) -> Self {
if v.w == 0 {
Self::Background
}
else if v.w == 255 {
} else if v.w == 255 {
let decoded = Self::decode(v.x, v.y, v.z);
let symbol_id = SymbolId::new(decoded.0);
let instance_id = attribute::InstanceIndex::new(decoded.1 as usize);
@ -257,12 +253,12 @@ mod target_tests {
match pack {
DecodingResult::Truncated { .. } => {
panic!("Values got truncated. This is an invalid test case: {}, {}", value1, value1)
},
}
DecodingResult::Ok(pack0, pack1, pack2) => {
let unpack = PointerTarget::decode(pack0.into(), pack1.into(), pack2.into());
assert_eq!(unpack.0, value1);
assert_eq!(unpack.1, value2);
},
}
}
}
@ -313,17 +309,17 @@ pub struct Mouse {
pub handles: Rc<[callback::Handle; 3]>,
pub frp: enso_frp::io::Mouse,
pub scene_frp: Frp,
pub logger : Logger
pub logger: Logger,
}
impl Mouse {
pub fn new
( scene_frp : &Frp
, root : &web::dom::WithKnownShape<web::HtmlDivElement>
, variables : &UniformScope
, current_js_event : &CurrentJsEvent
, logger : Logger)
-> Self {
pub fn new(
scene_frp: &Frp,
root: &web::dom::WithKnownShape<web::HtmlDivElement>,
variables: &UniformScope,
current_js_event: &CurrentJsEvent,
logger: Logger,
) -> Self {
let scene_frp = scene_frp.clone_ref();
let target = PointerTarget::default();
let last_position = Rc::new(Cell::new(Vector2::new(0, 0)));
@ -349,15 +345,28 @@ impl Mouse {
frp.position.emit(position);
}
}
)));
let on_down = mouse_manager.on_down.add(current_js_event.make_event_handler(
f!((event:&mouse::OnDown) frp.down.emit(event.button())))
),
));
let on_down = mouse_manager.on_down.add(
current_js_event
.make_event_handler(f!((event:&mouse::OnDown) frp.down.emit(event.button()))),
);
let on_up = mouse_manager.on_up.add(current_js_event.make_event_handler(
f!((event:&mouse::OnUp) frp.up.emit(event.button())))
let on_up = mouse_manager.on_up.add(
current_js_event
.make_event_handler(f!((event:&mouse::OnUp) frp.up.emit(event.button()))),
);
let handles = Rc::new([on_move, on_down, on_up]);
Self {mouse_manager,last_position,position,hover_ids,target,handles,frp,scene_frp,logger}
Self {
mouse_manager,
last_position,
position,
hover_ids,
target,
handles,
frp,
scene_frp,
logger,
}
}
/// Re-emits FRP mouse changed position event with the last mouse position value.
@ -369,9 +378,9 @@ impl Mouse {
/// - Callback above is run. The value of `screen_position` uniform changes and FRP events are
/// emitted.
/// - FRP events propagate trough the whole system.
/// - The rendering engine renders a frame and waits for the pixel read pass to report symbol
/// ID under the cursor. This is normally done the next frame but sometimes could take even
/// few frames.
/// - The rendering engine renders a frame and waits for the pixel read pass to report symbol ID
/// under the cursor. This is normally done the next frame but sometimes could take even few
/// frames.
/// - When the new ID are received, we emit `over` and `out` FRP events for appropriate
/// elements.
/// - After emitting `over` and `out `events, the `position` event is re-emitted.
@ -404,7 +413,8 @@ impl Keyboard {
pub fn new(current_event: &CurrentJsEvent) -> Self {
let logger = Logger::new("keyboard");
let frp = enso_frp::io::keyboard::Keyboard::default();
let bindings = Rc::new(enso_frp::io::keyboard::DomBindings::new(&logger,&frp,current_event));
let bindings =
Rc::new(enso_frp::io::keyboard::DomBindings::new(&logger, &frp, current_event));
Self { frp, bindings }
}
}
@ -459,14 +469,13 @@ impl Dom {
pub struct DomLayers {
/// Back DOM scene layer.
pub back: DomScene,
/// Back DOM scene layer with fullscreen visualization. Kept separately from `back`, because the
/// fullscreen visualizations should not share camera with main view.
/// Back DOM scene layer with fullscreen visualization. Kept separately from `back`, because
/// the fullscreen visualizations should not share camera with main view.
pub fullscreen_vis: DomScene,
/// Front DOM scene layer.
pub front: DomScene,
/// The WebGL scene layer.
pub canvas: web_sys::HtmlCanvasElement,
}
impl DomLayers {
@ -570,8 +579,12 @@ impl Renderer {
// - http://www.realtimerendering.com/blog/gpus-prefer-premultiplication
// - https://www.khronos.org/opengl/wiki/Blending#Colors
context.blend_equation_separate(Context::FUNC_ADD, Context::FUNC_ADD);
context.blend_func_separate ( Context::ONE , Context::ONE_MINUS_SRC_ALPHA
, Context::ONE , Context::ONE_MINUS_SRC_ALPHA );
context.blend_func_separate(
Context::ONE,
Context::ONE_MINUS_SRC_ALPHA,
Context::ONE,
Context::ONE_MINUS_SRC_ALPHA,
);
Self { logger, dom, context, variables, pipeline, composer }
}
@ -603,7 +616,6 @@ impl Renderer {
// ==============
// === Layers ===
// ==============
@ -661,23 +673,39 @@ impl HardcodedLayers {
let mask = Layer::new_with_cam(logger.sub("mask"), main_cam);
node_searcher.set_mask(&node_searcher_mask);
root.set_sublayers(
&[ &viz
, &below_main
, &main
, &port_selection
, &label
, &above_nodes
, &above_nodes_text
, &panel
, &panel_text
, &node_searcher
, &tooltip
, &tooltip_text
, &cursor
root.set_sublayers(&[
&viz,
&below_main,
&main,
&port_selection,
&label,
&above_nodes,
&above_nodes_text,
&panel,
&panel_text,
&node_searcher,
&tooltip,
&tooltip_text,
&cursor,
]);
Self {root,viz,below_main,main,port_selection,label,above_nodes,above_nodes_text,panel
,panel_text,node_searcher,node_searcher_mask,tooltip,tooltip_text,cursor,mask}
Self {
root,
viz,
below_main,
main,
port_selection,
label,
above_nodes,
above_nodes_text,
panel,
panel_text,
node_searcher,
node_searcher_mask,
tooltip,
tooltip_text,
cursor,
mask,
}
}
}
@ -708,7 +736,14 @@ impl Frp {
let shape = shape.clone_ref();
let camera_changed = camera_changed_source.clone_ref().into();
let frame_time = frame_time_source.clone_ref().into();
Self {network,shape,camera_changed,frame_time,camera_changed_source,frame_time_source}
Self {
network,
shape,
camera_changed,
frame_time,
camera_changed_source,
frame_time_source,
}
}
}
@ -769,8 +804,12 @@ pub struct SceneData {
impl SceneData {
/// Create new instance with the provided on-dirty callback.
pub fn new<OnMut:Fn()+Clone+'static>
(parent_dom:&HtmlElement, logger:Logger, stats:&Stats, on_mut:OnMut) -> Self {
pub fn new<OnMut: Fn() + Clone + 'static>(
parent_dom: &HtmlElement,
logger: Logger,
stats: &Stats,
on_mut: OnMut,
) -> Self {
debug!(logger, "Initializing.");
let dom = Dom::new(&logger);
@ -822,9 +861,29 @@ impl SceneData {
}
uniforms.pixel_ratio.set(dom.shape().pixel_ratio);
Self {display_object,dom,context,symbols,variables,current_js_event,mouse,keyboard,uniforms
,shapes,stats,dirty,logger,renderer,layers,style_sheet,bg_color_var,bg_color_change,frp
,extensions,disable_context_menu}
Self {
display_object,
dom,
context,
symbols,
variables,
current_js_event,
mouse,
keyboard,
uniforms,
shapes,
stats,
dirty,
logger,
renderer,
layers,
style_sheet,
bg_color_var,
bg_color_change,
frp,
extensions,
disable_context_menu,
}
}
pub fn shape(&self) -> &frp::Sampler<Shape> {
@ -919,8 +978,11 @@ impl SceneData {
}
/// Transforms screen position to the object (display object) coordinate system.
pub fn screen_to_object_space
(&self, object:&impl display::Object, screen_pos:Vector2) -> Vector2 {
pub fn screen_to_object_space(
&self,
object: &impl display::Object,
screen_pos: Vector2,
) -> Vector2 {
let origin_world_space = Vector4(0.0, 0.0, 0.0, 1.0);
let layer = object.display_layers().first().and_then(|t| t.upgrade());
let camera = layer.map_or(self.camera(), |l| l.camera());
@ -951,12 +1013,16 @@ impl display::Object for SceneData {
#[derive(Clone, CloneRef, Debug)]
pub struct Scene {
no_mut_access : SceneData
no_mut_access: SceneData,
}
impl Scene {
pub fn new<OnMut:Fn()+Clone+'static>
(parent_dom:&HtmlElement, logger:impl AnyLogger, stats:&Stats, on_mut:OnMut) -> Self {
pub fn new<OnMut: Fn() + Clone + 'static>(
parent_dom: &HtmlElement,
logger: impl AnyLogger,
stats: &Stats,
on_mut: OnMut,
) -> Self {
let logger = Logger::new_sub(logger, "scene");
let no_mut_access = SceneData::new(parent_dom, logger, stats, on_mut);
let this = Self { no_mut_access };

View File

@ -2,12 +2,12 @@
use crate::prelude::*;
use crate::display::object::traits::*;
use crate::display::camera::Camera2d;
use crate::display::camera::camera2d::Projection;
use crate::display::symbol::DomSymbol;
use crate::display::camera::Camera2d;
use crate::display::object::traits::*;
use crate::display::symbol::dom::eps;
use crate::display::symbol::dom::inverse_y_translation;
use crate::display::symbol::DomSymbol;
use crate::system::gpu::data::JsBufferView;
use crate::system::web;
use crate::system::web::NodeInserter;
@ -56,8 +56,11 @@ mod js {
/// Setup Camera perspective projection on DOM.
#[allow(unsafe_code)]
pub fn setup_camera_perspective
(dom:&web::JsValue, near:&web::JsValue, matrix_array:&web::JsValue);
pub fn setup_camera_perspective(
dom: &web::JsValue,
near: &web::JsValue,
matrix_array: &web::JsValue,
);
}
}
@ -109,7 +112,7 @@ pub struct DomSceneData {
pub dom: HtmlDivElement,
/// The child div of the `dom` element with view-projection Css 3D transformations applied.
pub view_projection_dom: HtmlDivElement,
logger : Logger
logger: Logger,
}
impl DomSceneData {
@ -197,7 +200,9 @@ impl DomScene {
/// Update the objects to match the new camera's point of view. This function should be called
/// only after camera position change.
pub fn update_view_projection(&self, camera: &Camera2d) {
if self.children_number() == 0 { return }
if self.children_number() == 0 {
return;
}
let trans_cam = camera.transform_matrix().try_inverse();
let trans_cam = trans_cam.expect("Camera's matrix is not invertible.");
@ -211,7 +216,7 @@ impl DomScene {
Projection::Perspective { .. } => {
js::setup_perspective(&self.data.dom, &near.into());
setup_camera_perspective(&self.data.view_projection_dom, near, &trans_cam);
},
}
Projection::Orthographic => {
setup_camera_orthographic(&self.data.view_projection_dom, &trans_cam);
}

View File

@ -3,17 +3,17 @@
use crate::data::dirty::traits::*;
use crate::prelude::*;
use crate::data::OptVec;
use crate::data::dirty;
use crate::data::OptVec;
use crate::display;
use crate::display::camera::Camera2d;
use crate::display::scene::Scene;
use crate::display::shape::ShapeSystemInstance;
use crate::display::shape::system::DynShapeSystemInstance;
use crate::display::shape::system::DynShapeSystemOf;
use crate::display::shape::system::KnownShapeSystemId;
use crate::display::shape::system::ShapeSystemId;
use crate::display::shape::ShapeSystemInstance;
use crate::display::symbol::SymbolId;
use crate::display;
use crate::system::gpu::data::attribute;
use enso_data::dependency_graph::DependencyGraph;
@ -28,9 +28,9 @@ use std::any::TypeId;
// =============
/// Display layers implementation. Layer consist of a [`Camera`] and a set of [`LayerItem`]s. Layers
/// are hierarchical and contain sublayers. Items of a layer containing sublayers layers are displayed
/// below items of sublayers layers. Layers are allowed to share references to the same camera. and
/// the same [`Symbol`]s.
/// are hierarchical and contain sublayers. Items of a layer containing sublayers layers are
/// displayed below items of sublayers layers. Layers are allowed to share references to the same
/// camera. and the same [`Symbol`]s.
///
///
/// # Symbol Management
@ -74,10 +74,10 @@ use std::any::TypeId;
/// # Symbols Ordering
/// There are two ways to define symbol ordering in scene layers, a global, and local (per-layer)
/// one. In order to define a global depth-order dependency, you can use the
/// `add_elements_order_dependency`, and the `remove_elements_order_dependency` methods respectively.
/// In order to define local (per-layer) depth-order dependency, you can use methods of the same
/// names in every layer instance. After changing a dependency graph, the layer management marks
/// appropriate dirty flags and re-orders symbols on each new frame processed.
/// `add_elements_order_dependency`, and the `remove_elements_order_dependency` methods
/// respectively. In order to define local (per-layer) depth-order dependency, you can use methods
/// of the same names in every layer instance. After changing a dependency graph, the layer
/// management marks appropriate dirty flags and re-orders symbols on each new frame processed.
///
/// During symbol sorting, the global and local dependency graphs are merged together. The defined
/// rules are equivalently important, so local rules will not override global ones. In case of
@ -122,9 +122,9 @@ use std::any::TypeId;
/// # Layer Lifetime Management
/// Both [`Group`] and every [`Layer`] instance are strongly interconnected. This is needed for a
/// nice API. For example, [`Layer`] allows you to add symbols while removing them from other layers
/// automatically. Although the [`SublayersModel`] registers [`WeakLayer`], the weak form is used only
/// to break cycles and never points to a dropped [`Layer`], as layers update the information on
/// a drop.
/// automatically. Although the [`SublayersModel`] registers [`WeakLayer`], the weak form is used
/// only to break cycles and never points to a dropped [`Layer`], as layers update the information
/// on a drop.
///
/// # Masking Layers With ScissorBox
/// Layers rendering an be limited to a specific set of pixels by using the [`ScissorBox`] object.
@ -154,7 +154,7 @@ use std::any::TypeId;
/// the nested masks will be skipped and a warning will be emitted to the console.
#[derive(Clone, CloneRef)]
pub struct Layer {
model : Rc<LayerModel>
model: Rc<LayerModel>,
}
impl Deref for Layer {
@ -197,8 +197,7 @@ impl Layer {
}
/// Instantiate the provided [`DynamicShape`].
pub fn instantiate<T>
(&self, scene:&Scene, shape:&T) -> LayerDynamicShapeInstance
pub fn instantiate<T>(&self, scene: &Scene, shape: &T) -> LayerDynamicShapeInstance
where T: display::shape::system::DynamicShape {
let (shape_system_info, symbol_id, instance_id) =
self.shape_system_registry.instantiate(scene, shape);
@ -254,7 +253,7 @@ impl From<&Layer> for LayerId {
/// A weak version of [`Layer`].
#[derive(Clone, CloneRef)]
pub struct WeakLayer {
model : Weak<LayerModel>
model: Weak<LayerModel>,
}
impl WeakLayer {
@ -345,9 +344,23 @@ impl LayerModel {
let mask = default();
let scissor_box = default();
let mem_mark = default();
Self {logger,camera,shape_system_registry,shape_system_to_symbol_info_map
,symbol_to_shape_system_map,elements,symbols_ordered,depth_order,depth_order_dirty
,parents,global_element_depth_order,sublayers,mask,scissor_box,mem_mark}
Self {
logger,
camera,
shape_system_registry,
shape_system_to_symbol_info_map,
symbol_to_shape_system_map,
elements,
symbols_ordered,
depth_order,
depth_order_dirty,
parents,
global_element_depth_order,
sublayers,
mask,
scissor_box,
mem_mark,
}
}
/// Unique identifier of this layer. It is memory-based, it will be unique even for layers in
@ -370,13 +383,16 @@ impl LayerModel {
use LayerItem::*;
match element {
Symbol(id) => Some(id),
ShapeSystem(id) => self.shape_system_to_symbol_info_map.borrow().get(&id).map(|t|t.id)
ShapeSystem(id) => self.shape_system_to_symbol_info_map.borrow().get(&id).map(|t| t.id),
}
}
/// Add depth-order dependency between two [`LayerItem`]s in this layer.
pub fn add_elements_order_dependency
(&self, below:impl Into<LayerItem>, above:impl Into<LayerItem>) {
pub fn add_elements_order_dependency(
&self,
below: impl Into<LayerItem>,
above: impl Into<LayerItem>,
) {
let below = below.into();
let above = above.into();
if self.depth_order.borrow_mut().insert_dependency(below, above) {
@ -386,12 +402,17 @@ impl LayerModel {
/// Remove a depth-order dependency between two [`LayerItem`]s in this layer. Returns `true`
/// if the dependency was found, and `false` otherwise.
pub fn remove_elements_order_dependency
(&self, below:impl Into<LayerItem>, above:impl Into<LayerItem>) -> bool {
pub fn remove_elements_order_dependency(
&self,
below: impl Into<LayerItem>,
above: impl Into<LayerItem>,
) -> bool {
let below = below.into();
let above = above.into();
let found = self.depth_order.borrow_mut().remove_dependency(below, above);
if found { self.depth_order_dirty.set(); }
if found {
self.depth_order_dirty.set();
}
found
}
@ -402,10 +423,11 @@ impl LayerModel {
/// This implementation can be simplified to `S1:KnownShapeSystemId` (not using [`Content`] at
/// all), after the compiler gets updated to newer version.
pub fn add_shapes_order_dependency<S1, S2>(&self) -> (PhantomData<S1>, PhantomData<S2>)
where S1 : HasContent,
where
S1: HasContent,
S2: HasContent,
Content<S1>: KnownShapeSystemId,
Content<S2> : KnownShapeSystemId {
Content<S2>: KnownShapeSystemId, {
let s1_id = <Content<S1>>::shape_system_id();
let s2_id = <Content<S2>>::shape_system_id();
self.add_elements_order_dependency(s1_id, s2_id);
@ -420,16 +442,20 @@ impl LayerModel {
/// # Future Improvements
/// This implementation can be simplified to `S1:KnownShapeSystemId` (not using [`Content`] at
/// all), after the compiler gets updated to newer version.
pub fn remove_shapes_order_dependency<S1,S2>
(&self) -> (bool,PhantomData<S1>,PhantomData<S2>)
where S1 : HasContent,
pub fn remove_shapes_order_dependency<S1, S2>(
&self,
) -> (bool, PhantomData<S1>, PhantomData<S2>)
where
S1: HasContent,
S2: HasContent,
Content<S1>: KnownShapeSystemId,
Content<S2> : KnownShapeSystemId {
Content<S2>: KnownShapeSystemId, {
let s1_id = <Content<S1>>::shape_system_id();
let s2_id = <Content<S2>>::shape_system_id();
let found = self.remove_elements_order_dependency(s1_id, s2_id);
if found { self.depth_order_dirty.set(); }
if found {
self.depth_order_dirty.set();
}
(found, default(), default())
}
@ -450,8 +476,11 @@ impl LayerModel {
}
/// Add the shape to this layer.
pub(crate) fn add_shape
(&self, shape_system_info:ShapeSystemInfo, symbol_id:impl Into<SymbolId>) {
pub(crate) fn add_shape(
&self,
shape_system_info: ShapeSystemInfo,
symbol_id: impl Into<SymbolId>,
) {
self.add_element(symbol_id.into(), Some(shape_system_info))
}
@ -459,7 +488,9 @@ impl LayerModel {
fn add_element(&self, symbol_id: SymbolId, shape_system_info: Option<ShapeSystemInfo>) {
self.depth_order_dirty.set();
match shape_system_info {
None => { self.elements.borrow_mut().insert(LayerItem::Symbol(symbol_id)); }
None => {
self.elements.borrow_mut().insert(LayerItem::Symbol(symbol_id));
}
Some(info) => {
let symbol_info = ShapeSystemSymbolInfo::new(symbol_id, info.ordering);
self.shape_system_to_symbol_info_map.borrow_mut().insert(info.id, symbol_info);
@ -476,7 +507,8 @@ impl LayerModel {
self.elements.borrow_mut().remove(&LayerItem::Symbol(symbol_id));
if let Some(shape_system_id) =
self.symbol_to_shape_system_map.borrow_mut().remove(&symbol_id) {
self.symbol_to_shape_system_map.borrow_mut().remove(&symbol_id)
{
self.shape_system_to_symbol_info_map.borrow_mut().remove(&shape_system_id);
self.elements.borrow_mut().remove(&LayerItem::ShapeSystem(shape_system_id));
}
@ -487,7 +519,8 @@ impl LayerModel {
self.depth_order_dirty.set();
self.elements.borrow_mut().remove(&LayerItem::ShapeSystem(shape_system_id));
if let Some(symbol_id) =
self.shape_system_to_symbol_info_map.borrow_mut().remove(&shape_system_id) {
self.shape_system_to_symbol_info_map.borrow_mut().remove(&shape_system_id)
{
self.symbol_to_shape_system_map.borrow_mut().remove(&symbol_id.id);
}
}
@ -498,8 +531,10 @@ impl LayerModel {
}
/// Consume all dirty flags and update the ordering of elements if needed.
pub(crate) fn update_internal
(&self, global_element_depth_order:Option<&DependencyGraph<LayerItem>>) {
pub(crate) fn update_internal(
&self,
global_element_depth_order: Option<&DependencyGraph<LayerItem>>,
) {
if self.depth_order_dirty.check() {
self.depth_order_dirty.unset();
self.depth_sort(global_element_depth_order);
@ -522,9 +557,10 @@ impl LayerModel {
/// dependency graph (from [`Group`]), the local one (per layer), and individual shape
/// preferences (see the "Compile Time Shapes Ordering Relations" section in docs of [`Group`]
/// to learn more).
fn combined_depth_order_graph
(&self, global_element_depth_order:Option<&DependencyGraph<LayerItem>>)
-> DependencyGraph<LayerItem> {
fn combined_depth_order_graph(
&self,
global_element_depth_order: Option<&DependencyGraph<LayerItem>>,
) -> DependencyGraph<LayerItem> {
let mut graph = if let Some(global_element_depth_order) = global_element_depth_order {
let mut graph = global_element_depth_order.clone();
graph.extend(self.depth_order.borrow().clone().into_iter());
@ -535,11 +571,15 @@ impl LayerModel {
for element in &*self.elements.borrow() {
if let LayerItem::ShapeSystem(id) = element {
if let Some(info) = self.shape_system_to_symbol_info_map.borrow().get(id) {
for &id2 in &info.below { graph.insert_dependency(*element,id2.into()); }
for &id2 in &info.above { graph.insert_dependency(id2.into(),*element); }
for &id2 in &info.below {
graph.insert_dependency(*element, id2.into());
}
for &id2 in &info.above {
graph.insert_dependency(id2.into(), *element);
}
}
}
}
};
graph
}
@ -547,20 +587,22 @@ impl LayerModel {
let graph = self.combined_depth_order_graph(global_element_depth_order);
let elements_sorted = self.elements.borrow().iter().copied().collect_vec();
let sorted_elements = graph.into_unchecked_topo_sort(elements_sorted);
let sorted_symbols = sorted_elements.into_iter().filter_map(|element| {
match element {
let sorted_symbols = sorted_elements
.into_iter()
.filter_map(|element| match element {
LayerItem::Symbol(symbol_id) => Some(symbol_id),
LayerItem::ShapeSystem(id) => {
let out = self.shape_system_to_symbol_info_map.borrow().get(&id).map(|t| t.id);
if out.is_none() {
warning!(self.logger,
warning!(
self.logger,
"Trying to perform depth-order of non-existing element '{id:?}'."
)
}
out
}
}
}).collect();
})
.collect();
*self.symbols_ordered.borrow_mut() = sorted_symbols;
}
}
@ -648,23 +690,33 @@ impl LayerModel {
/// Add depth-order dependency between two [`LayerItem`]s in this layer. Returns `true`
/// if the dependency was inserted successfully (was not already present), and `false`
/// otherwise. All sublayers will inherit these rules.
pub fn add_global_elements_order_dependency
(&self, below:impl Into<LayerItem>, above:impl Into<LayerItem>) -> bool {
pub fn add_global_elements_order_dependency(
&self,
below: impl Into<LayerItem>,
above: impl Into<LayerItem>,
) -> bool {
let below = below.into();
let above = above.into();
let fresh = self.global_element_depth_order.borrow_mut().insert_dependency(below, above);
if fresh { self.sublayers.element_depth_order_dirty.set(); }
if fresh {
self.sublayers.element_depth_order_dirty.set();
}
fresh
}
/// Remove a depth-order dependency between two [`LayerItem`]s in this layer. Returns `true`
/// if the dependency was found, and `false` otherwise.
pub fn remove_global_elements_order_dependency
(&self, below:impl Into<LayerItem>, above:impl Into<LayerItem>) -> bool {
pub fn remove_global_elements_order_dependency(
&self,
below: impl Into<LayerItem>,
above: impl Into<LayerItem>,
) -> bool {
let below = below.into();
let above = above.into();
let found = self.global_element_depth_order.borrow_mut().remove_dependency(below, above);
if found { self.sublayers.element_depth_order_dirty.set(); }
if found {
self.sublayers.element_depth_order_dirty.set();
}
found
}
@ -672,12 +724,14 @@ impl LayerModel {
/// This implementation can be simplified to `S1:KnownShapeSystemId` (not using [`Content`] at
/// all), after the compiler gets updated to newer version. Returns `true` if the dependency was
/// inserted successfully (was not already present), and `false` otherwise.
pub fn add_global_shapes_order_dependency<S1,S2>
(&self) -> (bool,PhantomData<S1>,PhantomData<S2>) where
pub fn add_global_shapes_order_dependency<S1, S2>(
&self,
) -> (bool, PhantomData<S1>, PhantomData<S2>)
where
S1: HasContent,
S2: HasContent,
Content<S1>: KnownShapeSystemId,
Content<S2> : KnownShapeSystemId {
Content<S2>: KnownShapeSystemId, {
let s1_id = <Content<S1>>::shape_system_id();
let s2_id = <Content<S2>>::shape_system_id();
let fresh = self.add_global_elements_order_dependency(s1_id, s2_id);
@ -688,12 +742,14 @@ impl LayerModel {
/// This implementation can be simplified to `S1:KnownShapeSystemId` (not using [`Content`] at
/// all), after the compiler gets updated to newer version. Returns `true` if the dependency was
/// found, and `false` otherwise.
pub fn remove_global_shapes_order_dependency<S1,S2>
(&self) -> (bool,PhantomData<S1>,PhantomData<S2>) where
pub fn remove_global_shapes_order_dependency<S1, S2>(
&self,
) -> (bool, PhantomData<S1>, PhantomData<S2>)
where
S1: HasContent,
S2: HasContent,
Content<S1>: KnownShapeSystemId,
Content<S2> : KnownShapeSystemId {
Content<S2>: KnownShapeSystemId, {
let s1_id = <Content<S1>>::shape_system_id();
let s2_id = <Content<S2>>::shape_system_id();
let found = self.remove_global_elements_order_dependency(s1_id, s2_id);
@ -736,7 +792,7 @@ impl std::borrow::Borrow<LayerModel> for Layer {
pub struct LayerDynamicShapeInstance {
pub layer: WeakLayer,
pub symbol_id: SymbolId,
pub instance_id : attribute::InstanceIndex
pub instance_id: attribute::InstanceIndex,
}
impl LayerDynamicShapeInstance {
@ -846,7 +902,7 @@ newtype_prim! {
#[allow(missing_docs)]
pub enum LayerItem {
Symbol(SymbolId),
ShapeSystem (ShapeSystemId)
ShapeSystem(ShapeSystemId),
}
impl From<ShapeSystemId> for LayerItem {
@ -943,9 +999,10 @@ impl ShapeSystemRegistryData {
self.shape_system_map.get_mut(&id).and_then(|t| {
let shape_system = t.shape_system.downcast_mut::<T>();
let instance_count = &mut t.instance_count;
shape_system.map(move |shape_system|
ShapeSystemRegistryEntryRefMut {shape_system,instance_count}
)
shape_system.map(move |shape_system| ShapeSystemRegistryEntryRefMut {
shape_system,
instance_count,
})
})
}
@ -960,12 +1017,13 @@ impl ShapeSystemRegistryData {
self.get_mut().unwrap()
}
fn with_get_or_register_mut<T,F,Out>
(&mut self, scene:&Scene, f:F) -> Out
where F:FnOnce(ShapeSystemRegistryEntryRefMut<T>)->Out, T:ShapeSystemInstance {
fn with_get_or_register_mut<T, F, Out>(&mut self, scene: &Scene, f: F) -> Out
where
F: FnOnce(ShapeSystemRegistryEntryRefMut<T>) -> Out,
T: ShapeSystemInstance, {
match self.get_mut() {
Some(entry) => f(entry),
None => f(self.register(scene))
None => f(self.register(scene)),
}
}
}

View File

@ -2,10 +2,10 @@
pub mod def;
pub mod shader;
pub mod system;
pub mod style_watch;
pub mod system;
pub use def::*;
pub use shader::*;
pub use system::*;
pub use style_watch::*;
pub use system::*;

View File

@ -1,8 +1,8 @@
//! This module is the root module for all primitive shapes and shape transform definitions.
pub mod primitive;
pub mod class;
pub mod modifier;
pub mod primitive;
pub mod unit;
pub mod var;

View File

@ -2,13 +2,13 @@
use crate::prelude::*;
use super::unit::*;
use super::modifier::*;
use super::unit::*;
use crate::data::color;
use crate::display::shape::primitive::def::var::Var;
use crate::display::shape::primitive::shader::canvas;
use crate::display::shape::primitive::shader::canvas::Canvas;
use crate::display::shape::primitive::def::var::Var;
use crate::data::color;
@ -23,7 +23,7 @@ pub trait Shape = 'static + canvas::Draw;
/// as a generic shape type.
#[derive(Debug, Clone, CloneRef)]
pub struct AnyShape {
rc: Rc<dyn canvas::Draw>
rc: Rc<dyn canvas::Draw>,
}
impl AsOwned for AnyShape {
@ -53,7 +53,7 @@ impl canvas::Draw for AnyShape {
#[derive(Debug, Derivative, Shrinkwrap)]
#[derivative(Clone(bound = ""))]
pub struct ShapeRef<T> {
rc:Rc<T>
rc: Rc<T>,
}
impl<T> From<&ShapeRef<T>> for ShapeRef<T> {
@ -94,7 +94,8 @@ impl<T> ShapeOps for ShapeRef<T> {}
impl ShapeOps for AnyShape {}
/// Methods implemented by every shape.
pub trait ShapeOps : Sized where for<'t> &'t Self : IntoOwned<Owned=Self> {
pub trait ShapeOps: Sized
where for<'t> &'t Self: IntoOwned<Owned = Self> {
/// Translate the shape by a given offset.
fn translate<V: Into<Var<Vector2<Pixels>>>>(&self, v: V) -> Translate<Self> {
Translate(self, v)

View File

@ -10,8 +10,8 @@ use crate::data::color::*;
use crate::display::shape::primitive::def::class::AnyShape;
use crate::display::shape::primitive::def::class::ShapeRef;
use crate::display::shape::primitive::def::var::Var;
use crate::display::shape::primitive::shader::canvas::Canvas;
use crate::display::shape::primitive::shader::canvas;
use crate::display::shape::primitive::shader::canvas::Canvas;

View File

@ -10,11 +10,11 @@ use inflector::Inflector;
use crate::display::shape::primitive::def::class::AnyShape;
use crate::display::shape::primitive::def::class::ShapeRef;
use crate::display::shape::primitive::shader::canvas::Canvas;
use crate::display::shape::primitive::shader::canvas;
use crate::display::shape::primitive::shader::canvas::Canvas;
use crate::display::shape::Var;
use crate::system::gpu::shader::glsl::Glsl;
use crate::system::gpu::shader::glsl::traits::*;
use crate::system::gpu::shader::glsl::Glsl;
@ -449,12 +449,19 @@ impl Rect {
}
/// Sets the radiuses of each of the corners.
pub fn corners_radiuses<T1,T2,T3,T4>
(&self, top_left:T1, top_right:T2, bottom_left:T3, bottom_right:T4) -> RoundedRectByCorner
where T1 : Into<Var<Pixels>> ,
pub fn corners_radiuses<T1, T2, T3, T4>(
&self,
top_left: T1,
top_right: T2,
bottom_left: T3,
bottom_right: T4,
) -> RoundedRectByCorner
where
T1: Into<Var<Pixels>>,
T2: Into<Var<Pixels>>,
T3: Into<Var<Pixels>>,
T4 : Into<Var<Pixels>> {
T4: Into<Var<Pixels>>,
{
RoundedRectByCorner(self.size(), top_left, top_right, bottom_left, bottom_right)
}

View File

@ -4,9 +4,9 @@ use super::var::*;
use crate::types::topology;
pub use crate::types::topology::Degrees;
pub use crate::types::topology::Pixels;
pub use crate::types::topology::Radians;
pub use crate::types::topology::Degrees;
@ -43,11 +43,11 @@ impl PixelDistance for f32 {
/// Common types.
pub mod types {
use super::*;
pub use super::PixelDistance;
use super::*;
pub use topology::Degrees;
pub use topology::Pixels;
pub use topology::Radians;
pub use topology::Degrees;
}
pub use types::*;

View File

@ -22,7 +22,8 @@ use std::ops::*;
pub trait VarInitializer<T> = VarInitializerMarker<T> + Into<Glsl>;
/// Marker trait for `VarInitializer`.
#[marker] pub trait VarInitializerMarker<T> {}
#[marker]
pub trait VarInitializerMarker<T> {}
// === Instances ===
@ -42,7 +43,12 @@ impl VarInitializerMarker<Var<color::Rgba>> for color::Rgba {}
impl<G> VarInitializerMarker<Var<color::Rgba>> for color::gradient::SdfSampler<G> {}
impl<T, S1, S2> VarInitializerMarker<Var<Vector2<T>>> for (S1, S2)
where T:Scalar, S1:VarInitializerMarkerNested<Var<T>>, S2:VarInitializerMarkerNested<Var<T>> {}
where
T: Scalar,
S1: VarInitializerMarkerNested<Var<T>>,
S2: VarInitializerMarkerNested<Var<T>>,
{
}
@ -88,26 +94,34 @@ impl Var<Pixels> {
impl Var<color::Rgba> {
/// Build a color from its components.
pub fn rgba(r:impl Into<Var<f32>>, g:impl Into<Var<f32>>, b:impl Into<Var<f32>>, a:impl Into<Var<f32>>)
-> Var<color::Rgba> {
format!("srgba({},{},{},{})",
pub fn rgba(
r: impl Into<Var<f32>>,
g: impl Into<Var<f32>>,
b: impl Into<Var<f32>>,
a: impl Into<Var<f32>>,
) -> Var<color::Rgba> {
format!(
"srgba({},{},{},{})",
r.into().glsl(),
g.into().glsl(),
b.into().glsl(),
a.into().glsl()
).into()
)
.into()
}
}
impl<T, S> From<T> for Var<S>
where T : VarInitializer<Var<S>> {
where T: VarInitializer<Var<S>>
{
default fn from(t: T) -> Self {
Self::Dynamic(t.into())
}
}
impl<T> From<T> for Var<T>
where T : VarInitializer<Var<T>> {
where T: VarInitializer<Var<T>>
{
fn from(t: T) -> Self {
Self::Static(t)
}
@ -138,17 +152,19 @@ impls! {[T:Into<Glsl>] From<Var<T>> for Glsl { |t|
// ==================
impl<T> Abs for Var<T>
where T:Abs {
where T: Abs
{
fn abs(&self) -> Self {
match self {
Self::Static(t) => Var::Static(t.abs()),
Self::Dynamic (t) => Var::Dynamic(format!("abs({})",t).into())
Self::Dynamic(t) => Var::Dynamic(format!("abs({})", t).into()),
}
}
}
impl<T> Min for Var<T>
where T:Min+Into<Glsl> {
where T: Min + Into<Glsl>
{
fn min(a: Self, b: Self) -> Self {
match (a, b) {
(Var::Static(a), Var::Static(b)) => Var::Static(Min::min(a, b)),
@ -156,13 +172,14 @@ where T:Min+Into<Glsl> {
let a: Glsl = a.into();
let b: Glsl = b.into();
Var::Dynamic(format!("min({},{})", a.glsl(), b.glsl()).into())
},
}
}
}
}
impl<T> Max for Var<T>
where T:Max+Into<Glsl> {
where T: Max + Into<Glsl>
{
fn max(a: Self, b: Self) -> Self {
match (a, b) {
(Var::Static(a), Var::Static(b)) => Var::Static(Max::max(a, b)),
@ -170,7 +187,7 @@ where T:Max+Into<Glsl> {
let a: Glsl = a.into();
let b: Glsl = b.into();
Var::Dynamic(format!("max({},{})", a.glsl(), b.glsl()).into())
},
}
}
}
}
@ -187,7 +204,7 @@ impl<T:Scalar> Dim1 for Var<Vector2<T>> {
fn x(&self) -> Var<T> {
match self {
Self::Static(t) => Var::Static(t.x.clone()),
Self::Dynamic (t) => Var::Dynamic(format!("{}.x",t).into())
Self::Dynamic(t) => Var::Dynamic(format!("{}.x", t).into()),
}
}
}
@ -196,7 +213,7 @@ impl<T:Scalar> Dim2 for Var<Vector2<T>> {
fn y(&self) -> Var<T> {
match self {
Self::Static(t) => Var::Static(t.y.clone()),
Self::Dynamic (t) => Var::Dynamic(format!("{}.y",t).into())
Self::Dynamic(t) => Var::Dynamic(format!("{}.y", t).into()),
}
}
}
@ -205,7 +222,7 @@ impl<T:Scalar> Dim1 for Var<Vector3<T>> {
fn x(&self) -> Var<T> {
match self {
Self::Static(t) => Var::Static(t.x.clone()),
Self::Dynamic (t) => Var::Dynamic(format!("{}.x",t).into())
Self::Dynamic(t) => Var::Dynamic(format!("{}.x", t).into()),
}
}
}
@ -214,7 +231,7 @@ impl<T:Scalar> Dim2 for Var<Vector3<T>> {
fn y(&self) -> Var<T> {
match self {
Self::Static(t) => Var::Static(t.y.clone()),
Self::Dynamic (t) => Var::Dynamic(format!("{}.y",t).into())
Self::Dynamic(t) => Var::Dynamic(format!("{}.y", t).into()),
}
}
}
@ -223,7 +240,7 @@ impl<T:Scalar> Dim3 for Var<Vector3<T>> {
fn z(&self) -> Var<T> {
match self {
Self::Static(t) => Var::Static(t.z.clone()),
Self::Dynamic (t) => Var::Dynamic(format!("{}.z",t).into())
Self::Dynamic(t) => Var::Dynamic(format!("{}.z", t).into()),
}
}
}
@ -234,7 +251,7 @@ impl PixelDistance for Var<Vector2<f32>> {
fn px(&self) -> Self::Output {
match self {
Self::Static(t) => Var::Static(Vector2(t.x.pixels(), t.y.pixels())),
Self::Dynamic (t) => Var::Dynamic(t.clone())
Self::Dynamic(t) => Var::Dynamic(t.clone()),
}
}
}
@ -244,7 +261,7 @@ impl PixelDistance for Var<Vector3<f32>> {
fn px(&self) -> Self::Output {
match self {
Self::Static(t) => Var::Static(Vector3(t.x.pixels(), t.y.pixels(), t.z.pixels())),
Self::Dynamic (t) => Var::Dynamic(t.clone())
Self::Dynamic(t) => Var::Dynamic(t.clone()),
}
}
}
@ -320,7 +337,7 @@ macro_rules! define_shape_data_operator {
}
}
}}
}
};
}
macro_rules! define_shape_data_prim_operator {
@ -371,7 +388,8 @@ define_shape_data_prim_operator! { Sub sub (-) for f32 where [A:RefInto<Glsl>] }
define_shape_data_prim_operator! { Rem rem (%) for f32 where [A:RefInto<Glsl>] }
impl<T> Neg for Var<T>
where T : Neg + RefInto<Glsl> {
where T: Neg + RefInto<Glsl>
{
type Output = Var<<T as Neg>::Output>;
fn neg(self) -> Self::Output {
match self {
@ -382,7 +400,8 @@ where T : Neg + RefInto<Glsl> {
}
impl<'t, T> Neg for &'t Var<T>
where &'t T : Neg + Into<Glsl> {
where &'t T: Neg + Into<Glsl>
{
type Output = Var<<&'t T as Neg>::Output>;
fn neg(self) -> Self::Output {
match self {
@ -400,13 +419,14 @@ macro_rules! define_shape_data_string_operator {
define_shape_data_string_operator_ref! { $name $fn ($opr) for str }
define_shape_data_string_operator_no_ref! { $name $fn ($opr) for String }
define_shape_data_string_operator_no_ref! { $name $fn ($opr) for CowString }
}
};
}
macro_rules! define_shape_data_string_operator_ref {
( $name:ident $fn:ident ($opr:tt) for $target:ident ) => {
impl<'t, A> $name<&'t $target> for &'t Var<A>
where A : RefInto<Glsl> {
where A: RefInto<Glsl>
{
type Output = Var<A>;
fn $fn(self, rhs: &'t $target) -> Self::Output {
Var::Dynamic(format!("{}({},{})", stringify!($fn), self.glsl(), rhs).into())
@ -414,7 +434,8 @@ macro_rules! define_shape_data_string_operator_ref {
}
impl<'t, A> $name<&'t $target> for Var<A>
where A : RefInto<Glsl> {
where A: RefInto<Glsl>
{
type Output = Var<A>;
fn $fn(self, rhs: &'t $target) -> Self::Output {
Var::Dynamic(format!("{}({},{})", stringify!($fn), self.glsl(), rhs).into())
@ -422,7 +443,8 @@ macro_rules! define_shape_data_string_operator_ref {
}
impl<'t, A> $name<&'t Var<A>> for &'t $target
where A : Display + RefInto<Glsl> {
where A: Display + RefInto<Glsl>
{
type Output = Var<A>;
fn $fn(self, rhs: &'t Var<A>) -> Self::Output {
Var::Dynamic(format!("{}({},{})", stringify!($fn), self.glsl(), rhs).into())
@ -430,19 +452,21 @@ macro_rules! define_shape_data_string_operator_ref {
}
impl<'t, A> $name<Var<A>> for &'t $target
where A : Display + RefInto<Glsl> {
where A: Display + RefInto<Glsl>
{
type Output = Var<A>;
fn $fn(self, rhs: Var<A>) -> Self::Output {
Var::Dynamic(format!("{}({},{})", stringify!($fn), self.glsl(), rhs).into())
}
}
}
};
}
macro_rules! define_shape_data_string_operator_no_ref {
( $name:ident $fn:ident ($opr:tt) for $target:ident ) => {
impl<'t, A> $name<$target> for &'t Var<A>
where A : RefInto<Glsl> {
where A: RefInto<Glsl>
{
type Output = Var<A>;
fn $fn(self, rhs: $target) -> Self::Output {
Var::Dynamic(format!("{}({},{})", stringify!($fn), self.glsl(), rhs).into())
@ -450,7 +474,8 @@ macro_rules! define_shape_data_string_operator_no_ref {
}
impl<A> $name<$target> for Var<A>
where A : RefInto<Glsl> {
where A: RefInto<Glsl>
{
type Output = Var<A>;
fn $fn(self, rhs: $target) -> Self::Output {
Var::Dynamic(format!("{}({},{})", stringify!($fn), self.glsl(), rhs).into())
@ -458,7 +483,8 @@ macro_rules! define_shape_data_string_operator_no_ref {
}
impl<'t, A> $name<&'t Var<A>> for $target
where A : Display + RefInto<Glsl> {
where A: Display + RefInto<Glsl>
{
type Output = Var<A>;
fn $fn(self, rhs: &'t Var<A>) -> Self::Output {
Var::Dynamic(format!("{}({},{})", stringify!($fn), self.glsl(), rhs).into())
@ -466,13 +492,14 @@ macro_rules! define_shape_data_string_operator_no_ref {
}
impl<A> $name<Var<A>> for $target
where A : Display + RefInto<Glsl> {
where A: Display + RefInto<Glsl>
{
type Output = Var<A>;
fn $fn(self, rhs: Var<A>) -> Self::Output {
Var::Dynamic(format!("{}({},{})", stringify!($fn), self.glsl(), rhs).into())
}
}
}
};
}
define_shape_data_string_operator! { Add add (+) }
@ -516,46 +543,50 @@ impl Var<f32> {
// ===============================
impl<T> Sin for Var<T>
where T: Sin<Output=T> {
where T: Sin<Output = T>
{
type Output = Var<T>;
fn sin(&self) -> Self {
match self {
Self::Static(t) => Var::Static(t.sin()),
Self::Dynamic (t) => Var::Dynamic(format!("sin({})",t).into())
Self::Dynamic(t) => Var::Dynamic(format!("sin({})", t).into()),
}
}
}
impl<T> Asin for Var<T>
where T: Asin<Output=T> {
where T: Asin<Output = T>
{
type Output = Var<T>;
fn asin(&self) -> Self {
match self {
Self::Static(t) => Var::Static(t.asin()),
Self::Dynamic (t) => Var::Dynamic(format!("asin({})",t).into())
Self::Dynamic(t) => Var::Dynamic(format!("asin({})", t).into()),
}
}
}
impl<T> Cos for Var<T>
where T: Cos<Output=T> {
where T: Cos<Output = T>
{
type Output = Var<T>;
fn cos(&self) -> Self {
match self {
Self::Static(t) => Var::Static(t.cos()),
Self::Dynamic (t) => Var::Dynamic(format!("cos({})",t).into())
Self::Dynamic(t) => Var::Dynamic(format!("cos({})", t).into()),
}
}
}
impl<T> Acos for Var<T>
where T: Acos<Output=T> {
where T: Acos<Output = T>
{
type Output = Var<T>;
fn acos(&self) -> Self {
match self {
Self::Static(t) => Var::Static(t.acos()),
Self::Dynamic (t) => Var::Dynamic(format!("acos({})",t).into())
Self::Dynamic(t) => Var::Dynamic(format!("acos({})", t).into()),
}
}
}
@ -567,12 +598,13 @@ where T: Acos<Output=T> {
// ===================
impl<T> Sqrt for Var<T>
where T: Sqrt<Output=T> {
where T: Sqrt<Output = T>
{
type Output = Var<T>;
fn sqrt(&self) -> Self {
match self {
Self::Static(t) => Var::Static(t.sqrt()),
Self::Dynamic (t) => Var::Dynamic(format!("sqrt({})",t).into())
Self::Dynamic(t) => Var::Dynamic(format!("sqrt({})", t).into()),
}
}
}
@ -584,11 +616,12 @@ where T: Sqrt<Output=T> {
// =============
impl<T> Clamp for Var<T>
where T: Clamp<Output=T>+Into<Glsl> {
where T: Clamp<Output = T> + Into<Glsl>
{
type Output = Var<T>;
fn clamp(self, lower: Var<T>, upper: Var<T>) -> Var<T> {
use Var::Static;
use Var::Dynamic;
use Var::Static;
match (self, lower, upper) {
(Static(value), Static(lower), Static(upper)) => Static(value.clamp(lower, upper)),
@ -609,12 +642,13 @@ where T: Clamp<Output=T>+Into<Glsl> {
// ==============
impl<T> Signum for Var<T>
where T: Signum<Output=T> {
where T: Signum<Output = T>
{
type Output = Var<T>;
fn signum(self) -> Self {
match self {
Self::Static(t) => Var::Static(t.signum()),
Self::Dynamic (t) => Var::Dynamic(format!("sign({})",t).into())
Self::Dynamic(t) => Var::Dynamic(format!("sign({})", t).into()),
}
}
}
@ -693,15 +727,14 @@ impl Var<color::Rgba> {
/// Return the color with the given alpha value.
pub fn with_alpha(self, alpha: &Var<f32>) -> Self {
match (self, alpha) {
(Var::Static (t), Var::Static(alpha)) => {
Var::Static(color::Rgba::new(t.data.red,t.data.green,t.data.blue,*alpha))
},
(Var::Static(t), Var::Static(alpha)) =>
Var::Static(color::Rgba::new(t.data.red, t.data.green, t.data.blue, *alpha)),
(t, alpha) => {
let t = t.glsl();
let alpha = alpha.glsl();
let var = format!("srgba({0}.raw.x,{0}.raw.y,{0}.raw.z,{1})", t, alpha);
Var::Dynamic(var.into())
},
}
}
}
@ -710,15 +743,16 @@ impl Var<color::Rgba> {
pub fn multiply_alpha(self, alpha: &Var<f32>) -> Self {
match (self, alpha) {
(Var::Static(t), Var::Static(alpha)) => {
let var = color::Rgba::new(t.data.red,t.data.green,t.data.blue,*alpha*t.data.alpha);
let var =
color::Rgba::new(t.data.red, t.data.green, t.data.blue, *alpha * t.data.alpha);
Var::Static(var)
},
}
(t, alpha) => {
let t = t.glsl();
let alpha = alpha.glsl();
let var = format!("srgba({0}.raw.x,{0}.raw.y,{0}.raw.z,{0}.raw.w*{1})", t, alpha);
Var::Dynamic(var.into())
},
}
}
}
@ -726,7 +760,7 @@ impl Var<color::Rgba> {
pub fn into_linear(self) -> Var<color::LinearRgba> {
match self {
Var::Static(c) => Var::Static(c.into()),
Var::Dynamic(c) => Var::Dynamic(format!("rgba({0})",c.glsl()).into())
Var::Dynamic(c) => Var::Dynamic(format!("rgba({0})", c.glsl()).into()),
}
}
}

View File

@ -3,11 +3,11 @@
use crate::prelude::*;
use super::canvas;
use super::canvas::Canvas;
use crate::display::shape::primitive::def::primitive;
use crate::display::shape::primitive::shader::overload;
use crate::display::symbol::shader::builder::CodeTemplate;
use super::canvas;
use super::canvas::Canvas;
@ -42,7 +42,8 @@ impl Builder {
let shape_header = header("Shape Definition");
canvas.add_current_function_code_line(iformat!("return {shape_ref.getter()};"));
canvas.submit_shape_constructor("run");
let defs = iformat!("{defs_header}\n\n{sdf_defs}\n\n\n\n{shape_header}\n\n{canvas.to_glsl()}");
let defs =
iformat!("{defs_header}\n\n{sdf_defs}\n\n\n\n{shape_header}\n\n{canvas.to_glsl()}");
let redirections = overload::builtin_redirections();
let math = overload::allow_overloading(MATH);
@ -51,8 +52,14 @@ impl Builder {
let shape = overload::allow_overloading(SHAPE);
let defs = overload::allow_overloading(&defs);
let code = format!("{}\n\n{}\n\n{}\n\n{}\n\n{}\n\n{}",redirections,math,color,debug,shape,defs);
let main = format!("bool pointer_events_enabled = {};\n{}",pointer_events_enabled,FRAGMENT_RUNNER);
let code = format!(
"{}\n\n{}\n\n{}\n\n{}\n\n{}\n\n{}",
redirections, math, color, debug, shape, defs
);
let main = format!(
"bool pointer_events_enabled = {};\n{}",
pointer_events_enabled, FRAGMENT_RUNNER
);
CodeTemplate::new(code, main, "")
}

View File

@ -1,10 +1,10 @@
//! Canvas for drawing vector graphics. See the documentation of `Canvas` to learn more.
use crate::prelude::*;
use crate::data::color;
use crate::display::shape::primitive::def::var::Var;
use crate::prelude::*;
use crate::system::gpu::shader::glsl::Glsl;
use crate::system::gpu::types::*;
use crate::data::color;
@ -15,7 +15,7 @@ use crate::data::color;
/// Immutable reference to a shape defined on `Canvas` with a fast clone.
#[derive(Clone, Debug, Shrinkwrap)]
pub struct Shape {
rc: Rc<ShapeData>
rc: Rc<ShapeData>,
}
impl Shape {
@ -104,8 +104,7 @@ impl Canvas {
impl Canvas {
/// Checks if shape with the given id was already defined. If so, a cached `ShapeCanvas` is
/// returned. Otherwise the provided constructor is run and the result is cached.
pub fn if_not_defined<F:FnOnce(&mut Self) -> ShapeData>
(&mut self, id:usize, f:F) -> Shape {
pub fn if_not_defined<F: FnOnce(&mut Self) -> ShapeData>(&mut self, id: usize, f: F) -> Shape {
match self.defined_shapes.get(&id) {
Some(shape) => shape.clone(),
None => {
@ -140,8 +139,10 @@ impl Canvas {
/// Get the final GLSL code.
pub fn to_glsl(&self) -> String {
assert!(self.current_function_lines.is_empty(),
"Internal error. Not all canvas GLSL code lines were converted to functions.");
assert!(
self.current_function_lines.is_empty(),
"Internal error. Not all canvas GLSL code lines were converted to functions."
);
self.functions.join("\n\n")
}
}
@ -213,8 +214,12 @@ impl Canvas {
}
/// Translate the current canvas origin.
pub fn translate<V:Into<Var<Vector2<Pixels>>>>
(&mut self, num:usize, s1:Shape, v:V) -> Shape {
pub fn translate<V: Into<Var<Vector2<Pixels>>>>(
&mut self,
num: usize,
s1: Shape,
v: V,
) -> Shape {
self.if_not_defined(num, |this| {
let v = v.into().glsl();
let trans = iformat!("position = translate(position,{v});");
@ -227,8 +232,7 @@ impl Canvas {
}
/// Rotate the current canvas origin.
pub fn rotation<A:Into<Var<Radians>>>
(&mut self, num:usize, s1:Shape, angle:A) -> Shape {
pub fn rotation<A: Into<Var<Radians>>>(&mut self, num: usize, s1: Shape, angle: A) -> Shape {
self.if_not_defined(num, |this| {
let angle: Glsl = angle.into().glsl();
let trans = iformat!("position = rotate(position,{angle});");
@ -241,8 +245,7 @@ impl Canvas {
}
/// Scale the current canvas origin.
pub fn scale<T:Into<Var<f32>>>
(&mut self, num:usize, s1:Shape, value:T) -> Shape {
pub fn scale<T: Into<Var<f32>>>(&mut self, num: usize, s1: Shape, value: T) -> Shape {
self.if_not_defined(num, |this| {
let value: Glsl = value.into().glsl();
let trans = iformat!("position = scale(position,{value});");
@ -255,8 +258,12 @@ impl Canvas {
}
/// Fill the shape with the provided color.
pub fn fill<Color:Into<Var<color::Rgba>>>
(&mut self, num:usize, s:Shape, color:Color) -> Shape {
pub fn fill<Color: Into<Var<color::Rgba>>>(
&mut self,
num: usize,
s: Shape,
color: Color,
) -> Shape {
self.if_not_defined(num, |this| {
let color: Glsl = color.into().glsl();
this.add_current_function_code_line(iformat!("Shape shape = {s.getter()};"));
@ -269,8 +276,7 @@ impl Canvas {
}
/// Make the borders of the shape crisp. Please note that it removes any form of antialiasing.
pub fn pixel_snap
(&mut self, num:usize, s:Shape) -> Shape {
pub fn pixel_snap(&mut self, num: usize, s: Shape) -> Shape {
self.if_not_defined(num, |this| {
let expr = iformat!("return pixel_snap({s.getter()});");
let mut shape = this.new_shape_from_expr(num, &expr);
@ -280,8 +286,7 @@ impl Canvas {
}
/// Grow the shape by the given value.
pub fn grow<T:Into<Var<f32>>>
(&mut self, num:usize, s:Shape, value:T) -> Shape {
pub fn grow<T: Into<Var<f32>>>(&mut self, num: usize, s: Shape, value: T) -> Shape {
self.if_not_defined(num, |this| {
let value: Glsl = value.into().glsl();
let expr = iformat!("return grow({s.getter()},{value});");
@ -292,15 +297,18 @@ impl Canvas {
}
/// Shrink the shape by the given value.
pub fn shrink<T:Into<Var<f32>>>
(&mut self, num:usize, s:Shape, value:T) -> Shape {
pub fn shrink<T: Into<Var<f32>>>(&mut self, num: usize, s: Shape, value: T) -> Shape {
let value = value.into();
self.grow(num, s, -value)
}
/// Repeat the shape with the given tile size.
pub fn repeat<T:Into<Var<Vector2<Pixels>>>>
(&mut self, num:usize, s:Shape, tile_size:T) -> Shape {
pub fn repeat<T: Into<Var<Vector2<Pixels>>>>(
&mut self,
num: usize,
s: Shape,
tile_size: T,
) -> Shape {
self.if_not_defined(num, |this| {
let value: Glsl = tile_size.into().glsl();
let repeat = iformat!("position = repeat(position,{value});");

View File

@ -4,9 +4,9 @@ use crate::prelude::*;
use crate::control::callback;
use crate::data::color;
use crate::display::style::Path;
use crate::display::style::data::DataMatch;
use crate::display::style;
use crate::display::style::data::DataMatch;
use crate::display::style::Path;
use enso_frp as frp;
@ -56,8 +56,10 @@ impl StyleWatchFrp {
Self { network, sheet, vars, handles, callback }
}
fn get_internal
(&self, path:impl Into<Path>) -> (frp::Source<Option<style::Data>>,Option<style::Data>) {
fn get_internal(
&self,
path: impl Into<Path>,
) -> (frp::Source<Option<style::Data>>, Option<style::Data>) {
let network = &self.network;
frp::extend! { network
source <- source::<Option<style::Data>>();

Some files were not shown because too many files have changed in this diff Show More