Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

on_click vs onclick #5

Open
ronny-rentner opened this issue Jan 10, 2022 · 6 comments
Open

on_click vs onclick #5

ronny-rentner opened this issue Jan 10, 2022 · 6 comments

Comments

@ronny-rentner
Copy link
Contributor

ronny-rentner commented Jan 10, 2022

Hi, first of all many thanks for your great project. After fiddling around with wxpython for a while, it's a real relieve :)

I was a bit surprised to find the prop being called "on_click" instead of "onclick".

You refer to React as an inspiration and they're doing "onclick" in their examples like here https://reactjs.org/docs/handling-events.html

Do you think it's too late to rename it in re-wx to "onclick"?

Ronny

@chriskiehl
Copy link
Owner

Hey! Glad you like it! It was a vacation hackathon that got outta control ^_^

Definitely not too late to rename things. This is all experimental alpha-level code at the moment, so everything is fair game. I welcome any / all ideas! That said, I'm not sure it's worth breaking the other snake_case on_blah style event handlers for this bit of React parity. onclick is kind of the odd man out that it's lowercased like that. It looks like just about all of React's handlers are camelCased, and same here with the form handlers. Since snake_case is a bit more idiomatic in python, I think it makes sense to just have all the handlers look the same for consistency (e.g. on_{event}).

Longer answer, this is ultimately due to the APIs design that makes on_click vs onclick something surprising which has to be discovered. The original wsx approach was heavily inspired by Clojure's Hiccup library. Which, while I dig its terseness and readability, it provides no useful mechanism for API discovery / correctness without browsing out-of-band documentation or reading the implementation.

As such, I've been kicking around an alternative wsx version where the objects all partially evaluated to generate the internal elements (rather than entirely deferred ala standard React). That'd make it so that your IDE can help you discover the API as you go, as well as all the other usual niceties that come with function application.

Something like...

return wsx2(
  [c.Frame(title='My cool program!'),
    [c.Block(orient=wx.HORIZONTAL),
     [c.StaticText(label='Hello world!')],
     [c.Button(label='click me!', on_click=lambda x: print(x))]]]
)

That'd be something that lets the type checker do the heavy lifting.

@ronny-rentner
Copy link
Contributor Author

Cool :) Ideally, I'd like to be able to do something like

wsx = wsx2_builder()
return (wsx.build()
  .Frame(title='My cool program!')
      .Block(orient=wsx.consts.HORIZONTAL, bgcolor=wsx.consts.BLACK)
          .Label(label='Hello world!', margin=15, color=wsx.consts.RED)
          .Button(label='click me!', on_click=lambda x: print(x))
          .Block(orient=wsx.consts.VERTICAL, text_align=wsx.consts.RIGHT)
              .Label(label='Hello world!', margin=15, opacity=0.5)
              .Image(uri='some.jpg', width=100, keep_aspect=False)
              .Button(label='click me!', on_click=lambda x: print(x))
              .end()
          .Button(label='close', on_click=sef.close)
)

This would save a lot of headaches about missing or wrong parenthesis and make it so much more readable. I admit it's probably not pythonic. My background is more web programming. Probably that's also one reason I had expected onclick because the on* HTML attributes are spelled like this.

While we are at it, in a local branch, I've aliased StaticText to Label and StaticBitmap to Image. Also, I've added a props filter that will translate "more css like props" into the respective wx props, e. g. when you set

margin=15 it translates into flag|=wx.ALL and border=15

Container type elements like Block that could have children would always expect them to be added next, so the builder would have to keep some kind of track if the last element added was a container element. It introduces the ugliness of the end() method which is a necessary downside of this approach. We could probably even get around it with some hack to analyze the indentation level. It could be more explicit with adding a .begin() to the .end().

The key goal is to somehow flatten out that tree structure of components so you don't have to carry and count open parenthesis all the time.

In a real app, the tree structure will be much more complex than our simple examples. I've already had the case a couple of times that I miscounted and also the errors are really hard to spot if you have many nested Blocks and a missing comma after some parenthesis.

Wdyt?

@ronny-rentner
Copy link
Contributor Author

PS: Maybe a more pythonic style would be:

with wsx.Frame(title='My cool program!') as f:
      with f.Block(orient=wsx.consts.HORIZONTAL, bgcolor=wsx.consts.BLACK) as b:
          b.Label(label='Hello world!', margin=15, color=wsx.consts.RED)
          b.Button(label='click me!', on_click=lambda x: print(x))
          with b.Block(orient=wsx.consts.VERTICAL, text_align=wsx.consts.RIGHT) as inner:
              inner.Label(label='Hello world!', margin=15, opacity=0.5)
              inner.Image(uri='some.jpg', width=100, keep_aspect=False)
              inner.Button(label='click me!', on_click=lambda x: print(x))
          b.Button(label='close', on_click=sef.close)

@ronny-rentner
Copy link
Contributor Author

ronny-rentner commented Jan 13, 2022

PPS: There is https://github.com/AndersMunch/wxWize and https://github.com/JoshMayberry/GUI_Maker that seem to use the 'with' approach

@chriskiehl
Copy link
Owner

lol. The contextmanager approach is interesting and pretty clever.

There's another option of just being explicit about the children.

c.Frame(title='my cool program', children=[
    c.block(orient=wx.HORIZONTAL, children=[
        c.StaticText(label='hello_world')
        c.Button(on_click=lambda x: print(x))
    ])
])

This is the approach taken in the Purescript React Basic library, which is pretty straight forward.

I shy away from the builder format not for sane or rational reasons, but because I mostly write Java at $dayjob, and .builder().blah().build() is something I only want to write when getting paid to do so ^_^

The key goal is to somehow flatten out that tree structure of components so you don't have to carry and count open parenthesis all the time.

Agreed. I think this is a good goal. While the Lisp fan in me doesn't mind a good parenthesis (or bracket) hunting session, it definitely has its shortcomings. As I go about rebuilding a substantial portion of Gooey in rewx, the pain on my end has mostly been needing to constantly refresh myself on what API methods are there and actually supported.

margin=15 it translates into flag|=wx.ALL and border=15

So, I'm mostly against this one in the core library (but such a thing would surely make a good add-on enhancement lib!). The rationale being that rewx's sights are aimed fairly low. Namely, making wx less awful through better state management and declarative layouts. The allure of smoothing out all kinds of lower-level GUI APIs behind an standardized html-ish one is super alluring (ala: React Native / Electron), but ultimately outside of the modest scope of rewx.

@ronny-rentner
Copy link
Contributor Author

Hey, thanks for your reply and sorry for hijacking this issue ticket for such discussions. I'm not sure what's the best place for such a discussion.

The more I dive into wx, the more I realize that it has deeper problems than just its messy API. I mean apart from the fact that all major controls use different methods to add children (Add() vs Append() vs AddTool() vs ...) also the sizers need a lot of different parameters combinations and attention if you want a good looking result.

In the docs, you're mentioning a 'virtual dom' for re-wx. I've recently watched this video about a new trend in JS to go away from a 'virtual dom'. https://www.youtube.com/watch?v=AdNJ3fydeao&t=7s I found that really inspiring.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants