A developer-friendly framework for building user interfaces in Rust

Overview

Frui

Reading: "Fru" as in "fruit" and "i" as in "I" (I am).

Latest version MIT Apache Discord

What is Frui?

Frui is a developer-friendly UI framework that makes building user interfaces easy and productive. It's inspired by Flutter architecture and is written in Rust!

For an introduction see the announcement.

Example

#![feature(type_alias_impl_trait)]

use frui::prelude::*;

#[derive(ViewWidget)]
struct App;

impl ViewWidget for App {
    fn build<'w>(&'w self, _: BuildCtx<'w, Self>) -> Self::Widget<'w> {
        Center::child(Text::new("Hello, World!"))
    }
}

fn main() {
    run_app(App);
}

Warning

This framework is still in an experimental phase of development. As such, API changes are inevitable and necessary for the best developer experience.

Currently, there is very little optimizations happening. Layout and drawing are the least optimized. Many important widgets are yet to be implemented.

Frui heavily utilizes some of the nightly features to optimize rebuilds of the widget tree and improve the API. Therefore, the Minimum Supported Rust Version is the latest nightly release of Rust. This may be a deal-breaker for some.

It is important to know that Frui should not be used to build any serious applications at this point in time.

Features

Ok, what's done and what's not?

  • ViewWidget (see StatelessWidget and StatefulWidget)
  • InheritedWidget (see InheritedWidget)
  • LocalKey (see Key)
  • Scheduling state updates
  • Basic event detection (KeyboardEventDetector / mouse events)
  • Basic layout widgets (Column, Row, Center)

  • Focus
  • Events
  • Accessibility
  • Z-layers drawing
  • Optimizations:
    • Widget-rebuilds (based on depth)
    • Layout
    • Painting
  • Library of widgets common to all design langauges (provided in frui_widgets)
    • Column, Row, Stack, Scroll, ...
    • KeyboardListener, GestureDetector, ...
    • Theming widgets, etc.
  • Officially supported widget library implementing most popular design languages (e.g. frui_material, frui_cupertino)
  • Documentation and tutorials

🦀 Counter - Example

Obligatory crab counter! From examples/crab_counter.rs.

#![feature(type_alias_impl_trait)]

use frui::prelude::*;

mod misc;
use misc::Button;

#[derive(ViewWidget)]
struct CrabCounter;

impl WidgetState for CrabCounter {
    type State = isize;

    fn create_state(&self) -> Self::State { 0 }
}

impl ViewWidget for CrabCounter {
    fn build<'w>(&'w self, ctx: BuildCtx<'w, Self>) -> Self::Widget<'w> {
        Column::builder()
            .space_between(60.0)
            .main_axis_size(MainAxisSize::Max)
            .cross_axis_size(CrossAxisSize::Max)
            .main_axis_alignment(MainAxisAlignment::Center)
            .cross_axis_alignment(CrossAxisAlignment::Center)
            .children((
                Text::new(format!("{} 🦀", *ctx.state()))
                    .size(100.0)
                    .weight(FontWeight::BOLD),
                Row::builder()
                    .space_between(10.0)
                    .children((
                        Button {
                            label: Text::new("+").size(30.),
                            on_click: || *ctx.state_mut() += 1,
                        },
                        Button {
                            label: Text::new("-").size(30.),
                            on_click: || *ctx.state_mut() -= 1,
                        },
                    )),
            ))
    }
}

fn main() {
    run_app(CrabCounter);
}

screenshot of application running above code

Crabs counter running on MacOS

Credits

Frui wouldn't exist without Flutter and its widget architecture, which inspired Frui's API. Thank you!

Frui also wouldn't exist without prior work done on Druid - which powers most of the back-end. Many widgets share some of the implementation details with it as well. Thank you a lot!

License

All code in this repository is dual-licensed under either:

