This repository has been archived by the owner on Dec 29, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
117 additions
and
141 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,8 @@ | ||
{ | ||
"rust-analyzer.linkedProjects": [ | ||
".\\examples\\showcase\\Cargo.toml", | ||
".\\Cargo.toml" | ||
".\\Cargo.toml", | ||
".\\examples\\counter_floem\\Cargo.toml", | ||
".\\examples\\counter_prettygooey\\Cargo.toml", | ||
".\\examples\\showcase\\Cargo.toml" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,165 +1,53 @@ | ||
# Prettygoey | ||
_The discontinued Iced-based version of Prettygooey can still be found [here](https://github.com/pieterdd/prettygooey/tree/0.1.1)._ | ||
|
||
# Prettygooey | ||
|
||
[![Crates.io](https://img.shields.io/crates/v/prettygooey.svg)](https://crates.io/crates/prettygooey) | ||
[![docs.rs](https://img.shields.io/docsrs/prettygooey/latest)](https://docs.rs/prettygooey/latest/prettygooey/theme/struct.Theme.html) | ||
|
||
Prettygooey is a set of themed UI components for the [iced](https://iced.rs/) GUI library. Works on Windows, Linux and Mac. | ||
Prettygooey is a set of themed UI components for the [floem](https://github.com/lapce/floem) GUI library. Works on Windows, Linux and Mac. | ||
|
||
![Showcase](docs/img/showcase.png) | ||
|
||
⚠️ **Prettygooey, like iced, is experimental software.** ⚠️ | ||
|
||
## First time using iced? | ||
|
||
The [official iced book](https://book.iced.rs/) was fairly short at the time of writing, so my limited knowledge was pieced together from [docs.rs](https://docs.rs/iced/latest/iced/index.html) snippets, reading source code and visiting their [forums](https://discourse.iced.rs/). | ||
|
||
The simplest way to create a GUI in iced is with an [`iced::Sandbox`](https://docs.rs/iced/latest/iced/trait.Sandbox.html). It kind of behaves like a window. You'll have to implement four methods: | ||
|
||
- `new`: prepares your initial state | ||
- `title`: controls the title of the window | ||
- `update`: more on this later | ||
- `view`: renders your widgets | ||
|
||
### Thinking in widgets | ||
|
||
Iced, like many GUI frameworks, works with containers (i.e. groups of widgets) and widgets. Containers help you lay out your widgets, and common examples of them include a row or a column. Containers can contain containers, too. | ||
|
||
Suppose you want to create a confirmation dialog. Such a layout would probably have the following structure: | ||
|
||
- A column container | ||
- A text widget with label "Are you sure?" | ||
- A row container | ||
- A "Yes" button | ||
- A "No" button | ||
|
||
When using vanilla iced widgets, this would look something like this: | ||
|
||
![Vanilla iced example](docs/img/vanilla_iced.png) | ||
|
||
Row and column containers have some useful modifier functions: | ||
|
||
- `spacing` adds a gap between your widgets to let your layout breathe. | ||
- `padding` adds spacing on the outside of the container. This keeps your text from sticking to the side of the window. | ||
⚠️ **Prettygooey, like floem, is experimental software.** ⚠️ | ||
|
||
Here's a simple example putting the above into practice: | ||
## First time using floem? | ||
|
||
```rust | ||
fn view(&self) -> Element<'_, Self::Message> { | ||
column!( | ||
text("Are you sure?"), | ||
row![button("Yes"), button("No")].spacing(10) | ||
) | ||
.spacing(20) | ||
.padding(10) | ||
.into() | ||
} | ||
``` | ||
Floem's documentation is available [here](http://lapce.dev/floem/floem/). You might notice that it incorporates familiar concepts from other UI frameworks, including: | ||
|
||
### Let's run this thing | ||
- Interface composition using nestable horizontal and vertical widget containers | ||
- A styling system that brings many CSS-like features to Rust, without the overhead of a browser runtime | ||
- Automatic propagation of data changes to your UI using signals, as seen in [SolidJS](https://www.solidjs.com/) | ||
- Implementation of UIs using functions, similar to Jetpack Compose | ||
- Keyboard accessibility | ||
|
||
You've defined your UI, but it won't show up until you invoke it. In the example below, we initialize a window with mostly default settings. | ||
For a mimimal example involving a counter that can be incremented/decremented, have a look at [this file](examples/counter_floem/src/main.rs). It looks quite basic when rendered: | ||
|
||
```rust | ||
MySandbox::run(Settings { | ||
window: window::Settings { | ||
size: (400, 450), | ||
position: Position::Centered, | ||
..window::Settings::default() | ||
}, | ||
..Settings::default() | ||
}) | ||
``` | ||
![A counter in pure floem](docs/img/counter_floem.png) | ||
|
||
You can find the full list of available settings [here](https://docs.rs/iced/latest/iced/settings/struct.Settings.html). | ||
|
||
### Interactivity | ||
|
||
Many widgets allow for some kind of user interaction. Examples include your garden variety button, text input or checkbox. These interactions produce events. For a checkbox, a typical interaction plays out like this: | ||
|
||
1. The checkbox takes its current state from a variable | ||
2. User clicks the checkbox | ||
3. The checkbox emits an event containing the new state | ||
4. Your Sandbox's `update` function reacts to that new state by updating the variable to the new state | ||
|
||
You get to decide what the event looks like. Your Sandbox can designate a specific enum as its [Message type](https://docs.rs/iced/latest/iced/trait.Sandbox.html#associatedtype.Message). For example: | ||
|
||
```rust | ||
#[derive(Debug, Clone)] | ||
enum SpaceshipSandboxMessage { | ||
BoostersEnabledChanged(bool), | ||
ShieldSelectionChanged(Shield), | ||
CommanderNameChanged(String), | ||
RebootButtonPressed, | ||
} | ||
``` | ||
|
||
In the case of a [checkbox](https://docs.rs/iced/latest/iced/widget/fn.checkbox.html), you set the event as follows: | ||
|
||
```rust | ||
let chk_enable_boosters = checkbox( | ||
"Enable boosters", | ||
self.enable_boosters, | ||
Self::Message::BoostersEnabledChanged, | ||
); | ||
``` | ||
|
||
Your Sandbox's `update` function will be called whenever such an event is emitted. There you can respond accordingly: | ||
|
||
```rust | ||
fn update(&mut self, message: Self::Message) { | ||
match message { | ||
Self::Message::BoostersEnabledChanged(value) => { | ||
self.enable_boosters = value; | ||
} | ||
} | ||
} | ||
``` | ||
If you've familiarized yourself with the floem's basics, keep reading to find out how to spice things up. | ||
|
||
## Getting started with Prettygooey | ||
|
||
In your Sandbox's constructor, create an instance of [`prettygooey::theme::Theme`](https://docs.rs/prettygooey/latest/prettygooey/theme/struct.Theme.html). You'll use this object to instantiate Prettygooey widgets. | ||
|
||
```rust | ||
fn new() -> Self { | ||
Self { | ||
theme: Theme { | ||
accent_color: AccentColor::Magenta, | ||
}, | ||
} | ||
} | ||
``` | ||
|
||
In your Sandbox's `view` function, return an instance of our primary container to apply the background. | ||
|
||
```rust | ||
fn view(&self) -> Element<'_, Self::Message> { | ||
// Pass a row or column of widgets to the container | ||
self.theme.primary_container(column![]).into() | ||
} | ||
``` | ||
|
||
All supported widgets can be created via the Theme instance. | ||
The Prettygooey workflow involves: | ||
|
||
```rust | ||
let button = self.theme.button("Click me"); | ||
``` | ||
1. Creating an instance of [`prettygooey::theme::Theme`](https://docs.rs/prettygooey/latest/prettygooey/theme/struct.Theme.html). `Theme::default()` lets you use default settings. | ||
2. Using the widget creation methods in `Theme` to build your UI. If Prettygooey doesn't have exactly what you want, you can mix and match with self-written UI components. You can keep using floem's `v_stack` and `h_stack` methods to lay out your components. | ||
3. Wrapping your window contents in Prettygooey's padded container to ensure your widgets don't stick to the side of the window. | ||
4. Wrapping the padded container in Prettygooey's primary container to apply the theme's window background. | ||
|
||
Prettygooey widgets may provide optional customizations. Take the Text widget for example. By importing the extension trait [`prettygooey::theme::TextExt`](https://docs.rs/prettygooey/latest/prettygooey/theme/trait.TextExt.html), you expose a `variant` method that'll let you switch the variant to Dimmed: | ||
[Over here](examples/counter_prettygooey/src/main.rs) you'll find the above example ported to Prettygooey. Here is a reference render: | ||
|
||
```rust | ||
self.theme | ||
.text("Theme selection") | ||
.variant(TextVariant::Dimmed), | ||
``` | ||
![A counter in Prettygooey](docs/img/counter_prettygooey.png) | ||
|
||
## Where to go from here | ||
|
||
For a list of available widgets with screenshots and examples, see the [code docs](https://docs.rs/prettygooey/latest/prettygooey/theme/struct.Theme.html#implementations). | ||
|
||
If you'd like to see more than a few loose snippets, check out the [showcase example](https://github.com/pieterdd/prettygooey/blob/main/examples/showcase/src/main.rs). It's the source code for the screenshot at the top of the README. | ||
If you'd like to see more than a few loose snippets, check out the [showcase example](examples/showcase/src/main.rs). It's the source code for the screenshot at the top of the README. | ||
|
||
## Not quite what you're looking for? | ||
|
||
Pop! OS's [libcosmic](https://github.com/pop-os/libcosmic) implements a much wider range of iced widgets and is backed by device manufacturer System76. On the other hand, libcosmic's learning curve may be a bit steeper. The library is primarily intended for use by applications that are native to the Cosmic desktop environment. | ||
I'm not aware of any other floem UI component libraries right now. As far as Rust UI libraries go, [Iced](https://iced.rs/) is a well-known one. Device manufacturer System76 is using it to implement its own desktop environment. You might be able to build onto their work by checking out [libcosmic](https://github.com/pop-os/libcosmic). Be advised that its learning curve may be a bit steeper than floem, and that the library is primarily intended for use by applications that are native to the Cosmic desktop environment. | ||
|
||
That said, I'd still check it out and make up your own mind. | ||
If you're willing to consider Electron-like solutions that may have a larger resource footprint, I'd definitely check out [Tauri](https://tauri.app/). Since it's built on HTML/JS/CSS, you can use it with any web-based UI framework. |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
[package] | ||
name = "pure-floem" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
prettygooey = { path = "../.." } | ||
floem = { git = "https://github.com/lapce/floem", rev = "92ba6406b2406e4223933267137229db0a619a0a" } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
use floem::reactive::create_signal; | ||
use floem::view::View; | ||
use floem::views::{h_stack, label, text, v_stack, Decorators}; | ||
use floem::EventPropagation; | ||
|
||
/// Renders your UI, and updates it whenever a signal fires | ||
fn app_view() -> impl View { | ||
// Use counter.get() to access the counter value. | ||
// Change it with set_counter.update(..) or set_counter.set(). | ||
let (counter, set_counter) = create_signal(0); | ||
|
||
// v_stack = vertical group layout | ||
v_stack(( | ||
label(move || format!("Value: {}", counter.get())), | ||
// h_stack = horizontal group layout | ||
h_stack(( | ||
text("Increment").on_click(move |_| { | ||
set_counter.update(|value| *value += 1); | ||
EventPropagation::Stop | ||
}), | ||
text("Decrement").on_click(move |_| { | ||
set_counter.update(|value| *value -= 1); | ||
EventPropagation::Stop | ||
}), | ||
)), | ||
)) | ||
} | ||
|
||
fn main() { | ||
floem::launch(app_view); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
[package] | ||
name = "hello-world" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
prettygooey = { path = "../.." } | ||
floem = { git = "https://github.com/lapce/floem", rev = "92ba6406b2406e4223933267137229db0a619a0a" } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
use floem::reactive::create_signal; | ||
use floem::view::View; | ||
use floem::views::{h_stack, v_stack, Decorators}; | ||
use floem::EventPropagation; | ||
use prettygooey::label::LabelVariant; | ||
use prettygooey::theme::Theme; | ||
|
||
fn app_view() -> impl View { | ||
let theme = Theme::default(); | ||
|
||
let (counter, set_counter) = create_signal(0); | ||
|
||
theme.primary_container(theme.padded_container(v_stack(( | ||
theme.label( | ||
move || format!("Value: {}", counter.get()), | ||
LabelVariant::Regular, | ||
), | ||
h_stack(( | ||
theme.button(|| "Increment").on_click(move |_| { | ||
set_counter.update(|value| *value += 1); | ||
EventPropagation::Stop | ||
}), | ||
theme.button(|| "Decrement").on_click(move |_| { | ||
set_counter.update(|value| *value -= 1); | ||
EventPropagation::Stop | ||
}), | ||
)), | ||
)))) | ||
} | ||
|
||
fn main() { | ||
floem::launch(app_view); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters