GithubHelp home page GithubHelp logo

magenic-adams / druid Goto Github PK

View Code? Open in Web Editor NEW

This project forked from linebender/druid

0.0 0.0 0.0 3.89 MB

A data-first Rust-native UI design toolkit.

Home Page: https://xi-editor.io/druid/

License: Apache License 2.0

Rust 99.71% FreeMarker 0.29%

druid's Introduction

druid

A data-first Rust-native UI toolkit.

crates.io docs.rs license

Druid is an experimental Rust-native UI toolkit. Its main goal is to demonstrate the potential of Rust as an application programming language, while letting users write fast, small, and generally efficient programs with minimal hassle.

Druid's current development is largely driven by its use in Runebender, a new font editor.

We have been doing periodic releases of druid on crates.io, but it is under active development and its API might change. All changes are documented in the changelog.

For an overview of some key concepts, see the (work in progress) druid book.

Example

Here's a simple counter example app.

use druid::widget::{Button, Flex, Label};
use druid::{AppLauncher, LocalizedString, Widget, WidgetExt, WindowDesc};

fn main() {
    let main_window = WindowDesc::new(ui_builder);
    let data = 0_u32;
    AppLauncher::with_window(main_window)
        .use_simple_logger()
        .launch(data)
        .expect("launch failed");
}

fn ui_builder() -> impl Widget<u32> {
    // The label text will be computed dynamically based on the current locale and count
    let text =
        LocalizedString::new("hello-counter").with_arg("count", |data: &u32, _env| (*data).into());
    let label = Label::new(text)
        .padding(5.0)
        .center();
    let button = Button::new("increment").on_click(|_ctx, data, _env| *data += 1)
        .padding(5.0);

    Flex::column()
    .with_child(label)
    .with_child(button)
}

Check out the the examples folder for a more comprehensive demonstration of druid's existing functionality and widgets.

Screenshots

calc.rs example flex.rs example custom_widget.rs example

Concepts

druid-shell

The druid toolkit uses druid-shell for a platform-abstracting application shell. Druid-shell is responsible for starting a native platform runloop, listening to events, converting them into a platform-agnostic representation, and calling a user-provided handler with them.

While druid-shell is being developed with the druid toolkit in mind, it is intended to be general enough that it could be reused by other projects interested in experimenting with Rust GUI. The druid-shell crate includes a couple of non-druid examples.

piet

Druid relies on the piet library for drawing and text layout. Piet is a 2D graphics abstraction with multiple backends: piet-direct2d, piet-coregraphics, piet-cairo, piet-web, and piet-svg are currently available, and a GPU backend is planned. In terms of druid platform support via piet, macOS uses piet-coregraphics, Linux uses piet-cairo, Windows uses piet-direct2d, and web uses piet-web.

use druid::kurbo::{BezPath, Point, Rect};
use druid::piet::Color;

// Create an arbitrary bezier path
// (ctx.size() returns the size of the layout rect we're painting in)
let mut path = BezPath::new();
path.move_to(Point::ORIGIN);
path.quad_to(
    (80.0, 90.0),
    (ctx.size().width, ctx.size().height),
);
// Create a color
let stroke_color = Color::rgb8(0x00, 0x80, 0x00);
// Stroke the path with thickness 1.0
ctx.stroke(path, &stroke_color, 1.0);

// Rectangles: the path for practical people
let rect = Rect::from_origin_size((10., 10.), (100., 100.));
// Note the Color:rgba8 which includes an alpha channel (7F in this case)
let fill_color = Color::rgba8(0x00, 0x00, 0x00, 0x7F);
ctx.fill(rect, &fill_color);

widgets

Widgets in druid (text boxes, buttons, layout components, etc.) are objects which implement the Widget trait. The trait is parametrized by a type (T) for associated data. All trait methods (event, lifecycle, update, paint, and layout) are provided with access to this data, and in the case of event the reference is mutable, so that events can directly update the data.

Whenever the application data changes, the framework traverses the widget hierarchy with an update method.