Comments
  • Feat flex widgets

    Feat flex widgets

    This PR/branch is based on feat-box-widgets

    Implementation of Flex with the same API in Flutter. And some relative widgets:

    • Expanded
    • Row and Column implemented by Flex now
    • Remove space_between and cross_axis_size in Column and Row
      • cross_axis_size can be covered with cross_axis_alignment
      • space_between is a specified type of main_axis_alignment. It should only be effective in that mode. Or maybe we do this like Flutter, with some space widgets? Or put the f64 value in MainAxisAlignment::SpaceBetween?

    CrossAxisAlignment::Baseline is to be done after we finish the text relative implementations.

    opened by xanahopper 9
  • feat: Implementation of basic box-model widgets.

    feat: Implementation of basic box-model widgets.

    Widgets

    • ConstrainedBox
    • UncontrainedBox
    • ColoredBox
    • SizedBox

    Traits

    • ~~BoxLayoutWidget, common for box-model measure and layout~~
    • ChildWidget, widgets with children.
    opened by xanahopper 4
  • cx not applied for my widget

    cx not applied for my widget

    Hello, I tried your great ui framework, but I have a problem when trying to run this example:

    #[derive(ViewWidget)]
    pub struct TextDebug {
        text:String
    }
    
    pub struct TextDebugState {
        text:String
    }
    
    impl WidgetState for TextDebug {
        type State = TextDebugState;
    
        fn create_state(&self) -> Self::State { 
            TextDebugState{text:String::from("hello3")} }
    }
    
    impl Debug for TextDebug{
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
            f.debug_struct("TextDebug").field("text", &self.text).finish()
        }
    }
    
    impl ViewWidget for TextDebug {
        fn build<'w>(&'w self, cx: BuildCx<'w, Self>) -> Self::Widget<'w> {
    let textt=cx.state().text.to_owned();
            Text::new( cx.state().text.to_owned())
        }
    }
    
    fn main() {
        run_app(App);
    }
    
    #[derive(ViewWidget)]
    struct App;
    
    impl WidgetState for App {
        type State =String;
    
        fn create_state(&self) -> Self::State {
            "hello".into()
        }
    }
    
    impl ViewWidget for App {
        fn build<'w>(&'w self, cx: BuildCx<'w, Self>) -> Self::Widget<'w> {
            
    Column::builder()
    .space_between(60.0)
    .main_axis_size(MainAxisSize::Max)
    .cross_axis_size(CrossAxisSize::Max)
    .main_axis_alignment(MainAxisAlignment::Center)
    .cross_axis_alignment(CrossAxisAlignment::Center)
    .children((
            
            button::Button{
                label:TextDebug{text:cx.state().to_owned()},
                on_click: ||{
                    *cx.state_mut()=String::from("hello from button");
                },
            },
            Text::new(
                cx.state().to_owned()
            ),
            TextDebug{text:cx.state().to_owned()},
            
    ))
        }
    }
    

    First of all, the widget always show hello3 instead of hello when initialising. And when the button is clicked, it doesn't update the TextDebug label, but it is working as expected for Text widget. What am I missing ? Thank you in advance for your help.

    opened by Alphapage 2
  • Feat `Container` basic widgets

    Feat `Container` basic widgets

    Basic Container components

    • DecoratedBox
    • LimitedBox
    • Shadow
    • ShapeBorder
    • etc...

    Directional

    • Directional trait for different text direction dependency widget
    • Directionality for inherited TextDirection
    opened by xanahopper 2
  • opt: `Alignment` implementation

    opt: `Alignment` implementation

    ~The polymorphism of abstract class AlignmentGeometry in Rust withtrait is ugly, and it cannot apply to third-party crate derive_builder。 Now change it to two separated struct and wrap them with a sum type AlignmentGeometry, which can be hold in widget with the same type.~ Add TextDirection and resolve from AlignmentGeometry into Alignment

    opened by xanahopper 2
  • Flex refactor

    Flex refactor

    • rewrite Flex implementation
    • correctly apply space_between
    • fix Container layout algorithm

    This implementation differs slightly from Flutter (on purpose), but it can always be changed later.

    opened by toiglak 1
  • This is awesome ... We need a discussions TAB!!!

    This is awesome ... We need a discussions TAB!!!

    Hey there! This is really an awesome project, I got amazed by seeing the code design language that you guys are using is identical to flutter which is amazing, and seeing it running in rust would be more amazing.

    I suggest to create a discussions page for this project.

    opened by omegaui 1
  • Refactor contextes

    Refactor contextes

    • Split RenderContext into LayoutCtx and PaintCtx
    • Rename BuildContext to BuildCtx
    • Rename PaintCtx to Canvas
    • Move rstate and wstate to RenderExt to share logic
    • Move try_parent_data and size to RenderOSExt to share logic
    • Move all rendering-related structures from frui::prelude to frui::render
    opened by toiglak 0
  • feat: Prototype of `Stack` widget

    feat: Prototype of `Stack` widget

    Run example

    cargo run --example stack
    

    How to use

    Stack::builder()
                .alignment(&Alignment::TOP_CENTER)
                .children((
                    Text::new("🦀").size(100.0).weight(FontWeight::BOLD),
                    Positioned {
                        child: Container::builder()
                        .color(Color::GREEN)
                        .width(50.0)
                        .height(50.0),
                        right: Some(10.0),
                        bottom: Some(10.0),
                        left: None,
                        top: None,
                        width: None,
                        height: None,
                    },
                    Positioned {
                        child: Container::builder()
                            .color(Color::GREEN)
                            .width(50.0)
                            .height(50.0),
                        right: Some(10.0),
                        bottom: Some(10.0),
                        left: Some(10.0),
                        top: Some(50.0),
                        width: None,
                        height: None,
                    },
                    Center {
                        child: Text::new("🦀").size(100.0).weight(FontWeight::BOLD),
                    },
                ))
    

    Preview

    image
    opened by xanahopper 0
  • Web and Wasm target.

    Web and Wasm target.

    I like very of the approach of using Flutter concepts to mount the UI.

    This project will give support for webassembly support?

    I also like the approach of async-ui.

    As a suggestion, it would be good if you put the concepts together.

    I make a issue here, because I couldn't join discord. Sorry.

    Thanks.

    opened by JADSN 3
  • Gesture Detector

    Gesture Detector

    Frui needs an easy way to handle pointer events. In this issue I wanted to document the overall API I am planning.

    ✅ Pointer Listener

    Widget that responds to low-level pointer events.

    PointerListener::builder()
        .on_pointer_down(|e| { ... })
        .on_pointer_up(|e| { ... })
        .on_pointer_scroll(|e| { ... })
    

    ✅ Pointer Region

    Widget that responds to pointer entering child's widget region. It also allows changing cursor icon (e.g. to a pointer icon when hovering over a button).

    PointerRegion::builder()
        .cursor(Cursor::Pointer)
        .on_enter(|e| { ... })
        .on_move(|e| { ... })
        .on_exit(|e| { ... })
    

    Gesture Detector

    Widget that distinguishes between different high-level gestures.

    GestureDetector::builder()
        .on_tap(|e| { ... })
        .on_double_tap(|e| { ... })
        .on_vertical_drag(|e| { ... })
        // ...
    

    I was thinking about adding an ability to directly extend that widget with custom gestures:

    fn add_gesture<G: Gesture>(self, gesture: G, callback: impl Fn(G::Event)) -> Self {
        // ...
    }
    

    Above builder method could then be abstracted using extension trait and used like:

    GestureDetector::builder()
        .on_tap(|_| { ... })
        .on_my_custom_gesture(|_| { ... })
    

    As of now, I am working on implementing PointerListener and KeyboardListener (other issue).

    GestureDetector is a little bit tricky to implement and not that useful on PC, so I plan to implement it later when we will focus on supporting mobile devices. For now, PointerListener and PointerRegion should be enough for handling input on PC.

    opened by toiglak 1
  • Core layout widgets

    Core layout widgets

    Following is a list of some of the more important core layout widgets that need to be implemented. Their exact API is up for debate, since there may be better ways to adapt those to Rust.

    Single-child layout widgets

    Multi-child layout widgets

    enhancement help wanted 
    opened by toiglak 11
