How to update GUI buttons outside the mainloop ?

Blitz3D Forums/Blitz3D Beginners Area/How to update GUI buttons outside the mainloop ?

RemiD(Posted 2012) [#1]
Hi, :)

I have coded a simple GUI in order to run functions in my level editor.

Until now there were only several buttons displayed depending on the mode i selected, and i was able to run a function each time i clicked on a button.

All the buttons were drawn after renderworld. This worked well because these functions did not require a user input inside a function.

But for some functions, i now need a user input inside a function.
For example, when i click on the button Level Create :
->The program asks the user for the name of the .lvl file he wants to load. (With the Message button)
->The program updates the text field depending on what keys the user types on. (With the TextField button)
->The program checks if a .lvl file with the typed name already exists.
->If yes
-->The program asks the users if he wants to overwrite the existing .lvl file. (With the Message button and the Yes button and the No button)
-->The program checks the user input
-->If yes
--->The program writes the .lvl file.
--->The program displays a message of success. (With the Message button and the Ok button)
-->If no
--->The program does not write the .lvl file.
--->The program displays a message of failure. (With the Message button and the Ok button)
->If no
-->The program writes the .lvl file.
-->The program displays a message of success. (With the Message button and the Ok button)

The problem is that i need to update the Message button, the TextField button, the Yes button, the No button, the Ok button, inside the LevelCreate() function, else they won't be displayed on the screen.

Here is an example of the structure of my code :
;Mainloop
Repeat 
 Cls()
 MouseInput()
 KeyboardInput()
 CameraModeSelect()
 CursorUpdate()
 ButtonsUpdate() 
 CameraUpdate()
 RenderWorld()
 ButtonsDraw()
 CursorDraw()
 Flip(True)
Until(ProgramState% = Quit%)
End

Function MouseInput()
 ;Gets the mouse input
End Function

Function KeyboardInput()
 ;Gets the keyboard input
End Function

Function CameraModeSelect()
 ;Selects the CameraMode (FirstPersonView, EditView)
End Function

Function CursorUpdate()
 ;Checks where is the cursor and if a button has been clicked or not.
End Function

Function ButtonsUpdate()
 ;If the Button clicked is the Button BLevelCreate
  ;LevelCreate()
 ;EndIf
End Function

Function CameraUpdate()
 ;Updates the camera depending on the CameraMode
End Function

Function ButtonsDraw()
 ;Draws the buttons which have to be shown 
End Function

Function CursorDraw()
 ;Draws the cursor image
End Function

Function LevelCreate()
  ;Asks the user the name of the level he wants To create.
  InputText$ = ""
  InputTextState% = Analyze%  
  ButtonText$(1) = "Please type the name of the level and press enter." 
  ButtonText$(2) = ""
  InputTextAsk()      
  ;Checks if a .lvl file with this name already exists.
  ;the others tests continue here
End Function
  
Function InputTextAsk()
 Repeat
  Cls()
  InputTextUpdate()
  ButtonsUpdate()
  RenderWorld()
  ButtonsDraw()
  Flip(True)
 Until(InputTextState% = Validate%)
End Function

Function InputTextUpdate()
 If(InputTextState% = Analyze%)    	
  CharIdentifier()
  If(KeyName$ = "SPACE")
   InputText$ = InputText$+" "
  ElseIf(KeyName$ = "DELETEPREVIOUS")
   InputTextLength% = Len(InputText$)
   If(InputTextLength% > 0)
    InputText$ = Left(InputText$,Len(InputText$)-1)
   EndIf
  ElseIf(KeyName$ = "VALIDATE")
   InputTextLength% = Len(InputText$)
   If(InputTextLength% >= 1)
    InputTextState% = Validate%
   EndIf
  Else
   InputText$ = InputText$+KeyName$
  EndIf    
  ButtonText$(2) = InputText$  
 EndIf
End Function

Function CharIdentifier()
 ;Checks what character is typed
End Function


You can see the other loop and the use of Renderworld() and Flip() inside the function InputTextAsk() and i do the same thing to update the others buttons that require the user input.

This works as expected but i guess this is not the best way to do this because if i want to use others buttons to get the user input inside others functions i will have many similar loops.

So before coding it all this way, i wonder if you know another approach in order to achieve this result ?
If yes, can you please explain the concept ?

Thanks,

Last edited 2012


Guy Fawkes(Posted 2012) [#2]
u COULD try putting them in a Repeat Until loop, and just updating them that way? That's the only logical way I know of, at least :)


RemiD(Posted 2012) [#3]
I have solved this problem by using 2 modes for the input, one for the controls of the player and one for the menu, and also by using several states for each functions.


Guy Fawkes(Posted 2012) [#4]
Good Job :)


Kryzon(Posted 2012) [#5]
So before coding it all this way, i wonder if you know another approach in order to achieve this result ?
If yes, can you please explain the concept ?

Try making each gadget individually updatable, and implement gadget focus. You can do this with Types.

The most important thing is you should never update the GUI through any other loop than your main one. If you leave your main loop, consider it as the condition to terminate the app.
You can still do things like lock the mouse when inputting text, even when updating only through the main loop - you just need to design the logic correctly.
Every logic pass you update all GUI elements and check for events. Inside your main loop you will process these events in whatever way you want.

You should download BlitzUI and take a look at the source, it's awesome:
http://www.melog.ch/dl/blitzui_130.zip (kindly hosted by jfk EO-11110)


Guy Fawkes(Posted 2012) [#6]
<3 Thank You, Kryzon! This is AWESOME! :D


RemiD(Posted 2012) [#7]
I don't use an "events" system for my GUI but this is an interesting example. Thanks Kryzon.