• This repository has been archived on 05/Jun/2024
  • Stars
    star
    405
  • Rank 106,656 (Top 3 %)
  • Language
    Rust
  • License
    Apache License 2.0
  • Created about 2 years ago
  • Updated 6 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Rust UI design toolkit - moved.

Masonry

Masonry is a framework that aims to provide the foundation for Rust GUI libraries.

Masonry gives you a platform to create windows (using Glazier as a backend) each with a tree of widgets. It also gives you tools to inspect that widget tree at runtime, write unit tests on it, and generally have an easier time debugging and maintaining your app.

The framework is not opinionated about what your user-facing abstraction will be: you can implement immediate-mode GUI, the Elm architecture, functional reactive GUI, etc, on top of Masonry.

This project was originally a fork of Druid that emerged from discussions I had with Raph Levien and Colin Rofls about what it would look like to turn Druid into a foundational library.

Installing

cargo add masonry

Linux

On Linux, Masonry requires gtk+3; see GTK installation page. (On ubuntu-based distro, running sudo apt-get install libgtk-3-dev from the terminal will do the job.)

OpenBSD

On OpenBSD, Masonry requires gtk+3; install from packages:

pkg_add gtk+3

Example

The todo-list example looks like this:

use masonry::widget::{prelude::*, TextBox};
use masonry::widget::{Button, Flex, Label, Portal, WidgetMut};
use masonry::Action;
use masonry::{AppDelegate, AppLauncher, DelegateCtx, WindowDescription, WindowId};

const VERTICAL_WIDGET_SPACING: f64 = 20.0;

struct Delegate {
    next_task: String,
}

impl AppDelegate for Delegate {
    fn on_action(
        &mut self,
        ctx: &mut DelegateCtx,
        _window_id: WindowId,
        _widget_id: WidgetId,
        action: Action,
        _env: &Env,
    ) {
        match action {
            Action::ButtonPressed => {
                let mut root: WidgetMut<Portal<Flex>> = ctx.get_root();
                let mut flex = root.child_mut();
                flex.add_child(Label::new(self.next_task.clone()));
            }
            Action::TextChanged(new_text) => {
                self.next_task = new_text.clone();
            }
            _ => {}
        }
    }
}

fn main() {
    // The main button with some space below, all inside a scrollable area.
    let root_widget = Portal::new(
        Flex::column()
            .with_child(
                Flex::row()
                    .with_child(TextBox::new(""))
                    .with_child(Button::new("Add task")),
            )
            .with_spacer(VERTICAL_WIDGET_SPACING),
    );

    let main_window = WindowDescription::new(root_widget)
        .title("To-do list")
        .window_size((400.0, 400.0));

    AppLauncher::with_window(main_window)
        .with_delegate(Delegate {
            next_task: String::new(),
        })
        .log_to_console()
        .launch()
        .expect("Failed to launch application");
}

As you can see, compared to crates like Druid or Iced, Masonry takes a fairly low-level approach to GUI: there is no complex reconciliation logic or dataflow going on behind the scenes; if you want to add a widget to the flex container, you call flex.add_child(your_widget).

This simplicity makes Masonry somewhat painful if you want to use it to actually build GUI applications. The hope is that, by being low-level and straightforward, developers can easily build GUI frameworks on top of it.

(Well, in theory. The first stress-test will be porting Panoramix, a React-style GUI in Rust, to Masonry.)

Unit tests

Masonry is designed to make unit tests easy to write, as if the test function were a mouse-and-keyboard user. Tests look like this:

#[test]
fn some_test_with_a_button() {
    let [button_id] = widget_ids();
    let widget = Button::new("Hello").with_id(button_id);

    let mut harness = TestHarness::create(widget);

    // Make a snapshot test of the visual contents of the window
    assert_render_snapshot!(harness, "hello");

    harness.edit_root_widget(|mut button, _| {
        let mut button = button.downcast::<Button>().unwrap();
        button.set_text("World");
    });

    // Make new snapshot test now that the window has changed
    assert_render_snapshot!(harness, "world");

    // References to widget automatically implement Debug, and
    // will print their part of the widget hierarchy.
    println!("Window contents: {:?}", harness.root_widget());

    // You can also use insta to snapshot-test the widget hierarchy
    assert_debug_snapshot!(harness.root_widget());

    // Clicking on a button will produce a "ButtonPressed" action.
    harness.mouse_click_on(button_id);
    assert_eq!(
        harness.pop_action(),
        Some((Action::ButtonPressed, button_id))
    );
}

Contributing

Issues and PRs are welcome. See help-wanted issues if you don't know where to begin.

Roadmap

The immediate next steps are:

  • Remove Env type and Data trait (#8)

  • Re-add Dialog feature (#25)

  • Switch to using Vello and Glazier (#24)

  • Refactor TextLayout (#23)

  • Rework Widget trait (#26)

  • Port Panoramix to Masonry

  • Port Xilem to Masonry

See ROADMAP.md and the issues page for more.

More Repositories

1

druid

A data-first Rust-native UI design toolkit.
Rust
9,543
star
2

xilem

An experimental Rust native UI framework
Rust
3,444
star
3

vello

A GPU compute-centric 2D renderer.
Rust
2,315
star
4

piet

An abstraction for 2D graphics.
Rust
1,251
star
5

runebender

A font editor written in Rust.
Rust
762
star
6

kurbo

A Rust library for manipulating curves
Rust
698
star
7

skribo

A Rust library for low-level text layout.
Rust
325
star
8

glazier

Deprecated Rust Window Creation Library
Rust
209
star
9

parley

Rich text layout library
Rust
197
star
10

piet-metal

Experimental Metal-based GPU renderer for piet 2D graphics.
Rust
140
star
11

bevy_vello

An integration to render with Vello in Bevy game engine.
Rust
117
star
12

spline

A spline for interactive 2D curve design
Rust
112
star
13

druid-widget-nursery

A place where Druid widgets come to mature before moving to the Druid repo.
Rust
87
star
14

velato

An integration to parse and render Lottie with Vello.
Rust
71
star
15

norad

Rust crate for working with Unified Font Object files
Rust
43
star
16

rbf-interp

An implementation of Radial Basis Function multidimensional interpolation
Rust
35
star
17

gpu-stroke-expansion-paper

Rust
35
star
18

2d.graphics

Repo for an ideational book on 2D graphics, plus tools to make images
26
star
19

peniko

Primitive types for styling vector graphics.
Rust
22
star
20

vello_svg

An integration to render SVG files with Vello.
Rust
15
star
21

wiki

Wiki and documentation for 2D graphics projects
9
star
22

android_trace

Support for Android NDK Tracing in Rust
Rust
6
star
23

rfcs

Suggestions for major changes to the linebender ecosystem
6
star
24

linebender.github.io

Main webpage for linebender org
SCSS
5
star
25

interpoli

Rust
3
star
26

runebender.app

Ruby
2
star
27

piet-snapshots

Data for snapshot testing of piet backends
2
star