| ▲ | kayson 2 days ago |
| I'm very interested in (and a total novice in) cross platform GUI application development. Hadn't heard of GPUI, though I had heard of Tauri. I looked at the GPUI front page and saw this mess of almost-CSS method chaining... Surely there's a better way? This seems horrible to me. > div()
.flex()
.flex_col()
.gap_3()
.bg(rgb(0x505050))
.size(px(500.0))
.justify_center()
.items_center()
.shadow_lg()
.border_1()
.border_color(rgb(0x0000ff))
.text_xl()
.text_color(rgb(0xffffff))
.child(format!("Hello, {}!", &self.text))
.child(
div()
.flex()
.gap_2()
.child(div().size_8().bg(gpui::red()))
.child(div().size_8().bg(gpui::green()))
.child(div().size_8().bg(gpui::blue()))
.child(div().size_8().bg(gpui::yellow()))
.child(div().size_8().bg(gpui::black()))
.child(div().size_8().bg(gpui::white())),
) |
|
| ▲ | ogoffart 2 days ago | parent | next [-] |
| IMHO Rust isn't a great language for describing UIs because it is too explicit in places that doesn't need to be for coding a UI.
Which is why in Slint (another Rust UI framework) we opted for a DSL. The application logic stays in Rust, but the UI is described in a language designed for it. Your example would look like this: export component Hello inherits Rectangle {
in property <string> text: "World";
width: 500px; height: 500px;
background: #505050;
border-width: 1px; border-color: blue;
drop-shadow-blur: 15px; drop-shadow-color: #0008;
VerticalLayout {
alignment: center; spacing: 12px;
Text { text: "Hello, \{root.text}!"; font-size: 20px; color: white; horizontal-alignment: center; }
HorizontalLayout {
alignment: center; spacing: 8px;
for c in [#f00, #0f0, #00f, #ff0, #000, #fff]: Rectangle { width: 32px; height: 32px; background: c; }
}
}
}
More on why we chose a DSL vs code in Rust: https://slint.dev/blog/domain-specific-language-vs-imperativ... |
| |
| ▲ | thisismyanon2 a day ago | parent | next [-] | | My experience has been that DSLs don't scale well. For simple things they provide a veneer of ease-of-use but eventually they were an albatross with Chef just as they were with QML and Slint. With both Slint and various Qt bindings for Rust marshalling data between Rust and the UI is painful. With Slint you get the added bonus of things just not yet existing in the DSL. That's a result of both immaturity and a strong focus on mobile at the expense of desktop. But the result is same. gpui has a killer dock widget, QML has the primitives to approximate one, and it's pretty much a no-go with Slint (though there's a third-party dock widget for Slint it's written in C++). Here's a more idiomatic version of the previous example. IME gpui (and iced) is a lot easier to extend than something with a DSL, and if you check out the gpui example you'll see that gpui provides convenient methods to get consistent styles vs the Slint example where you hardcode widths and sizes. Those hex color abbreviations give me a facial tic every single time. use gpui::{black,red,green,blue,yellow,white};
let Self{text,..} = self;
v_flex()
.gap_3()
.bg(rgb(0x505050))
.size(px(500.0))
.justify_center()
.items_center()
.shadow_lg()
.border_1()
.border_color(black())
.text_xl()
.text_color(white())
.child(format!("Hello, {text}!"))
.child(
h_flex()
.gap_2()
.children(
[red(), green(), blue(), yellow(), black(), white()].map(|color|
div().size_8().bg(color)
)))
| |
| ▲ | c-smile 2 days ago | parent | prev | next [-] | | > Rust isn't a great language for describing UIs because it is too explicit in places that doesn't need to be for coding a UI. That's is not about just Rust ... Any domain has its own optimal or sub-optimal language describing it. Criteria of optimality is a bit subjective of course. Like: INI, TOML, YAML, etc. are better (YMMV, again) for user facing configs than JSON or XML and so on. I think that HTML is better for defining hierarchical UI structures and CSS and CSS selectors are (arguably again) better to define UI styling. My Sciter[1] was initially using .FRM alike inputs (VisualBasic forms, good for IDE but bad for a human) but I quickly discovered that having styles, structure and code-behind-UI in single PL makes non-manageable mess. So Sciter uses HTML, CSS and JS we all familiar with. Not 100% match of course but good enough. [1] https://sciter.com | | |
| ▲ | ivanmontillam a day ago | parent [-] | | I love Sciter, but the curse of Discord is bloated web. They have no shame in deploying a 300 MB hot mess bundle. |
| |
| ▲ | MisterMunchkin a day ago | parent | prev | next [-] | | Slint is proprietary though, so that’s a dead end. I’m not going to use something which will inevitably be rug-pulled when you sell to private capital. | | |
| ▲ | ogoffart a day ago | parent [-] | | Slint is an open source, free software. The whole framework is on GitHub. A rug pull can't take back what's already released, and one could always fork if needed. Btw, a rug pull can happen under even the most permissive licenses. As we've seen in the past with some project changing license or direction. That's more or less already happened with GPUI when Zed refocused development on its own needs rather than other GPUI users resulting in several forks. |
| |
| ▲ | LittleLily a day ago | parent | prev | next [-] | | isn't that basically QML? | |
| ▲ | IshKebab a day ago | parent | prev [-] | | I'm not sure it matters anymore unfortunately. I've vibe coded a few apps using gpui-kit and it works well. It helps that gpui-kit provides a number of high quality components (e.g. the data table is especially good). But even where it doesn't (e.g. log output) Opus 5.5 was able to easily write one that worked perfectly. It even added ANSI colour support... which I am still on the fence about but it did make the very good point that it means the logging is exactly the same in GUI and CLI mode. |
|
|
| ▲ | ordu 2 days ago | parent | prev | next [-] |
| > Surely there's a better way? I'd like to know it. I don't think that it can be substantially better. You have to compromise between the amount of customization you are allowed to do and the amount of options you have to pick values for. I can't vouch for GPUI, I don't know how good its compromise is, but it bears enough similarities to other modern UI-toolkits. I don't think there is a better way, but if you know one, I'd like to know about it. And, well, don't forget, it is a front-page example, that is not necessarily an example how one should compose their code, it demonstrates what you can do with GPUI. In real life code you'd probably move those children's construction into separate named functions, maybe you'd use some predefined styles to apply to individual elements, instead of picking fg/bg/text-colors, maybe sizes and some other attributes for each one explicitly, and maybe some other tricks. |
| |
| ▲ | eviks 2 days ago | parent [-] | | One improvement could be a better way to group and elide units, e.g. Instead of .border_1().border_color(rgb(0x0000ff)) You get .border(1 0x0000ff) (guess, this can only be in a macro) Or at least have "color" which understands that it's allied to border instead of having to repeat "border" > I don't think that it can be substantially better Don't give up too early, there is no way it can't be, we don't really have any good systems optimized for ergonomics to reach anything great | | |
| ▲ | c-smile 2 days ago | parent [-] | | > .border(1 0x0000ff) After 10 or so of those you'll start dreaming of border-left: 2px solid rgb(0 0 100%);
right? | | |
| ▲ | eviks a day ago | parent [-] | | If you're dreaming, why would you stop at that when you could dream of much more visually compelling solid left thick border in a single symbol ┠ or more explicitly ├2 that'd be perfectly paired with a dream-like visual designer that doesn't exist? |
|
|
|
|
| ▲ | tcallred 2 days ago | parent | prev | next [-] |
| All a language needs to be good at expressing UIs is some sort of tail lambda syntax like Swift and Kotlin. It's the perfect way to express a tree structure (which is essentially all UI) while also being in a true programming language (as opposed to a markup language like XML). |
|
| ▲ | CupricTea 2 days ago | parent | prev | next [-] |
| This is basically what coding UI in Bevy was like before the `bsn!` macro |
|
| ▲ | odo1242 2 days ago | parent | prev | next [-] |
| Well, keep in mind that you’re not expected to have the entire UI in one statement. You’re supposed to break this up into functions. That’s why stuff like Flutter and SwiftUI work. Also, this is basically what Tailwind code looks like. |
|
| ▲ | ijustlovemath 2 days ago | parent | prev | next [-] |
| That's a result of the borrow checker meeting dev ergonomics. Method chaining/functional style ks extremely common. GPUI is also fairly low level, it lets you do a ton of things! |
|
| ▲ | kalleboo 2 days ago | parent | prev | next [-] |
| I'm never going to complain about SwiftUI again |
|
| ▲ | selfmodruntime 15 hours ago | parent | prev | next [-] |
| HTML and CSS, for all their faults, are the best layout engine we have. |
|
| ▲ | tomburgs 20 hours ago | parent | prev | next [-] |
| Honestly I'd pick this over whatever is going on with tailwind. On a more serious note I feel like it's not bad but could be improved if they managed to break it down by styling domain (sort of like SwiftUI). Something along the lines of .flex(gap: 2).text(size: "xl", color: ...) |
|
| ▲ | vazark 18 hours ago | parent | prev | next [-] |
| honestly I'm not sure why they didn't choose to define a curated subset of HTML/CSS and use a parser. That's what the code is defining anyway |
|
| ▲ | desolate_muffin 2 days ago | parent | prev | next [-] |
| Someone needs close the loop and make an HTML/CSS to GPUI transpiler |
| |
|
| ▲ | alexaholic 2 days ago | parent | prev [-] |
| One person's mess is another person's Tailwind |