PMunch / wxnim

Nim wrapper for wxWidgets.
MIT License
94 stars 11 forks source link

controlgallery.nim fails with "object.nim(37, 78) Error: invalid indentation" #28

Open harrier77 opened 4 months ago

harrier77 commented 4 months ago

I have followed the instructions in Readme: cd examples/genuimacro nim cpp -r controlgallery.nim but the compiler exits with this wxnim-master/wxnim/private/object.nim(37, 78) Error: invalid indentation

I tried to edit the code, re-enter the indentation as tab (not allowed) and as spaces (2 or 3), nothing works. I think I am missing something about nim syntax.

PMunch commented 4 months ago

I haven't had time to test this, but looking at that line I believe it is the pragma syntax which has gotten stricter. If you move the [T] part to right after the * I believe it should work. Granted this project hasn't been touched in quite a while, so you might run into other issues..

harrier77 commented 4 months ago

This is the line: 37 WxObjectDataPtr {.importcpp: "wxObjectDataPtr", header: wxh, inheritable.}[T] = object What do you mean with "move the [T] part to right after the "? The [T] is already on the right part just before the =.

But I tried with WxObjectDataPtr*[T] and actually the compilation goes on, it stops after some other lines: object.nim(65, 42) Error: undeclared identifier: 'WxClassInfo' . Maybe the line 37 error is resolved but there is something else.

PMunch commented 4 months ago

Yes, that's what I meant by right after the *. Are you still trying to compile the controlgallary? Or did you now try to compile just object.nim? It can't be compiled on its own because it relies on being include-ed at the right place.

harrier77 commented 4 months ago

I tried to compile controlgallary and it stops at line 65 of object.nim with "Error: undeclared identifier: 'WxClassInfo'" If I try to compile object.nim by itself, it stops at line 15 object.nim(15, 42) Error: undeclared identifier: 'wxh' It seems to have no sense, it passes line 15 when is linked to controlgallery but has error by itself.

PMunch commented 4 months ago

It actually makes perfect sense. In Nim import and include are two different things. The former is a nice hygienic thing which does namespaces and deduplication and all that jazz, while the latter is a simple copy-paste of the file into your current source file. That's why object.nim won't compile on its own and fails in a different place. The error in this case was caused by the {.noforward: on.} pragma in wx.nim changing name to {.experimental: "codeReordering".}. There was a hint about this in the compilation output.

After having fixed that and a couple more misplaced generics in the code I managed to get further in compiling. However I hit a dead end at the "implicitDeref" experimental pragma which was removed in Nim 2.0.0. This is unfortunate as it requires a rewrite of this library to be functional again. However I have pushed my changes as they are backwards compatible with 1.6.18, which still compiles this just fine (and is still supported).

harrier77 commented 4 months ago

Ok, I misunderstood your previous post. Yes, it has perfect sense, the object works only when included. Thanks for your work on this Library if you succeed in making it work again I can help you in some way testing it. I want to learn nim coding a small interface with WebView and wxwidget.

PMunch commented 4 months ago

I mean you can just run choosenim 1.6.18 and the library still works if you want to use it. But I'll try to get this fixed up at some point.

harrier77 commented 4 months ago

Ok, it works. Thank you for suggesting the use of choosenim, now I have two version of nim installed and I can switch very easy from one to the other. (I have to understand where both are installed )

harrier77 commented 4 months ago

I tried the examples, with genui and without. But it's not easy for me to manage the various options only using the source code of wxnim as reference. Are there examples with different combinations of controls and layout? With c++ I use wxlglade to set up the position of controls and sizers and so on. And after exporting the code I can learn the syntax. For example I have this cpp code, panel_1 = new wxPanel(this, wxID_ANY); wxGridSizer* grid_sizer_1 = new wxGridSizer(3, 3, 0, 0); grid_sizer_1->Add(0,` 0, 0, 0, 0); grid_sizer_1->Add(0, 0, 0, 0, 0); grid_sizer_1->Add(0, 0, 0, 0, 0); grid_sizer_1->Add(0, 0, 0, 0, 0); button_1 = new wxButton(panel_1, wxID_ANY, wxT("Avvia")); grid_sizer_1->Add(button_1, 0, wxALIGN_CENTER, 0); grid_sizer_1->Add(0, 0, 0, 0, 0); grid_sizer_1->Add(0, 0, 0, 0, 0); grid_sizer_1->Add(0, 0, 0, 0, 0); grid_sizer_1->Add(0, 0, 0, 0, 0); panel_1->SetSizer(grid_sizer_1); Layout();