Owner
Frui Framework
A developer-friendly framework for building user interfaces in Rust
Frui Framework
A typesafe, flexible, simple, and user-friendly unit system library for Rust that has good error messages.

uy A typesafe, flexible, simple, and user-friendly unit system library for Rust that has good error messages. Usage uy not only stores the unit of a v

Lachlan Sneff 19 Aug 8, 2023
My journey of learning rust as a web developer.

My journey of learning rust Low-level languages seem very interesting to me. I always wanted to learn a low-level language but never had the chance. T

null 1 Oct 21, 2021
Roadmap to becoming a Rust Web Developer in 2021

Roadmap to becoming a Rust Web Developer in 2021

Anshul Goyal 1.4k Jan 4, 2023
How to be a full stack Rust Developer

How to be a full stack Rust Developer Read Rust API guideline. Test code here and refer to the Rust blog posts at Steadylearner. If you need or know s

Steadylearner 1.2k Jan 8, 2023
A backend framework for building fast and flexible APIs rapidly.

Andromeda Andromeda is a backend framework for Rust, to simplify the development of the kinds of basic API services that we developers have to build s

Framesurge 7 Dec 28, 2022
RcLite: small, fast, and memory-friendly reference counting for Rust

RcLite: small, fast, and memory-friendly reference counting RcLite is a lightweight reference-counting solution for Rust that serves as an alternative

Khashayar Fereidani 147 Apr 14, 2023
Human-friendly indexed collections

Indexical: Human-Friendly Indexed Collections Indexical is a library for conveniently and efficiently working with indexed collections of objects. "In

Will Crichton 45 Nov 1, 2023
Dataflow system for building self-driving car and robotics applications.

ERDOS ERDOS is a platform for developing self-driving cars and robotics applications. Getting started The easiest way to get ERDOS running is to use o

ERDOS 163 Dec 29, 2022
A query-building & utility crate for SurrealDB and its SQL querying language that aims to be simple

Surreal simple querybuilder A simple query-builder for the Surreal Query Language, for SurrealDB. Aims at being simple to use and not too verbose firs

Thibault H 11 Dec 30, 2022
A tutorial of building an LSM-Tree storage engine in a week! (WIP)

LSM in a Week Build a simple key-value storage engine in a week! Tutorial The tutorial is available at https://skyzh.github.io/mini-lsm. You can use t

Alex Chi 870 Jan 3, 2023
Book - Actix user guides

User guides Actix User Guide Actix API Documentation (Development) Actix API Documentation (Releases) Actix Web User Guide Actix Web API Documentation

Actix 185 Dec 25, 2022
Checks Crusader Kings 3 user mod files for common mistakes and warns about them.

ck3-tiger Pounces on bugs. Checks Crusader Kings 3 user mod files for common mistakes and warns about them. For example: missing localizations, or usi

Richard Braakman 8 Jan 5, 2023
TUI (Text User Interface) - Get Instant feedback for your sh commands

Bashtastic Visualizer TUI (Text User Interface) - Get Instant feedback for your sh commands. Explore and play with your queries ??. The idea of this p

Alfredo Suarez 7 Nov 26, 2023
Integra8 rust integration test framework Rust with a focus on productivity, extensibility, and speed.

integra8 Integra8 rust integration test framework Rust with a focus on productivity, extensibility, and speed. | This repo is in a "work in progress"

exceptional 3 Sep 26, 2022
A recommender systems framework for Rust

Quackin Release the quackin! ?? Quackin is a recommender systems framework written in Rust. This is a young project, which means two things: There wil

Christopher Vittal 8 Dec 8, 2021
Safe Rust bindings to the DynamoRIO dynamic binary instrumentation framework.

Introduction The dynamorio-rs crate provides safe Rust bindings to the DynamoRIO dynamic binary instrumentation framework, essentially allowing you to

S.J.R. van Schaik 17 Nov 21, 2022
Rust bindings to the dos-like framework

dos-like for Rust   This project provides access to Mattias Gustavsson's dos-like framework, so as to write DOS-like applications in Rust. How to use

Eduardo Pinho 9 Aug 25, 2022
A minimal boilerplate for Astro / Vite with the Nannou creative framework (Rust → WASM). Supports multiple sketches + hot-reload.

Astro x Nannou Starter astro-nannou-demo-1c.mov ?? Try it online! # 0a. Rust language tools open https://www.rust-lang.org/tools/install # 0b. wasm-p

Julian Cataldo 4 Jan 4, 2023
Indeed, an ORM library, not a framework, written in Rust

Ormlib Indeed, an ORM library, not a framework, written in Rust Features The main idea that I put into my ORM library is a minimum of stupid code and

Evgeny Igumnov 5 Sep 4, 2023