All the widget trait methods are provided with a corresponding context (EventCtx, LifeCycleCtx, UpdateCtx, LayoutCtx, PaintCtx). The widget can request things and cause actions by calling methods on that context.

In addition, all trait methods are provided with an environment Env, which includes the current theme parameters (colors, dimensions, etc.).

impl<T: Data> Widget<T> for Button<T> {
    fn event(&mut self, ctx: &mut EventCtx, event: &Event, data: &mut T, env: &Env) {
      ...
    }

    fn lifecycle(&mut self, ctx: &mut LifeCycleCtx, event: &LifeCycle, data: &T, env: &Env) {
      ...
    }

    fn update(&mut self, ctx: &mut UpdateCtx, old_data: &T, data: &T, env: &Env) {
      ...
    }

    fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints, data: &T, env: &Env) -> Size {
      ...
    }

    fn paint(&mut self, ctx: &mut PaintCtx, data: &T, env: &Env) {
      ...
    }
}

Druid provides a number of basic utility and layout widgets and it's easy to implement your own. You can also compose widgets into new widgets:

fn build_widget() -> impl Widget<u32> {
    let mut col = Flex::column();
    for i in 0..30 {
        let button = Button::new(format!("Button {}", i).padding(5.0);
        col.add_child(button, 0.0);
    }
    Scroll::new(col)
}

layout

Druid's layout protocol is strongly inspired by Flutter's box layout model. In druid, widgets are passed a BoxConstraint that provides them a minimum and maximum size for layout. Widgets are also responsible for computing appropriate constraints for their children if applicable.

data

Druid uses a Data trait to represent value types. These should be cheap to compare and cheap to clone.

In general, you can use derive to generate a Data impl for your types.

#[derive(Clone, Data)]
struct AppState {
    which: bool,
    value: f64,
}

lens

The Lens datatype gives access to a part of a larger data structure. Like Data, this can be derived. Derived lenses are accessed as associated constants with the same name as the field.

#[derive(Clone, Data, Lens)]
struct AppState {
    which: bool,
    value: f64,
}

To use the lens, wrap your widget with LensWrap (note the conversion of CamelCase to snake_case):

LensWrap::new(WidgetThatExpectsf64::new(), AppState::value);

Alternatively, lenses for structs, tuples, and indexable containers can be constructed on-demand with the lens macro:

LensWrap::new(WidgetThatExpectsf64::new(), lens!(AppState, value));

This is particularly useful when working with types defined in another crate.

Using druid

An explicit goal of druid is to be easy to build, so please open an issue if you run into any difficulties. Druid is available on crates.io and should work as a lone dependency (it re-exports all the parts of druid-shell, piet, and kurbo that you'll need):

druid = "0.5.0"

Since druid is currently in fast-evolving state, you might prefer to drink from the firehose:

druid = { git = "https://github.com/xi-editor/druid.git", version = "0.5" }

Platform notes

Linux

On Linux, druid requires gtk+3; see gtk-rs dependencies for installation instructions.

Alternatively, there is an X11 backend available, although it is currently missing quite a few features. You can try it out with --features=x11.

Alternatives

Druid is only one of many ongoing Rust-native GUI experiments. To mention a few:

Contributions

We gladly accept contributions via GitHub pull requests. Please see CONTRIBUTING.md for more details.

A very good place to ask questions and discuss development work is our Zulip chat instance, in the #druid channel.

Authors

The main authors are Raph Levien and Colin Rofls, with much support from an active and friendly community.

druid's People

Contributors

cmyr avatar raphlinus avatar futurepaul avatar xstrom avatar zaynetro avatar rylev avatar forloveofcats avatar mrandri19 avatar vbsteven avatar scholtzan avatar jneem avatar mendelt avatar ralith avatar edwin0cheng avatar luleyleo avatar dmitry-borodin avatar fishrockz avatar lihram avatar sapphire-arches avatar teddemunnik avatar s3thi avatar zarenor avatar emigr2k1 avatar ratmice avatar chris-zen avatar jjl avatar crsaracco avatar kindlychung avatar totsteps avatar malmz avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.