Anyone able to make non-terrible themes?!
Well, I've been updating and trying to get a basic theme api setup in Fidgetty. I'm mostly going for the most basic widget/theme support roughly following common idioms found in web based ones like Bootstrap, Bulma CSS, Material Design.
I also fixed some bugs with orgBox'es which make it easier to do fancy constraints using Em and Vh calculated units.
Useful points:
Ideally customizing an individual widget's theme would look something like:
Checkbox:
value: self.myCheck
text: fmt"Click {self.myCheck}"
withSubTheme:
theme.highlight = themePalette.warning
theme.foreground = themePalette.warning.lighten(0.2)
theme.text = themePalette.textDark
Though currently I haven't implemented withSubTheme, but you can do this. See the image below for the resulting (yellow) checkbox.
You can run nim c -r -d:release -d:demoBulmaTheme tests/testDemo.nim to see the result.
wow, this is a cool direction.
But please note that inventing a theming system is a big task. I am sorry to repeat myself but I think it would be wise, to copy the properties of widgets from other systems.
I think Flutter is probably the most advanced/flexible here(Kivy is also nice, css and friends can be used for macro syntax).
This is about the fields and how to structure things, because for example text theming is not just color, it can be font style, it can have future features: perhaps effects like shadow, blur etc. But thinking too large is also a danger, because then you risk never finishing.
Just an idea: what do you think of passing a struct, basically a typed hashtable, of all the possible properties, and if a widget has some handling for that property, it will render it accordingly.
The user fills whatever s/he wants of that object.
The purpose is that the API doesn't change very much, and you can just add functionality ""at your leisure"". (because you specified you want to avoid a heavyweight object oriented style)
One last note: velocity_x syntax (sorry flutter related again). builds on flutter and just adds extension methods (for Nim, they would just be procs) and look what they are able to achieve (fluid syntax that returns an object):
"Welcome to VelocityX".text.white.xl4.bold.center.makeCentered().box.roundedLg.red500.shadow2xl.make().whHalf(context).centered();
wow, this is a cool direction.
Thanks! Good to hear others think it's a good direction. It's a tricky problem that's been done many times and no ones found the Perfect Solution (tm), at least IMHO.
This is about the fields and how to structure things, because for example text theming is not just color, it can be font style, it can have future features: perhaps effects like shadow, blur etc. But thinking too large is also a danger, because then you risk never finishing.
It is hard. Luckily I've used a number of theme systems and some amount of HTML/CSS. So it gives me enough context I've gotten a basic set of useful items. Currently the fields/properties I've added are enough to handle the basics, I think.
Here's they are:
Palette* = object
foreground*: Color
accent*: Color
highlight*: Color
disabled*: Color
background*: Color
text*: Color
textBg*: Color
cursor*: Color
GeneralTheme* = object
textStyle*: TextStyle
textCorner*: float32
innerStroke*: Stroke
outerStroke*: Stroke
gloss*: ImageStyle
cornerRadius*: (float32, float32, float32, float32)
shadows*: seq[Shadow]
horizontalPadding*: float32
verticalPadding*: float32
itemSpacing*: float32
Partly I'm thinking that instead of needing to handle _every kind theme ability is to lean on Fidget and let users easily create custom widgets based on existing ones. Sort of like borrowing from some of the React patterns people seem to use. That has pros and cons so it may not be best way forward.
Still I like that Fidget makes it soooo easy to create custom widgets. It still takes a bit of work to make good widgets but you're at least not fighting the framework. Outside of HTML world it usually seems to require a lot of setup to make custom widgets.
Just an idea: what do you think of passing a struct, basically a typed hashtable, of all the possible properties, and if a widget has some handling for that property, it will render it accordingly.
It's definitely crossed my mind. I was thinking of sticking with the above, but adding extras properties that could be user defined. Ideally it'd use compile time generated unique id's rather than string to be fast, but Nim makes that pretty easy.
I think that could look like:
if theme.hasExtraProperty[LeftPadding]:
let leftPad = theme[LeftPadding]
let x = box.x +
if pallete.hasExtraProperty[CapitalLetterFontSize]:
let capitalColor = pallete[CapitalLetterFontSize]
...
@kobi what do you think about a system like that?
General Updates
TextBox and Text Editing Updates
The "glitching" that occurs when editing a text node is gone. The glitch occurred when you unfocused a text item after updating the text.
This was done by modifying the text input system (TextBox) to use the same text directly from Fidget Nodes. It required switching Fidget Nodes to use unicode Runes instead of strings. However, it likely makes sense even if it uses more memory since calculating text layout doesn't require converting to/from strings. The TextBox's are also now stored in Fidget Node's after editing the field. This should make it easier to maintain things like the text selection in a text box after re-focusing on it.
Themes
I've added some templates to help overriding sub-themes and sub-pallets for given set of widgets. This is useful for say making "warning widgets" which use some coloring for warning.
Here's a the syntax as found in TestDemo:
Theme(warningPalette()):
Checkbox:
value: self.myCheck
text: fmt"Click {self.myCheck}"