OnUpdate, OnRender and nesting loop

Monkey Forums/Monkey Programming/OnUpdate, OnRender and nesting loop

ziggy(Posted 2013) [#1]
I need a way to be able to call the app OnRender from the OnUpdate.
Let me explain:
In the GUI engine I'm writing with Monkey, I want to add a MsBox (notify) window system, and that would require that, when the code has a Notify("Whatever"), the engine can enter a sort of nested update/render loop while the modal window is shown. Any ideas?

Pseudocode:
...
Method DoSomethingImportant()
   If license.Expired Then
      'That would require the App to process a secondary event loop:
      Notify("Your license is expired.") 
      Return
   End
End


I don't know if the problem is understandable but when a modal form has to be shown, we need the GUI system to be able to render it, show it on screen process the user input, detect when the window has been closed, and continue execution where it was. As far as I know, there's no way to call a "ProcessEvents" or the like into the Mojo App, isn't it?


Rushino(Posted 2013) [#2]
To me that would be better that Notify set some kind of a flag that you can handle in update/render main loop. Why it couldnt be like this ?

Notify:

Method Notify(msg:String)
..Create window..
..Add window to notify list..
End

OnRender:

..See if there any notification in the list and if yes call the Render() of it..

OnUpdate:

..Same..


ziggy(Posted 2013) [#3]
Why it couldnt be like this ?

because you can't get the result of the dialog on the program flow. Another example: (Ask is a function that shows a Yes/No modal dialog

Method ClosingForm()
   If Ask("Do you want to save changes?") = DialogResult.Yes Then
      SaveChanges()
   End
   self.Close()
End

If "Ask" only sets a flag or does anything how can you wait for the result while the function does process its render and update, so user can see the dialog and click/select the desired option?


Midimaster(Posted 2013) [#4]
It is never a good idea to combine waiting on events/updating an rendering.

A GUI is diveded in two parts: the logical part which "knows", what is visible or "on top" or "behind the fingers" and receives user inputs...

...and a graphic part, which knows, which elements are visible and paints the state of the GUI.

So the lifetime of a notify-Box is:

-mainloop

-create and open it and set all properties like "text", "wating", "Visible", etc... in OnUpdate()

-back to main loop

-waiting for a user reaction in OnUpdate()
-paint the box in OnRender()

-back to main loop

-recognizing the user, set the box "visible" and "waiting" to FALSE and react on the users decision in OnUpdate()

-back to main loop

Strict
Import mojo

Class Game Extends App

	Field Notify%

	Method OnCreate%()
		SetUpdateRate 5
		Return 0
	End	

	Method OnUpdate%()
		If KeyHit(KEY_ESCAPE) Then Error ""
		If TouchHit()
			If Notify=0
				' mouse action starts notify box:
				Notify=-1
			Else
				' mouse action goes to notify buttons:
				If TouchX()<320
					Notify=1
				Else
					Notify=2
				Endif
			Endif
		Endif

		' proceed notify results:
		If Notify>0 
			If Notify=1
				Print "YES"
			Else
				Print "NO"
			Endif
			Notify=0
		Endif
		Return 0
	End	

	Method OnRender%()
		Cls 0,255,0
		' paint regular screen
			SetColor 255,255,255
			DrawText "PRESS MOUSE",150,250
		If Notify=-1
			' paint notfy box over the screen:
			SetColor 111,0,111
			DrawRect 50,200,200,100
			DrawRect 350,200,200,100
			SetColor 255,255,255
			DrawText "YES",150,250
			DrawText "NO",450,250			
		Endif
		' main loop is still running:
		Print "Render" +Millisecs()
		Return 0
	End	

End

Function Main%()
	New Game
	Return 0
End



ziggy(Posted 2013) [#5]
It is never a good idea to combine waiting on events/updating an rendering.
I could not disagree more on that.
It may be usually a bad- idea, but the good option is always the most balanced one. Having to rely on flags, callbaks, events or interfaces just to be able to show a notify window is going by too far. In this particular scenario for easy and small dialogs, it's not worth it.

All notify dialogs are designed to do exactly this. A folder selection dialog, and any modal one.

If it's not done like this, you're forced to over complicate program flow. Do you know of any GUI system where you can't launch a SelectFolder function, or AskYesNo function, etc that have the form of a GUI dialog on screen, in a way that program flow can wait for the response to act accordingly?

If you think on program flow diagrams, you know that rhombus with a yes/no that is the result of user interaction, in this case, as the result of a dialog. That's something even the more basic and simple GUI system provides. Monkey current lag of nested event-poll processing disallows this.

We had Notify, SelectFolder and the like functions on BlitzMax, and it happens to be impossible to do the same with a mojo-based GUI system. That's my request.

I know how to code a work-around, but if it can't be encapsulated on a function, it's quite unusable.

Should I have to build a status diagram, set flags, etc, just to ask for a folder selection, open file, etc? That's a very disgusting limitation of current schema, and forces a over-engineering of very simple and common tasks, to the point that they become sort of unusable. It could be solved by a simple "doevents" function that can be used internaly on modal windows processing. That's what I'm requesting. Most of event-driven system like Mojo does provide this for exactly the same reason (also to allow rendering updating while processing complex loops to avoid the program to be shown as irresponsive, but that's another problem...)

Edit: the only reason I see to not having this "ProcessEvents" or "pullEvents" or "DoEvents" function on Mojo is the current implementation of the c++ garbage collector (again). As it requires those event to be processed outside any Mojo function or method.


Difference(Posted 2013) [#6]
That's a very disgusting limitation of current schema, and forces a over-engineering of very simple and common tasks, to the point that they become sort of unusable.


Consider your blood pressure - it's friday after all , and there are after all, more than one way to skin a cat.

I completely agree with MidiMaster, I have total separation of rendering, timing and input, in my own framework, and have found no limitations. What you call workarounds, I call design.

PS: I always found the need for "DoEvents" a pain.

totally asynchronous greetings, Diff.


Midimaster(Posted 2013) [#7]
Oh yes, now I understand... You would need something like a program counter, which can be put on a stack to find back to the same code line later....

Reaching a "Notify"-command the program flow jumps into a MY_GUI function, which stores the PG, sets a flag, and continue to leave the OnUpdate(). Later on closing the Notify-Gadget the MY_GUI remembers the PG and can continue the game...


ziggy(Posted 2013) [#8]
Other than telling me how I should do it asyncronously, which is something I aready know how to do, and other than telling me what should I like or dislike. Is there any other reason for not providing a way to make syncronious operations if I want? Other than not having a more versatile garbage collector?
If I have to add a callback or the like anytime I want a dialog to perform a modal action, this is so contrary to any of the GUI designed systems that I've been using such as WinForms, GTK#...
winForms:
DoEvents

GTK:
while (GLib.MainContext.Iteration ())

wxWidgets:
wxYield and FlushActive

and so on...

Mojo... ?? no way AFAIK

As Monkey allows recursion... why not allow us to use it if we want to do it carefully?


Gerry Quinn(Posted 2013) [#9]
[Deleted, thought I had a solution but it does not really deliver what the OP wants]


ziggy(Posted 2013) [#10]
You would need something like a program counter, which can be put on a stack to find back to the same code line later
Yes, that's called a call stack :D I want to be able to use it also to commit render/udpate operations if I want to.
In the case of writing a GUI that can provide modal dialogs for simple tasks, it is really woth it. I mean dialogs like a simple log-in form, a folder selector, a notify window, a simple yes/no question dialog, etc. Having to rely on async checks/callbacks etc for this ultra simple tasks that could be provided to the GUI users as a simple function, is very counter productive.
I know this is a very specific need. But happens to be the one I'm facing right now.


marksibly(Posted 2013) [#11]
This is just the way some 'modern' OSs/Guis work - ie: your app cannot 'halt' progress, or you break the whole system.

If this were not the case, I wouldn't have bothered with all the OnUpdate/OnRender nonsense, and you guys would have been able to use...

Repeat
   ...do cool stuff...
   Flip
Forever


...instead. If only...

The same goes for native coding - eg: in Android, you don't just call 'MessageBox' and it blocks until 'OK' is clicked. Instead, the function returns immediately and will *eventually* call a 'close clicked' handler or something.

Perhaps something tricky could be done with threads on some targets, but I'm not going there for a while yet (if ever) so for now you're stuck with having to 'fake' synchronous ops in a 'continuously running' environment.


ziggy(Posted 2013) [#12]
Ok. Thanks for the info. I'll redesign my original approach.


Fred(Posted 2013) [#13]
I believe everybody's right here. To make it safe and clean or if you want to be cross platform you don't have the choice.
But when you are prototyping, making some quick and dirty runs, it a pain to have to implement a gui system for an input(even with an already made module) it could lead to more code just to implement it than the one you need to test.
In that case, in html5 only, you can do that with javascript.

#if TARGET = "html5"
Import "webfuncs.js"
Extern
function 	WebAlert:void( message:String ) = "WebAlert"
function 	WebConfirm:Int( message:String ) = "WebConfirm"
function 	WebPrompt:String( message:String, textfield:String ) = "WebPrompt"
Public
#endif

webfuncs.js

function WebAlert( message )
{
	alert( message ) ;
}

function WebConfirm( message )
{
	return confirm( message ) ;
}

function WebPrompt( message, textfield )
{
	var		dispmess = message ;
	do
	{
		str = prompt( dispmess, textfield ) ;
		if( !str )
		{
			return "_cancel" ;				
		}	
		dispmess = message + "\r20 characters only !" ;
	} 
	while( str.length > 20 ) ;
	return str ;
}


Then you can use in your code:
local input:String = WebPrompt( "Enter a name", "default name" )

it halts the code without any issue.