map_each previously was written such that if a chain of mappings fed each other, a deadlock could occur because while the first one was mapped, the second callback gets invoked and tries to update the first value while it's still being held. This refactor switches from std Mutex to parking_lot, allowing me to remove a workaround for needing to run drop callbacks in a separate thread during the drop of a DynamicGuard. In addition to that change, the lower level `map_generational` calls now take a DynamicGuard as their parameter. This allows these functions to drop ownership of the referenced data during the callback. The map_each implementation takes advantage of this by ensuring that the guard is dropped before set is invoked, minimizing potential lock overlaps. With this refactor, some old code of mine with complex validations now works again. |
||
|---|---|---|
| .github/workflows | ||
| .rustme | ||
| assets | ||
| cushy-macros | ||
| examples | ||
| guide | ||
| src | ||
| .crate-docs.md | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| CHANGELOG.md | ||
| CODE_OF_CONDUCT.md | ||
| CONTRIBUTING.md | ||
| LICENSE-APACHE | ||
| LICENSE-MIT | ||
| README.md | ||
| rustfmt.toml | ||
Cushy
Cushy is an experimental Graphical User Interface (GUI) crate for the Rust
programming language. It features a reactive data model and aims to enable
easily creating responsive, efficient user interfaces. To enable easy
cross-platform development, Cushy uses its own collection of consistently-styled
Widgets.
Cushy is powered by:
Kludgine, a 2d graphics library powered by:winitfor windowing/inputwgpufor graphicscosmic_textfor text layout + rasterization
palettefor OKLab-based HSL color calculationsarboardfor clipboard supportfiguresfor integer-based 2d math
Getting Started with Cushy
The Widget trait is the building block of Cushy: Every user
interface element implements Widget. The Widget trait
documentation has an overview of how Cushy works. A list of built-in
widgets can be found in the cushy::widgets module.
Cushy uses a reactive data model. To see an example of how reactive data models work, consider this example that displays a button that increments its own label:
fn main() -> cushy::Result {
// Create a dynamic usize.
let count = Dynamic::new(0_isize);
// Create a new label displaying `count`
count
.to_label()
// Use the label as the contents of a button
.into_button()
// Set the `on_click` callback to a closure that increments the counter.
.on_click(move |_| count.set(count.get() + 1))
// Run the application
.run()
}
Here are some ways to learn more about Cushy:
- Explore the examples directory. Nearly every feature in Cushy was initially tested by creating an example.
- Browse the user's guide.
- Ask questions in Discussions or on Discord.
Project Status
This project is early in development, but is quickly becoming a decent framework. It is considered alpha and unsupported at this time, and the primary focus for @ecton is to use this for his own projects. Feature requests and bug fixes will be prioritized based on @ecton's own needs.
If you would like to contribute, bug fixes are always appreciated. Before working on a new feature, please open an issue proposing the feature and problem it aims to solve. Doing so will help prevent friction in merging pull requests, as it ensures changes fit the vision the maintainers have for Cushy.
Open-source Licenses
This project, like all projects from Khonsu Labs, is open-source. This repository is available under the MIT License or the Apache License 2.0.
To learn more about contributing, please see CONTRIBUTING.md.