How can I rewrite it using genui or purewx?

PMunch commented 4 months ago

For purewx it should be pretty much the same, just convert the syntax to Nim. For genui I believe something like this would be what you're looking for:

# NOTE: these imports are relative to this folder, this would not be required if wxnim was installed with Nimble
import "../../wxnim/wx", "../../wxnim/genui"

# Experimental is required for now, this will become default later
{.experimental: "implicitDeref".}

# Generate the GUI
genui:
  mainFrame % Frame(title = "Hello World"):
    Panel | Gridsizer(3, 3, 0, 0):
      Button[flag = wxAlignCenter]: "Avvia"

# Show the main frame and run the main loop
mainFrame.show()
runMainLoop()

As you can see you use the | operator to attach a sizer to an element, and [] to set the arguments when adding to a sizer. Adding elements to other elements and sizers are done automatically by indentation.

PMunch commented 4 months ago

By the way, you can pass --expandMacro:genui during compilation and Nim will show you what the genui macro expands to which is very helpful.

harrier77 commented 4 months ago

Thank you, I can watch the macro expanded. Now I can place Button in cell at position 0,0 of the grid, but in the code generated by wxglade I was able to place it in the position 1,2 using "grid_sizer_1->Add(0, 0, 0, 0, 0)" 3 times in the first row and 1 time in the second, (the same way I should use "td /td" in html). How can I do the same using genui?

harrier77 commented 4 months ago

By the way, I have just installed wxformbuilder, it seems better that wglade and it can export python, cpp and lua. How difficult is to create a plugin to make it export in nimx genui macro?

PMunch commented 4 months ago

You can just do the same thing in WxNim:

# NOTE: these imports are relative to this folder, this would not be required if wxnim was installed with Nimble
import "../../wxnim/wx", "../../wxnim/genui"

# Experimental is required for now, this will become default later
{.experimental: "implicitDeref".}

# Generate the GUI
genui:
  mainFrame % Frame(title = "Hello World"):
    panel % Panel | Gridsizer(3, 3, 0, 0)

panel.getSizer.add(0, 0, 0, 0)
panel.getSizer.add(0, 0, 0, 0)
panel.getSizer.add(0, 0, 0, 0)
panel.getSizer.add(0, 0, 0, 0)

panel.addElements:
  Button[flag = wxAlignCenter]: "Button"

# Show the main frame and run the main loop
mainFrame.show()
runMainLoop()

Of course you could've just added some StaticText: "" elements in the original definition to fill those cells as well.

As for wxformbuilder/wxglade I have no idea, never used either of them.

harrier77 commented 4 months ago

Thanks! It works exactly as intended. But now I have to understand better the syntax: the four times panel.getSizer.add(0, 0, 0, 0) are not indented, so for what I can understand it means that they are outside genui macro, or am I wrong? And why is there a % before "Panel"?

PMunch commented 4 months ago

Did you read the explanation of the genui macro in the README? https://github.com/PMunch/wxnim?tab=readme-ov-file#the-genui-macro

Basically the genui macro here is run, and creates a frame and a panel with a sizer. The frame is assigned to the variable mainFrame and the panel is assigned to the variable panel (this is what the % symbol does.

Then outside the genui macro we use the panel variable that was just created for us to run normal wxWidget code on the panel, in this case we get the sizer and add some empty spacers to it. Then we call the addElements macro which is essentially the exact same thing as the genui macro, but it adds elements as the child of an existing element, just as if it was indented under it in the original genui call.

harrier77 commented 4 months ago

Thank you very much. I started to read the explanation in Readme and now I can understand almost everything. If I need some other hint I will contact you. But it seems that the Readme is enough for what I have intention to do.

PMunch commented 4 months ago

Great to hear, if you make it open source I'd be very interested to see what you make with this!

harrier77 commented 4 months ago

Probably you overrate my skills. The app I coded at now is a small panel with three buttons. I need it to launch chrome to browse a local httpd in nim which serves html pages dynamicaly generated with the list of directories full of documents. My next step is to replace chrome with a WebView in a window coded in wxnim.

But you may be interested to know that the panel with three buttons in wxnim needs 36 rows of code, in cpp 138. Your macros are very powerful.

harrier77 commented 4 months ago

Here I am again. I tried very hard to got webview functioning, as an exercise to improve my understanding of the whole nim and c. In short: