-
Notifications
You must be signed in to change notification settings - Fork 19
Element styling / CSS / overriding default styles #22
Comments
So, originally I was going to do some refactoring of widget state in general, because there are some things about it that can be made more general, and some of which interact with styling, specifically "properties", but actually I think it might be better to just deal with styling now and try to refactor that later. A lot of similar mechanisms used to style draw state right now can be expanded to apply to widgets, which along with some mechanism for selecting widgets to style, gets us most of the features you're describing. Also I do think it will be closer to CSS than what I might have suggested before.
Hmm, maybe after the refactoring of properties I'm thinking about, you could define your own property for "is above a certain size" and provide a selector on that property. Until then, the simpler solution which is less flexible is just to add a flag to your widget that can be styled that will hide something specific.
Yes if you don't specify any style sheet, no styling means using the defaults for everything, which will be supplied by
Eventually you should be able to load styles from a file, but this will be after everything is made possible in Rust first. It should validate the whole style sheet against types you have registered in your app when the style sheet file is loaded, so it should be as reliable as inline style declarations as long as you make sure you validate before deploying.
Not totally sure what you mean, but the style sheet, whether it's inline, or from a file, will have to be initialized when the application starts up.
Yes, there should be some ID and class like system for selecting widgets, both globally and locally.
Not sure I understand. A different thing related to cassowary I should mention that it's not possible right now to declare relative constraints between widgets without the widgets actually existing, which I think will be needed to style layouts the way they need to be. Because of this, I'm going to make everything styleable except for layout, then make the needed changes to
There should be pre-defined classes, but they shouldn't be generic to any widget I don't think. So for instance you would have Just a heads up, I'm starting to work on this now. |
So the basic plan is this, create style definitions for widgets, eg. Styles will be selected based on this priority:
|
Yes, this is what I thought to use cassowary for: Assign different weights to the 1 - 5 priorities, then let cassowary solve for the best one. Just an idea, though. I don't have that much time to work on limn, mostly only weekends. I'll try to finish #29 in order to get the customization going. |
Hmm yeah I'm not sure if cassowary can be very useful for weighting priorities, I don't think it makes sense to put styles inside the cassowary solver for example. Btw, not sure if you are still working on #29 but if so I'd say focus on the font loading part and on my comments on there, let me know if you are doing any work that's style related. The work I've done on this will probably overwrite any of your changes to What I'm working on actually replaces the custom |
Well, I'd wait for your stuff then and try to merge #29 with your components. I currently have a lot of stuff to do in the coming weeks, so I won't have the time to work on limn much. |
I've created a PR that lays the foundation for most of the items you have listed here, this is copied from the new
What's missing is still:
I think the foundation is there though so I'm going to leave it as is to focus on other things for the time being, @fschutt let me know if you have any feedback on the current design. |
I guess its OK, but the font is still hard-coded to |
I also wanted to say: If you compile the examples in release mode, you get a segmentation fault when trying to run them. I don't know where this is coming from, I'll try to find the source. UPDATE: The segfault seems to be a problem of nightly 25-11 |
@fschutt sure, this is not intended to solve font loading, there is no change to how fonts are named or loaded. I don't think there should be any overlap in the logic of font inheritance, handled by the style module, and font fallback, handled by the font loader. |
Thanks for the heads up on the seg fault, just updated nightly, seems to be fixed in 26-11 |
i think you could make the macro cleaner:
or split it to
not sure if its possible but I think current macro looks little messy. |
@jaroslaw-weber hmm yeah it is a little busy, unfortunately I don't think it can be split without requiring everything to be duplicated in I agree there is a bit of rightward drift and it's a little funny how it specifies name where generics would go, but I still think the first is better, if name could be moved out and have
or:
|
@christolliday |
loadin styling from file is nice, but what about performance overhead? with some code generation we could try to make styling embedded, we could load styles faster. for hot reload we could use overriding with serialized stylesheet about generic styling, like bootstap, i would provide it as outside library. make core library dirty and simple. |
Hmm the idea was to have it resemble an associated type hence the <>, it's actually a trait on ButtonStyle that has Button as an associated type, but it makes more sense to declare I'm not too worried about the overhead of loading styles from a file, dealing with the overhead of actually applying (and reapplying) the styles is going to take more attention. Maybe eventually embedding styles could be useful but probably not for a while. As for providing styles in an outside library, yep, right now styles are actually declared in the example code. Eventually it will make sense to chop up limn into sub crates too but I don't think it's needed yet. |
@christolliday I tried to use limn again to style something. So far I've encountered numbers of bugs:
Not sure if I should make seperate issue for these otherwise I'd just be spamming issues. I don't want to sound too negative, but the absolute most I can do right now is to change the border color (for some reason, this only works for the base state, not |
I'm dont know much about the styling code but the constraints are documented here, I agree it's hard to find. As for padding it can be set individually per side like so...
I haven't had much time to play with limn since #34, but i was planning on playing around with the new style code later on this week. |
@fschutt thanks for the report, to be honest I would say calling it mediocre at this stage is generous. On top of the missing features, there are going to be a few bugs and I think there might be some undocumented assumptions about the order some styling methods need to be run, thanks for reminding me of that in particular I'll try and look into it soon. Actually there are some other things that aren't documented about how these APIs need to be used I'm just remembering now, I'll write those up too, may or may not be related to your issues. I'll look into the rest of your other issues as well but my focus is going to be on working out the fundamental APIs and less on fixing bugs that aren't architectural, so PRs would be appreciated! Issues as well. The other thing is, the styling work done so far is purely to create a foundation for declaring and applying styles, and is only used for the low hanging fruit so far, there also needs to be work done in creating the appropriate styleable components and using them in more places. (for example, a component that specifies the layout of a child relative to its parent could be made and applied to a child). The work here should simplify declaring layouts in general, so that you should only rarely need the API that specifies relationships between any arbitrary set of widgets (currently the only API). |
@christolliday Just wanted to tell you: I've used your constraint code here. I am working on that library now, which uses CSS instead of constraints (mostly because it's more flexible). I'll credit you as an author, I hope that's OK. I can't really use |
@fschutt of course that's ok and thanks for the heads up, disappointed that you decided against contributing to limn, but more experimentation in this area is always good! I do have some opinions on the scalability of your approach though if you are interested. Ultimately limn will likely support CSS but I can't blame you for thinking otherwise because I haven't made it at all clear what the path is between where it is and where it is planned to be is, I'm more focused on implementing specific features, and supporting CSS files directly is not yet my first priority. As for limn-layout, you might think the model of limn-layout is heavily tied into the model of limn but it's as much if not more so based on the model of cassowary, which influences limn. Not all of limn-layout, but the bulk of it. I had a quick look at how you are using cassowary, I could be wrong but it seems to me you are recreating the entire layout for every change without caching any of it? If that is the case I think you will probably run into major performance issues, and if you try to optimize it and still use cassowary you will end up recreating something similar to limn-layout. |
@christolliday I've thought about performance, but currently it's not too bad. Currently, if I have 500 dom elements I have a frame time of roughly 2 - 4ms + 1ms for rendering and my target is 16ms (60 fps), so I still have a lot of headroom to spare even if cassowary should get expensive. Of course, I don't redraw every frame, only if it's necessary, so the CPU usage is rather low. Yes, you can probably do it faster and there are lots of things that I have missed in terms of performance optimization, but I can fix those later. There are lots of "shortcuts" and caching strategies available, at least for the CSS. For example, if only the background color of something changes (on a hover event, which is very common), you don't have to re-layout the whole thing. The idea was to rebuild the entire DOM on every redraw so you don't have a Basically, the only time a re-layout is necessary is:
So yes, I don't currently cache much (except for the CSS), but I don't think I'll have extreme performance problems, even though my model isn't that CPU-friendly. And yes, that doesn't fit very well with cassowary. I exploit a bit the fact that Rust is already pretty fast. Right now it's in the early stages of development, though, so I can't really predict if the performance will be sufficient. As for limn, it's a cool project, but I just didn't see any updates for months and I thought you had given up. My goal with CSS is basically to force the application programmer to embed a CSS file in the application (via If you want to use CSS, you can take a look at the css-parser file, it has lots of utility functions that you might want. |
@fschutt to be clear the benefits of having your UI state be a function of application state are undeniable and is what I'm aiming for as well but in a different way. It seems like you are creating a better Conrod, which is what I am trying to avoid with limn. I think the only reason this approach works efficiently for javascript frameworks is because they are not constructing the UI for every change, they are only constructing a representation (virtual DOM) that can be diffed against a representation of the existing state. My plan with Limn is to first create a mutable tree (DOM) and it's representation as a foundation for a diffable representation (virtual DOM). Both so that the mutable tree API can be used on a per component basis to avoid the cost of diffing, but also to avoid overreach, no point in a virtual DOM if the DOM is not reliable. You might want to skip the part of having a mutable API to fallback on, but unless you use something analogous to a virtual DOM, I think the upper bound on performance will be below that of a web app, which seems to me at least to defeat the purpose of using Rust for a GUI. It's good that you only update the UI in response to model changes, but optimizing for the case where the model changes once per frame is important too. When you say ~3-5ms per render, does that include adding and calculating constraints for 500+ elements? |
@christolliday good catch. I've tested this with 500 constraints, if I add and remove all constraints every frame, it needs roughly 8ms (for 500 constraints), otherwise only 0.3 ms (for calculating the layout). Now, I can currently use the slow way because even then I'll stay below 16ms. But eventually, I'll need to do it correctly and cache the components. I've already implemented the css caching (i.e. it only re-layouts now if you push a css rule and only if that css rule actually affects the layout). Now to cache the DOM I'll use hashing. Each DOM node can currently be hashed and then get compared to the hash of the previous state (or be directly compared, without hashing). This way I am still trading in a bit of performance, but it hashing / calculating the checksum of 500 nodes should be faster than removing / adding constraints. Thanks for the heads up. |
@fschutt ok yeah, you can probably get good enough performance through some caching scheme like that, just thought I'd say something having thought about this a lot from looking at Conrod, thinking it's caching scheme is pretty complex and deciding on the mutable tree/virtual DOM approach. But, it's not going to happen overnight for limn and you'll probably get what you need faster the way you are going especially if performance is not critical. Also it might be more trouble than it's worth but if you do cache the layout you might consider using limn-layout and LimnSolver as a layout cache, maintaining a map of DOM node hashes to LayoutIds (analagous to WidgetId in limn), or replacing LayoutIds with hashes, then you can replace constraints on a per node basis. It's not well documented and it might be a poor match for your CSS based system but if you are thinking about it let me know and I'll clean it up/document it better. |
Issue for discussing a possible set of CSS styling rules in order to override the default styling on
limn
widgets + possible implementation design.I want to style my application to look like MS Office. Some other guy maybe wants to style his icons to look more like MacOS. A third guy doesn't care about styling and just wants to have a basic GUI.
Since I personally think that
limn
will win the fight for desktop GUIs in the Rust world, it's necessary to talk about styling, since it'll appear at some point.What the design should allow (my opinion):
hover
andclicked
effect modifiers. I think these are the minimum things that need to be stylable. Currently this can already be done, but you have to copy the wholesrc/widgets/button.rs
file and basically make your own button.limn
(to start styling the application from scratch)Now for questions:
cassowary-rs
to solve for the different properties (which one takes precedence)?primary
,secondary
,success
,danger
,warning
,info
,light
,dark
)?The text was updated successfully, but these errors were encountered: