{"id":13407542,"url":"https://github.com/linebender/druid","last_synced_at":"2025-05-12T16:34:02.817Z","repository":{"id":37490019,"uuid":"155783257","full_name":"linebender/druid","owner":"linebender","description":"A data-first Rust-native UI design toolkit. ","archived":false,"fork":false,"pushed_at":"2024-10-25T16:15:08.000Z","size":9638,"stargazers_count":9666,"open_issues_count":302,"forks_count":570,"subscribers_count":98,"default_branch":"master","last_synced_at":"2025-05-05T14:17:16.776Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://linebender.org/druid/","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/linebender.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS","dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2018-11-01T22:25:17.000Z","updated_at":"2025-05-05T12:34:57.000Z","dependencies_parsed_at":"2024-01-03T04:07:05.230Z","dependency_job_id":"0d3b5db4-f04e-4343-bd16-34b78860359f","html_url":"https://github.com/linebender/druid","commit_stats":{"total_commits":2206,"total_committers":207,"mean_commits":"10.657004830917874","dds":0.757026291931097,"last_synced_commit":"c02452ddeebc527992e8f112f434f23ce24c934d"},"previous_names":["xi-editor/druid"],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linebender%2Fdruid","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linebender%2Fdruid/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linebender%2Fdruid/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linebender%2Fdruid/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/linebender","download_url":"https://codeload.github.com/linebender/druid/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253777428,"owners_count":21962686,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-30T20:00:42.626Z","updated_at":"2025-05-12T16:34:02.795Z","avatar_url":"https://github.com/linebender.png","language":"Rust","readme":"![druid banner](https://raw.githubusercontent.com/linebender/druid/screenshots/images/small_banner.png)\n\n## A data-first Rust-native UI toolkit.\n\n[![crates.io](https://img.shields.io/crates/v/druid)](https://crates.io/crates/druid)\n[![docs.rs](https://docs.rs/druid/badge.svg)](https://docs.rs/druid/)\n[![license](https://img.shields.io/crates/l/druid)](https://github.com/linebender/druid/blob/master/LICENSE)\n[![chat](https://img.shields.io/badge/zulip-join_chat-brightgreen.svg)](https://xi.zulipchat.com)\n\nDruid was an experimental Rust-native UI toolkit. Its main goal was to offer a\npolished user experience. There were many factors to this goal, including\nperformance, a rich palette of interactions (hence a widget library to support\nthem), and playing well with the native platform.\nSee the [goals section](#Goals) for more details.\n\nWe did periodic releases of Druid on crates.io. All changes were documented\nin [the changelog](https://github.com/linebender/druid/blob/master/CHANGELOG.md).\n\nFor an overview of some key concepts, see the incomplete [Druid book].\n\n## Project status\n\n**UNMAINTAINED**\n\n**The Druid project has been discontinued.**\n\nNew development effort moved on to [Xilem], which has a lot of fundamental changes to allow for\na wider variety of applications with better performance, but it also heavily inherits from Druid.\nWe see [Xilem] as the future of Druid.\n\nDruid is reasonably usable for [some subset of applications](https://github.com/linebender/druid/issues/1360)\nand has a significant testing history, which ensures some stability and correctness.\nHowever, there will not be any new features or bug fixes coming to Druid. As such we don't recommend\nusing Druid for brand new applications. If you insist, then at least make sure your application\ndoesn't require a feature that Druid doesn't have, e.g. accessibility or 3D support.\n\n## Contributions\n\nAs the Druid project has been discontinued, **we will not be accepting any more contributions**.\n\nPlease take a look at some of our other projects instead, especially the Druid successor [Xilem].\n\n## Example\n\nHere's a simple counter example app:\n\n```rust\nuse druid::widget::{Button, Flex, Label};\nuse druid::{AppLauncher, LocalizedString, PlatformError, Widget, WidgetExt, WindowDesc};\n\nfn main() -\u003e Result\u003c(), PlatformError\u003e {\n    let main_window = WindowDesc::new(ui_builder());\n    let data = 0_u32;\n    AppLauncher::with_window(main_window)\n        .log_to_console()\n        .launch(data)\n}\n\nfn ui_builder() -\u003e impl Widget\u003cu32\u003e {\n    // The label text will be computed dynamically based on the current locale and count\n    let text =\n        LocalizedString::new(\"hello-counter\").with_arg(\"count\", |data: \u0026u32, _env| (*data).into());\n    let label = Label::new(text).padding(5.0).center();\n    let button = Button::new(\"increment\")\n        .on_click(|_ctx, data, _env| *data += 1)\n        .padding(5.0);\n\n    Flex::column().with_child(label).with_child(button)\n}\n```\n\nCheck out the [the examples folder] for a more comprehensive demonstration of\nDruid's existing functionality and widgets. Check [druid_widget_nursery](https://github.com/linebender/druid-widget-nursery) for more widgets.\n\n## Screenshots\n\n[![calc.rs example](https://raw.githubusercontent.com/linebender/druid/screenshots/images/0.6.0/calc.png)](/druid/examples/calc.rs)\n[![flex.rs example](https://raw.githubusercontent.com/linebender/druid/screenshots/images/0.6.0/flex.png)](/druid/examples/flex.rs)\n[![custom_widget.rs example](https://raw.githubusercontent.com/linebender/druid/screenshots/images/0.6.0/custom_widget.png)](/druid/examples/custom_widget.rs)\n\n## Using Druid\n\nAn explicit goal of Druid was to be easy to build.\nDruid is available on [crates.io] and should work as a lone dependency\n(it re-exports all the parts of `druid-shell`, `piet`, and `kurbo` that you'll need):\n\n```toml\ndruid = \"0.8.3\"\n```\n\n### Platform notes\n\n#### Linux\n\nOn Linux, Druid requires gtk+3; see [GTK installation page].\n(On ubuntu-based distro, running `sudo apt-get install libgtk-3-dev` from the terminal will do the job.)\n\n#### OpenBSD\n\nOn OpenBSD, Druid requires gtk+3;  install from packages:\n```sh\npkg_add gtk+3\n```\n\nAlternatively, there is an X11 backend available, although it is currently\n[missing quite a few features](https://github.com/linebender/druid/issues?q=is%3Aopen+is%3Aissue+label%3Ashell%2Fx11+label%3Amissing).\nYou can try it out with `--features=x11`.\n\n## Goals\n\nDruid's goal was to make it easy to write and deploy high quality desktop\napplications with a smooth and polished user experience on all common\nplatforms. In order to achieve this we strived for a variety of things:\n\n- Make it easy to build and package on all supported platforms.\n- Implement abstractions to avoid platform specific quirks.\n- Respect platform conventions and expectations.\n- Handle display resolution and scaling reliably with little effort.\n- Enable easy, yet powerful internationalization.\n- Offer robust accessibility support.\n- Produce small and fast binaries with low memory usage.\n- Have a small dependency tree, a high quality code base and good organization.\n- Focus on powerful, desktop-grade applications.\n- Provide a flexible set of layouts and common widgets.\n- Ease creation of custom components and application logic as needed.\n\n### Non-Goals\n\nIn order to fulfill those goals, we couldn't support every use case. Luckily\nthe Rust community is working on a variety of different libraries with\ndifferent goals, so here are some of Druid's non-goals and possible\nalternatives that can offer those capabilities:\n\n- Use the platform-native widgets or mimic them. ([Relm], [Slint])\n- Embed easily into custom render pipelines. ([Conrod])\n- Adhere to a specific architectural style such as Elm. ([Iced], [Relm])\n- Support rendering to HTML when targeting the web. ([Iced], [Moxie])\n\nDruid was just one of many ongoing [Rust-native GUI experiments].\n\n## Concepts\n\n### druid-shell\n\nThe Druid toolkit uses `druid-shell` for a platform-abstracting application shell.\n`druid-shell` is responsible for starting a native platform runloop, listening to\nevents, converting them into a platform-agnostic representation, and calling a\nuser-provided handler with them.\n\nWhile `druid-shell` was being developed with the Druid toolkit in mind, it was\nintended to be general enough that it could be reused by other projects\ninterested in experimenting with Rust GUI. The `druid-shell` crate includes a\ncouple of [non-`druid` examples].\n\n### piet\n\nDruid relies on the [Piet library] for drawing and text layout. Piet is a 2D graphics\nabstraction with multiple backends: `piet-direct2d`, `piet-coregraphics`, `piet-cairo`,\n`piet-web`, and `piet-svg` are currently available.\nIn terms of Druid platform support via Piet, macOS uses `piet-coregraphics`,\nLinux/OpenBSD/FreeBSD use `piet-cairo`, Windows uses `piet-direct2d`, and web uses `piet-web`.\n\n```rust\nuse druid::kurbo::{BezPath, Point, Rect};\nuse druid::piet::Color;\n\n// Create an arbitrary bezier path\n// (ctx.size() returns the size of the layout rect we're painting in)\nlet mut path = BezPath::new();\npath.move_to(Point::ORIGIN);\npath.quad_to(\n    (80.0, 90.0),\n    (ctx.size().width, ctx.size().height),\n);\n// Create a color\nlet stroke_color = Color::rgb8(0x00, 0x80, 0x00);\n// Stroke the path with thickness 1.0\nctx.stroke(path, \u0026stroke_color, 1.0);\n\n// Rectangles: the path for practical people\nlet rect = Rect::from_origin_size((10., 10.), (100., 100.));\n// Note the Color:rgba8 which includes an alpha channel (7F in this case)\nlet fill_color = Color::rgba8(0x00, 0x00, 0x00, 0x7F);\nctx.fill(rect, \u0026fill_color);\n```\n\n### widgets\n\nWidgets in Druid (text boxes, buttons, layout components, etc.) are objects\nwhich implement the [Widget trait]. The trait is parametrized by a type (`T`)\nfor associated data. All trait methods (`event`, `lifecycle`, `update`, `paint`,\nand `layout`) are provided with access to this data, and in the case of\n`event` the reference is mutable, so that events can directly update the data.\n\nWhenever the application data changes, the framework traverses the widget\nhierarchy with an `update` method.\n\nAll the widget trait methods are provided with a corresponding context\n([EventCtx], [LifeCycleCtx], [UpdateCtx], [LayoutCtx], [PaintCtx]). The widget can request\nthings and cause actions by calling methods on that context.\n\nIn addition, all trait methods are provided with an environment `Env`, which\nincludes the current theme parameters (colors, dimensions, etc.).\n\n```rust\nimpl\u003cT: Data\u003e Widget\u003cT\u003e for Button\u003cT\u003e {\n    fn event(\u0026mut self, ctx: \u0026mut EventCtx, event: \u0026Event, data: \u0026mut T, env: \u0026Env) {\n      ...\n    }\n\n    fn lifecycle(\u0026mut self, ctx: \u0026mut LifeCycleCtx, event: \u0026LifeCycle, data: \u0026T, env: \u0026Env) {\n      ...\n    }\n\n    fn update(\u0026mut self, ctx: \u0026mut UpdateCtx, old_data: \u0026T, data: \u0026T, env: \u0026Env) {\n      ...\n    }\n\n    fn layout(\u0026mut self, ctx: \u0026mut LayoutCtx, bc: \u0026BoxConstraints, data: \u0026T, env: \u0026Env) -\u003e Size {\n      ...\n    }\n\n    fn paint(\u0026mut self, ctx: \u0026mut PaintCtx, data: \u0026T, env: \u0026Env) {\n      ...\n    }\n}\n```\n\nDruid provides a number of [basic utility and layout widgets] and it's easy to\nimplement your own. You can also compose widgets into new widgets:\n\n```rust\nfn build_widget() -\u003e impl Widget\u003cu32\u003e {\n    let mut col = Flex::column();\n    for i in 0..30 {\n        let button = Button::new(format!(\"Button {}\", i).padding(5.0);\n        col.add_child(button);\n    }\n    Scroll::new(col)\n}\n```\n\n### layout\n\nDruid's layout protocol was strongly inspired by [Flutter's box layout model].\nIn Druid, widgets are passed a `BoxConstraint` that provides them a minimum and\nmaximum size for layout. Widgets are also responsible for computing appropriate\nconstraints for their children if applicable.\n\n### data\n\nDruid uses a [Data trait] to represent [value types]. These should be cheap to\ncompare and cheap to clone.\n\nIn general, you can use `derive` to generate a `Data` impl for your types.\n\n```rust\n#[derive(Clone, Data)]\nstruct AppState {\n    which: bool,\n    value: f64,\n}\n```\n\n### lens\n\nThe [Lens datatype] gives access to a part of a larger data structure. Like\n`Data`, this can be derived. Derived lenses are accessed as associated constants\nwith the same name as the field.\n\n```rust\n#[derive(Clone, Data, Lens)]\nstruct AppState {\n    which: bool,\n    value: f64,\n}\n```\n\nTo use the lens, wrap your widget with `LensWrap` (note the conversion of\nCamelCase to snake_case):\n\n```rust\nLensWrap::new(WidgetThatExpectsf64::new(), AppState::value);\n```\n\nAlternatively, lenses for structs, tuples, and indexable containers can be\nconstructed on-demand with the `lens` macro:\n\n```rust\nLensWrap::new(WidgetThatExpectsf64::new(), lens!(AppState, value));\n```\n\nThis is particularly useful when working with types defined in another crate.\n\n## Authors\n\nThe main authors are Raph Levien and Colin Rofls, with much support from an\nactive and friendly community. See the AUTHORS file for more.\n\n[Runebender]: https://github.com/linebender/runebender\n[the examples folder]: /druid/examples\n[Piet library]: https://github.com/linebender/piet\n[custom_widget]: /druid/examples/custom_widget.rs\n[basic utility and layout widgets]: /druid/src/widget\n[Flutter's box layout model]: https://api.flutter.dev/flutter/rendering/BoxConstraints-class.html\n[value types]: https://sinusoid.es/lager/model.html#id2\n[GTK installation page]: https://www.gtk.org/docs/installations/linux/\n[Rust-native GUI experiments]: https://areweguiyet.com\n[CONTRIBUTING.md]: /CONTRIBUTING.md\n[Zulip chat instance]: https://xi.zulipchat.com\n[non-`druid` examples]: /druid-shell/examples/shello.rs\n[crates.io]: https://crates.io/crates/druid\n[EventCtx]: https://docs.rs/druid/0.8.3/druid/struct.EventCtx.html\n[LifeCycleCtx]: https://docs.rs/druid/0.8.3/druid/struct.LifeCycleCtx.html\n[LayoutCtx]: https://docs.rs/druid/0.8.3/druid/struct.LayoutCtx.html\n[PaintCtx]: https://docs.rs/druid/0.8.3/druid/struct.PaintCtx.html\n[UpdateCtx]: https://docs.rs/druid/0.8.3/druid/struct.UpdateCtx.html\n[Widget trait]: https://docs.rs/druid/0.8.3/druid/trait.Widget.html\n[Data trait]: https://docs.rs/druid/0.8.3/druid/trait.Data.html\n[Lens datatype]: https://docs.rs/druid/0.8.3/druid/trait.Lens.html\n[Druid book]: https://linebender.org/druid/\n[Iced]: https://github.com/hecrj/iced\n[Conrod]: https://github.com/PistonDevelopers/conrod\n[Relm]: https://github.com/antoyo/relm\n[Moxie]: https://github.com/anp/moxie\n[Slint]: https://github.com/slint-ui/slint\n[Xilem]: https://github.com/linebender/xilem\n","funding_links":[],"categories":["3D Graphics Abstractions","Rust","Libraries","库 Libraries","Rust 程序设计","others","GUI"],"sub_categories":["Rust","GUI","GUI GUI","网络服务_其他"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flinebender%2Fdruid","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flinebender%2Fdruid","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flinebender%2Fdruid/lists"}