Open psparago opened 2 years ago
Hmmm... your problem made me think that we probably introduced some bug with the size of View
when we rewrote that functionality. But I tried the original jroimarting/gocui
implementation and it has the same problem.
So just to explain why it doesn't show anything, it's because the size of the View
is too small. Even without Frame
, it just sees it as empty, because the x0
, y0
and x1
, y1
are corners of the frame even if the frame is not there.
If you increase the y1
to 3
, it would increase the size of the View
to 1
(top border is on position 1 and bottom border on position 3, making position 2 available to write and giving the size of the inner view as 1 line):
w.status, err = g.SetView("status", 2, 1, maxX-2, 3, 0) // changed the 2, 0) into 3, 0)
I tried it on hello.go
example, where you can just lower the y1
parameter by 1
and it wouldn't display anything (not even in the original implementation).
Let us know if that helps. I'm not sure if the View size which you have there ever worked. So I hope by increasing it you will resolve your problem and won't introduce any new one :)
Thank you very much for the speedy response. I truly appreciate it.
Unfortunately I get the same behavior after make the change suggested. I've even expanded the y1 to 5 and draw a frame around the view and it is still empty.
I'm wondering if I'm handling the actual write to the status view properly. In the hello.go example, the write is done in layout. That wouldn't be the case in my implementation. I am using the gui update event to update the view. I did set breakpoints and I see the event being consumed but still no output in the status view.
Do you have any ideas as to why my code isn't producing the output even with the expanded vertical size?
I've uploaded an updated copy of my test application.
Thank you again.
Oh I see now. I didn't download the app before as I just saw the View size in your comment and assumed that's the reason.
Now I downloaded and checked your code and the reason why it's not working for you is that you delete the status
view every call of (*Window)Layout(*gocui.Gui)
function in widgets/window.go:188
.
_ = g.DeleteView("status") // <======= This line is the problem!
w.status, err = g.SetView("status", 2, 0, maxX-2, 3, 0)
if err != nil {
if err != gocui.ErrUnknownView {
return err
}
w.status.Frame = true
w.status.Editable = false
}
To make it more clear on how gocui
works:
gocui.Update
, keybing, etc.) or system event (change of terminal size, etc.)Layout
functions and call them and then after the buffer representing the screen is created, it will display it in terminalFrom this you can see, that when your button press update the status
it happens in the 2nd step. However, the window Layout
function is called in the 3rd step and the status
view which currently has the message in it would be deleted and recreated again without any content.
There is two ways you can do here, either not delete the view if it exist and keep it around. Or have a status message string
field in the Window
instead and in the window Layout
just create the status view and populate it with that message if necessary.
Maybe one more thing about it. The gocui.ErrUnknownView
is probably the design decision here, where you can always run SetView
and just check and decide accordingly what should be done.
err == gocui.ErrUnknownView
- newly created View
, you can populate it with the "default" contenterr == nil
- this is existing view and was updated with new dimension (or the same dimension), it may contain some content alreadyerr != nil
- something is wrong, maybe incorrectly specified dimension or name Thank you SO much, especially for taking the time to explain how this works. I removed the delete of the view in the test app and I now have output! I will run through the logic and decide what best works in the actual application.
I should note that the author did modify (and Expose) flush() in his hacked version. I must have missed a nuance that made his version work.
Once again I truly appreciate the time you took to not only solve my issue, but more importantly (to me) to explain how it works so I can make a proper design decision.
Thank you!!!
Hello again, I really hesitant to bother you again and I realize you're not my personal consultant :-), but, while I have statuses mostly working now, I've run into a roadblock I spent today trying to work around.
Essentially, status view output is not shown while the code invoked by the widgets we're using is processing. That is to say, if the action of the keypress attempts to display a status message, the view is not drawn until the action completes.
The user event is queued immediately but it looks to me that the reason the status view is not drawn is the event loop is executing the keypress synchronously thus the event loop is blocked waiting for the code invoked by a keypress to complete before processing user events (as documented). Once the action is complete the status message does, is fact, drawn.
I think my understanding of why this is happening is accurate and I understand the reasoning for this, but Is there any way in the framework to get around this behavior? (It doesn't appear so)
However, to get around this behavior, I tried creating an independent gocui instance with its own MainLoop dedicated to the status view, but, any attempt to invoke actions just hangs the UI. Would something like this even work?
I have uploaded a version of my test application (that does not have the attempt at a second gocui instance) that demonstrate that the status message is not displayed while the action invoked by the widget keypress is running.
Once again, I do not want to take advantage of your kind nature. However, if you can direct me to a solution or advise that this is simply not possible in our current design, it would be much appreciated.
No problem at all, just happend to be around so happy to help ;)
This is quite straight forward in gocui
, as you observed the user functions (executed by gui.Update()
) are executed sequentially in main gocui
loop described above (step 2). That's the reason it's hanging.
You shouldn't really have a logic in those functions, and rather use them only to update the UI.
Your logic should go into separate go routine. You can start the go routine before executing MainLoop
or you can start it from any gui.Update
or keybind function, but it should be started as a go routine and not called as a regular function.
When you have the output, you just issue gui.Update
where you populate View
you want with data you've got. You can do it directly in that go routine or send the data back thru channel into some separate go routine which handles UI updates. That depends on you.
I would suggest to look into goroutine example which has some basic code for this kind of situation:
https://github.com/awesome-gocui/gocui/blob/master/_examples/goroutine.go
If this is not the proper place for this question, my apologies (and sorry for the length of this post).
I am working on a shell UI that is legacy code (that I didn't author). It has been working for many years, but It was based on a hacked version of jroimartin/gocui and a hacked version of a widget package the author found (4 years ago, he just disappeared).
We recently moved all of our Go code to 1.18 (from 1.11) and, with that, we revised all our packages including moving our terminal GUI utility from the hacked jroimartin/gocui code to the latest release V1.1.0 of awesome-gocui (Thanks folks!).
The terminal UI app is a utility that has a main menu "page" that transfers to several "pages" of "forms". All of these "pages" are comprised of widgets from the still hacked widgets package (they seem to work OK).
Every "page" has a status view (not a widget) at the top of the page. For some reason, the status view no longer shows any text.
Relevant code:
"Pages" are represented by an unfortunately named "Window" struct. In the Layout function on the Window struct, two VIews are created: a View to hold the "form" widgets (gathered as children), and a View to show status messages:
The status text is set using the
SetStatus
function on the "Window" struct :Here's an example use from a test page I created:
Note the call to SetStatus in the example code.
If you look closely at the SetStatus function you see that I am printing the View buffer to the screen after writing the status text to the buffer. The text "Say Something!!!" does indeed get printed to the screen when the Test "button" is pressed.
Any guidance would be greatly appreciated. Thank you. gocui-test.tar.gz