cogentcore / core

A free and open source framework for building powerful, fast, elegant 2D and 3D apps that run on macOS, Windows, Linux, iOS, Android, and the web with a single Go codebase, allowing you to Code Once, Run Everywhere.
http://cogentcore.org/core
BSD 3-Clause "New" or "Revised" License
1.69k stars 80 forks source link

Form string field as Chooser #1204

Open j0hnsmith opened 1 week ago

j0hnsmith commented 1 week ago

Describe the feature

I'd like a string field in a form struct to be rendered as a Chooser.

I've had a quick dig through the code and it doesn't seem possible as things stand. Essentially this equates to a larger feature request, that form field widgets can be specified via struct tags where appropriate (and in this case, enum values provided).

Code below is indicitive of what I'd like to be possible.

Relevant code

type MyStruct struct {
    SomeField string `widget:"chooser" values:"foo,bar,baz"`
}

form := core.NewForm(someFrame)
form.SetStruct(&MyStruct{}) // SomeField is rendered as a Chooser with available values of foo, bar, baz
kkoreilly commented 1 week ago

This would certainly be good to support. The main question is whether this should be a specific feature for a chooser, or whether it should be general for all widgets; how many use cases are there for such a feature? We used to support a display:"slider" tag, although it looks like that currently isn't working. I will consider how this should best be implemented, and then I can implement it soon. Thank you for the suggestion!

theclapp commented 1 week ago

Could there be some way to make the values settable at runtime in addition to compile time? Or should you just build your own widget and use a regular Chooser in that case?

kkoreilly commented 1 week ago

I think the best solution for this is something like this:

type MyStruct struct {
    SomeField string
}

func (m *MyStruct) CoreFieldValue(field string) core.Value {
  if field == "SomeField" {
    return core.NewChooser().SetStrings("foo", "bar", "baz")
  }
  return nil // this indicates to just use the default value
}

This approach (which is similar to our existing ShouldDisplay; I will add docs for that soon) gives you complete control, so you can idiomatically programmatically specify the widget type and widget properties; in general, it is better to use code than struct tags for more complicated things, which has the added benefit of making it modifiable at runtime as @theclapp asked about above.

j0hnsmith commented 1 week ago

Code is a much better idea, applies to all widgets and avoids a never ending battle of exposing everything via struct tags and keeping them up to date for every new feature.

kkoreilly commented 1 week ago

Okay, I will add a CoreFieldValuer interface.

One question is whether we should get rid of some already existing struct tags and have people just write code for them instead. Things like display:"-", edit:"-", label:"..." etc are very convenient and frequently used, but perhaps more idiosyncratic tags like display:"date" are not merited? Or are they still worth it? There are also various styling tags such as width:"...", grow:"..." etc, which are potentially better expressed with real stylers under this paradigm. Moreover, sometimes it would be very useful to specify a default value outside of a struct tag. Also, it would be ideal if we could merge the aforementioned existing ShouldDisplay with this, although there are some obstacles to doing so.

I will think about this some more, and any feedback is welcome.

theclapp commented 1 week ago

I feel like tags are great maybe for prototyping or some other form of rapid development, or personal or small-scale use, but for larger scale use, code is better.

Is there any way you could reasonably do both, and just have the tag processing code call the lower-level customization functions? (It's entirely possible, of course, that the answer to this question is "No".)

Disclaimer: I have yet to use CogentCore in anything close to "anger", so my opinion may not be worth much.

kkoreilly commented 1 week ago

@theclapp It is certainly theoretically possible (and easy) to do that; the main question is whether the negatives of having two very different ways to do the same thing outweigh the convenience of some of these less frequently used tags. Again, we are definitely going to keep key tags like display:"-", edit:"-", and label:"..."; the main question is about display:"date", width:"...", grow:"...", etc.

Also, I have decided that it makes sense to keep ShouldDisplay separate for various logistical reasons.