Author Topic: Immediate Mode GUI  (Read 18372 times)

Offline Albert

  • Dr. Type
  • ****
  • Posts: 257
    • View Profile
    • Blog
Immediate Mode GUI
« on: 2010-Dec-14 »
Update: For the updated IMGUI system jump to: http://www.glbasic.com/forum/index.php?topic=5431.msg69686#msg69686

I followed Sol's tutorial about Immediate Mode GUI http://sol.gfxile.net/imgui/ and expanded it a bit (only the top widget will be highlighted; added a dragable Window widget)

Quote
The magic here is that the call to button will perform everything the widget would be expected to do at any single time, including the rendering of the visible widget. There's a bit of global data that's shared by all of the widgets that enables them to work.

There's no setup phase, but if a widget needs some data to show it's state (say, a scroll bar, text edit field, etc), the state data is owned by the host application and not the widget. This is surprisingly handy and performance-friendly, as there's no querying and message-sending involved.

There's also no cleanup required, except for the data that you have allocated yourself. The widgets only exist when they're called, so you'll need to ask for them each frame you want to use them.

Nothing is ever simply positive, and IMGUI does have its problems. The most obvious one is that it's just about as anti-OOP as you can get, so it may feel wrong for you. Other problems are related to the fact that the widgets don't really exist except when they are queried, and as such things like automatic layouts or keyboard focus get somewhat more difficult.



Here is the code:
Code: GLBasic [Select]
// --------------------------------- //
// Project: imgui
// Start: Thursday, December 09, 2010
// IDE Version: 8.174

// Made by Bence Dobos. Based on this great tutorial http://sol.gfxile.net/imgui/
// Widget IDs must be unique!

SETCURRENTDIR("Media") // seperate media and binaries?
SYSTEMPOINTER TRUE
LOADFONT "smalfont.png", 0

//GUI object
GLOBAL gui AS UIState

//variables (what the widgets will be using and changing)
GLOBAL backgroundcolor = RGB(100,100,255)
GLOBAL text$ = "teszt"
GLOBAL showwin=FALSE
GLOBAL winX=300
GLOBAL winY=50
GLOBAL win2X=70
GLOBAL win2Y=250
GLOBAL menustr1$[]
DIMDATA menustr1$[], "File", "Open", "Save", "Save As", "---", "New project", "Open project", "Close project", "---", "Exit"
GLOBAL showmenu1=FALSE
GLOBAL menustr2$[]
DIMDATA menustr2$[], "View", "Output", "Status", "---", "Skins", "Colors", "Look and feel",  "---", "Whitespace", "Wordwrap"
GLOBAL showmenu2=FALSE
GLOBAL toastmsg$="Welcome"
GLOBAL toasttimer=50

//start endless loop
WHILE TRUE
        CLEARSCREEN backgroundcolor
        //prepare the gui
        gui.prepare()

        ALPHAMODE 0
        PRINT "(SHIFT+)TAB to switch widget, ENTER, UP, DOWN to use widget",5,25,TRUE
        //ALPHAMODE -0.5

        //buttons (doing nothing)
        IF button(1,10,50,60,25,RGB(100,0,200),"Button") THEN settoast("button", 50)
        IF button(2,120,50,100,25,RGB(100,0,200),"Button long") THEN settoast("button long", 100)

        //button (change background color)
        IF button(3,10,100,60,25,RGB(255,0,200),"Color") THEN backgroundcolor = RND(0xffffff)

        //button (show/hide window)
        IF button(4,120,100,150,25,RGB(100,0,200),"Show/hide Window") THEN showwin = NOT showwin

        //button (show popupmenu)
        IF button(5,10,0,40,25,RGB(200,200,200),"File") THEN showmenu1=TRUE
        //button (show popupmenu)
        IF button(6,50,0,50,25,RGB(200,200,200),"View") THEN showmenu2=TRUE
               
        //slider (change background color)
        sliderV(7, 550, 20, 430, 0xffffff, backgroundcolor)
        textfield(7, 10,200, 20, text$)
        sliderH(8, 50, 410, 430, 0xffffff, backgroundcolor)    

        //window (about window, transparent)
        ALPHAMODE -0.7
        window( 20, win2X, win2Y, 200, 150, RGB(100,200,70), "About")
        ALPHAMODE 0
        PRINT "Immediate Mode GUI",             win2X+5,        win2Y+20, TRUE
        PRINT "Written by Bence Dobos",         win2X+5,        win2Y+50, TRUE
        PRINT "Based on Jari Komppa's",         win2X+5,        win2Y+80, TRUE
        PRINT "great tutorial at",                      win2X+5,        win2Y+100, TRUE
        PRINT "sol.gfxile.net/imgui/",          win2X+5,        win2Y+120, TRUE

        //window (showing gui variables)
        IF showwin
                window( 10, winX, winY, 200, 300, RGB(200,200,200), "GUI states")
                PRINT "tab: " + gui.tab         ,winX+5,         winY+20, TRUE
                PRINT "shift: " + gui.shift     ,winX+100,       winY+20, TRUE
                PRINT "ctrl: " + gui.ctrl       ,winX+5,         winY+40, TRUE
                PRINT "alt: " + gui.alt         ,winX+100,       winY+40, TRUE
                PRINT "up: " + gui.up           ,winX+5,         winY+60, TRUE
                PRINT "down: " + gui.down       ,winX+100,       winY+60, TRUE
                PRINT "left: " + gui.left       ,winX+5,         winY+80, TRUE
                PRINT "right: " + gui.right     ,winX+100,       winY+80, TRUE
                PRINT "mousex:" + gui.mousex    ,winX+5,         winY+100, TRUE
                PRINT "mousex:" + gui.mousey    ,winX+100,       winY+100, TRUE
                PRINT "lclick: " + gui.mouselclick      ,winX+5,         winY+120, TRUE
                PRINT "rclick: " + gui.mouserclick      ,winX+100,       winY+120, TRUE
                PRINT "mclick: " + gui.mousemclick      ,winX+5,         winY+140, TRUE
                PRINT "scroll: " + gui.mousescroll      ,winX+100,       winY+140, TRUE
                PRINT "prehot: " + gui.prehotitem       ,winX+5,         winY+160, TRUE
                PRINT "hotitem: " + gui.hotitem         ,winX+100,       winY+160, TRUE
                PRINT "active: " + gui.activeitem       ,winX+5,         winY+180, TRUE
                PRINT "kbditem: " + gui.kbditem         ,winX+100,       winY+180, TRUE
                PRINT "key$: " + gui.keyentered$        ,winX+5,         winY+200, TRUE
                PRINT "keychar: " + gui.keychar         ,winX+100,       winY+200, TRUE
                PRINT "lastwidget: " + gui.lastwidget   ,winX+5,         winY+220, TRUE
                //a red close button bottom of the window
                IF button(11,winX+5,winY+270,190,25,RGB(255,100,100),"Close this window") THEN showwin = NOT showwin
                //a red close button top-right of the window
                IF button(12,winX+200-16,winY,16,16,RGB(255,100,100),"X") THEN showwin = NOT showwin
        ENDIF

        IF showmenu1
                LOCAL item = popupmenu(30, 10, 0, RGB(200,200,200), menustr1$[])
                IF item = -1 THEN showmenu1=FALSE
                IF item>0
                        settoast(menustr1$[item] + " MeniItem selected", 50)
                        showmenu1=FALSE
                ENDIF
        ENDIF
        IF showmenu2
                LOCAL item = popupmenu(30, 50, 0, RGB(200,200,200), menustr2$[])
                IF item = -1 THEN showmenu2=FALSE
                IF item>0
                        settoast(menustr2$[item] + " MeniItem selected", 50)
                        showmenu2=FALSE
                ENDIF
        ENDIF  
        IF toasttimer>0
                toast(99, 320-LEN(toastmsg$, TRUE)/2, 440, RGB(60, 60, 60), toastmsg$, toasttimer)
                DEC toasttimer
        ENDIF
       
        //finish the gui
        gui.finish()
        SHOWSCREEN
WEND

FUNCTION settoast:text$, timer
        toastmsg$=text$
        toasttimer=timer
ENDFUNCTION

// --------------------------------- //
// Immediate Mode GUI code start here
// Widget IDs must be unique!

FUNCTION getkey: k, BYREF dst
        IF KEY(k)
                IF dst<>-1
                        dst = 1
                ENDIF
        ELSE
                dst = 0
        ENDIF
ENDFUNCTION

TYPE UIState
        //mouse
        mousex
        mousey
        mouselclick
        mouserclick
        mousemclick
        mousescroll

        //keyboard
        kbditem
        keyentered$
        keychar
        tab
        shift
        ctrl
        alt
        up
        down
        left
        right

        //widget
        prehotitem
        hotitem
        activeitem
        lastwidget

        //checking if mouse position is in specified region
        FUNCTION inregion: x, y, w, h
                IF (self.mousex<x OR self.mousey<y OR self.mousex>=x+w OR self.mousey>=y+h) THEN RETURN FALSE
                RETURN TRUE
        ENDFUNCTION

        //prepare the IMGUI. Must call at the start of your gameloop
        FUNCTION prepare:
                //widget
                self.hotitem = self.prehotitem
                self.prehotitem = 0
                //mouse
                MOUSESTATE self.mousex, self.mousey, self.mouselclick, self.mouserclick
                self.mousemclick = MOUSEAXIS(5)
                self.mousescroll = MOUSEAXIS(2)
                //keyboard
                self.keyentered$ = INKEY$()
                self.keychar = ASC(self.keyentered$)
                getkey(15, self.tab)
                getkey(42, self.shift)
                getkey(29, self.ctrl)
                getkey(56, self.alt)
                getkey(200, self.up)
                getkey(205, self.right)
                getkey(208, self.down)
                getkey(203, self.left)
                //PRINT "key "+self.keyentered$+" "+ASC(self.keyentered$),360,5,TRUE
        ENDFUNCTION

        //finish the IMGUI. Must call at the end of your gameloop
        FUNCTION finish:
                //mouse
                IF self.mouselclick = FALSE
                        self.activeitem = 0
                ELSE
                        IF self.activeitem = 0 THEN self.activeitem = -1
                ENDIF
                //keyboard
                IF gui.tab = 1
                        self.kbditem = 0
                ENDIF
                self.keyentered$ = ""
                self.keychar = 0
        ENDFUNCTION
ENDTYPE //TYPE IMGUI

//Button widget (clickable)
FUNCTION button: id, x, y, width, height, color, text$
        LOCAL fw, fh
        GETFONTSIZE fw, fh

        IF gui.hotitem = id
                IF (gui.activeitem = 0 AND gui.mouselclick)
                        gui.activeitem = id
                ENDIF
        ENDIF
        IF gui.inregion(x,y,width,height)
                gui.prehotitem = id
        ENDIF
        IF gui.kbditem = 0
                gui.kbditem = id
        ENDIF

        IF gui.kbditem = id
                DRAWRECT x-1, y-1, width+4, height+4, RGB(255, 0, 0)
        ENDIF

        DRAWRECT x+1, y+1, width, height, RGB(0, 0, 0)
        IF gui.hotitem = id
                IF gui.activeitem = id
                        DRAWRECT x+2, y+2, width, height, RGB(255, 255, 255)
                ELSE
                        DRAWRECT x, y, width, height, RGB(255, 255, 255)
                ENDIF
        ELSE
                DRAWRECT x, y, width, height, color
        ENDIF

        PRINT text$, x+5, y+(height-fh)/2, TRUE

        //KBDITEM stb...
        IF gui.kbditem = id
                IF gui.tab = 1
                        gui.kbditem = 0
                        IF gui.shift THEN gui.kbditem = gui.lastwidget
                        gui.tab = -1
                ENDIF
                IF gui.keyentered$="\n" //ENTER
                        RETURN 1
                ENDIF
        ENDIF

        gui.lastwidget = id

        IF gui.mouselclick = 0 AND gui.hotitem = id AND gui.activeitem = id THEN RETURN 1

        RETURN 0
ENDFUNCTION

//slider widget (vertical)
FUNCTION sliderV: id, x, y, height, maximum, BYREF value
        STATIC marginH = 4
        STATIC marginW = 4
        LOCAL ypos = ((height-16) * value) / maximum

        IF gui.hotitem = id
                IF (gui.activeitem = 0 AND gui.mouselclick)
                        gui.activeitem = id
                ENDIF
        ENDIF
        IF (gui.inregion(x+marginW,y+marginH, 16, height))
                gui.prehotitem = id
        ENDIF
        IF gui.kbditem = 0
                gui.kbditem = id
        ENDIF

        IF gui.kbditem = id
                DRAWRECT x-1, y-1, 16+2, height+marginH*2+2, RGB(255, 0, 0)
        ENDIF

        DRAWRECT x, y, 16, height + marginH*2, RGB(50, 50, 50)

        IF (gui.activeitem = id OR gui.hotitem = id)
                DRAWRECT x+marginW, y+marginH + ypos, 16-marginW*2, 16, RGB(255,255,255)
        ELSE
                DRAWRECT x+marginW, y+marginH + ypos, 16-marginW*2, 16, RGB(200,200,200)
        ENDIF

        IF gui.kbditem = id
                IF gui.tab = 1
                        gui.kbditem = 0
                        IF gui.shift THEN gui.kbditem = gui.lastwidget
                        gui.tab = -1
                ENDIF
                IF gui.up = 1
                        IF (value>0)
                                DEC value
                                RETURN 1
                        ENDIF
                ENDIF
                IF gui.down = 1
                        IF (value<maximum)
                                INC value
                                RETURN 1
                        ENDIF
                ENDIF
        ENDIF

        gui.lastwidget = id

        IF gui.activeitem = id
                LOCAL mousepos = gui.mousey - (y+marginH)
                IF (mousepos < 0) THEN mousepos = 0
                IF (mousepos > height) THEN mousepos = height
                LOCAL v = (mousepos*maximum) / height
                IF (v <> value)
                        value = v
                        RETURN 1
                ENDIF
        ENDIF

        RETURN 0
ENDFUNCTION

//slider widget (vertical)
FUNCTION sliderH: id, x, y, width, maximum, BYREF value
        STATIC marginH = 4
        STATIC marginW = 4
        LOCAL xpos = ((width-16) * value) / maximum

        IF gui.hotitem = id
                IF (gui.activeitem = 0 AND gui.mouselclick)
                        gui.activeitem = id
                ENDIF
        ENDIF
        IF (gui.inregion(x+marginH,y+marginW, width, 16))
                gui.prehotitem = id
        ENDIF
        IF gui.kbditem = 0
                gui.kbditem = id
        ENDIF

        IF gui.kbditem = id
                DRAWRECT x-1, y-1, width+marginH*2+2, 16+2, RGB(255, 0, 0)
        ENDIF

        DRAWRECT x, y, width + marginH*2, 16, RGB(50, 50, 50)

        IF (gui.activeitem = id OR gui.hotitem = id)
                DRAWRECT x+marginW + xpos, y+marginH, 16, 16-marginW*2, RGB(255,255,255)
        ELSE
                DRAWRECT x+marginW + xpos, y+marginH, 16, 16-marginW*2, RGB(200,200,200)
        ENDIF

        IF gui.kbditem = id
                IF gui.tab = 1
                        gui.kbditem = 0
                        IF gui.shift THEN gui.kbditem = gui.lastwidget
                        gui.tab = -1
                ENDIF
                IF gui.left = 1
                        IF (value>0)
                                DEC value
                                RETURN 1
                        ENDIF
                ENDIF
                IF gui.right = 1
                        IF (value<maximum)
                                INC value
                                RETURN 1
                        ENDIF
                ENDIF
        ENDIF

        gui.lastwidget = id

        IF gui.activeitem = id
                LOCAL mousepos = gui.mousex - (x+marginH)
                IF (mousepos < 0) THEN mousepos = 0
                IF (mousepos > width) THEN mousepos = width
                LOCAL v = (mousepos*maximum) / width
                IF (v <> value)
                        value = v
                        RETURN 1
                ENDIF
        ENDIF

        RETURN 0
ENDFUNCTION


//textfield widget (could type text in it)
FUNCTION textfield: id, x, y, width, BYREF buffer$

        LOCAL length = LEN(buffer$)
        LOCAL changed = 0
        LOCAL fw, fh
        GETFONTSIZE fw, fh

        IF gui.hotitem = id
                IF (gui.activeitem = 0 AND gui.mouselclick)
                        gui.activeitem = id
                ENDIF
        ENDIF
        IF (gui.inregion(x-4,y-4, width*fw+8, fh+8))
                gui.prehotitem = id
        ENDIF
        IF gui.kbditem = 0
                gui.kbditem = id
        ENDIF

        IF gui.kbditem = id
                DRAWRECT x-6, y-6, width*fw+12, fh+12, RGB(255,0,0)
        ENDIF

        IF (gui.activeitem = id OR gui.hotitem = id)
                DRAWRECT x-4, y-4, width*fw+8, fh+8, RGB(200,200,200)
        ELSE
                DRAWRECT x-4, y-4, width*fw+8, fh+8, RGB(100,100,100)
        ENDIF

        IF gui.kbditem = id AND MOD(GETTIMERALL(),1000) < 500
                PRINT buffer$+"_", x, y
        ELSE
                PRINT buffer$, x, y
        ENDIF

        IF gui.kbditem = id
                IF gui.tab = 1
                        gui.kbditem = 0
                        IF gui.shift THEN gui.kbditem = gui.lastwidget
                        gui.tab = -1
                ENDIF
                IF ASC(gui.keyentered$) = 8 AND length > 0
                        buffer$ = MID$(buffer$, 0, length-1)
                        changed = 1
                ENDIF
        ENDIF
        IF (ASC(gui.keyentered$)>=32 AND ASC(gui.keyentered$)<=127 AND length<width)
                buffer$ = buffer$ + gui.keyentered$
                changed = 1
        ENDIF

        IF (gui.mouselclick=FALSE AND gui.hotitem = id AND gui.activeitem = id)
                gui.kbditem = id
        ENDIF

        gui.lastwidget = id

        RETURN changed

ENDFUNCTION

//window widget (only a rectangle, with draggable header)
FUNCTION window: id, BYREF x, BYREF y, width, height, color, name$
        STATIC headerH = 16
        LOCAL changed = 0
        LOCAL fw, fh
        GETFONTSIZE fw, fh

        IF gui.hotitem = id
                IF (gui.activeitem = 0 AND gui.mouselclick)
                        gui.activeitem = id
                ENDIF
        ENDIF

        IF (gui.inregion(x, y, width, height))
                gui.prehotitem = -2 //window area
        ENDIF
        IF (gui.inregion(x, y, width, headerH))
                gui.prehotitem = id     //header
        ENDIF

        //move window
        IF gui.mouselclick = 1 AND gui.activeitem = id
                x = gui.mousex-width/2
                y = gui.mousey-headerH/2
                changed = 1
        ENDIF

        IF (gui.activeitem = id OR gui.hotitem = id)
                DRAWRECT x, y, width, headerH, RGB(255, 255, 255)
        ELSE
                DRAWRECT x, y, width, headerH, color
        ENDIF

        PRINT name$, x+5, y+(headerH-fh)/2, TRUE

        LOCAL namelen = LEN(name$, TRUE)
        FOR i=1 TO 4
                DRAWLINE x + 10 + namelen, y+headerH*i/4.0, x + width - 5, y+headerH*i/4.0, RGB(255, 255, 255)
        NEXT

        IF (gui.activeitem = id OR gui.hotitem = id)
                DRAWRECT x, y+headerH, width, height-headerH, color //RGB(255,255,255)
        ELSE
                DRAWRECT x, y+headerH, width, height-headerH, color
        ENDIF

        RETURN changed
ENDFUNCTION

//popupmenu widget (only active while hot, return -1 if )
FUNCTION popupmenu: id, x, y, color, menuitems$[]
        LOCAL fw, fh
        GETFONTSIZE fw, fh
        LOCAL width=0
        LOCAL height=0
        LOCAL numitems=0       
        LOCAL item=0
        FOREACH mi$ IN menuitems$[]
                width = MAX(width, LEN(mi$, TRUE))
                IF mi$<>"---" THEN INC numitems
        NEXT
        height = numitems*fh
        INC width, 10

        IF (gui.inregion(x, y+fh, width, height-fh) OR gui.inregion(x, y, LEN(menuitems$[0],TRUE)+10, fh))
                gui.prehotitem = id
                gui.hotitem = id
                IF (gui.activeitem = 0)
                        gui.activeitem = id
                ENDIF
        ENDIF
        IF gui.hotitem<>id AND gui.mouselclick
                RETURN -1
        ENDIF

        DRAWRECT x, y, LEN(menuitems$[0],TRUE)+10, fh, 0xffffff-color
        DRAWRECT x, y+fh, width, height-fh, color
        IF (gui.hotitem = id)
                item = INTEGER((gui.mousey - y) / fh)
                IF item>0
                        DRAWRECT x, y+item*fh, width, fh, RGB(255, 255, 255)
                ENDIF
        ENDIF
               
        LOCAL ypos=0
        FOREACH mi$ IN menuitems$[]
                IF mi$<>"---"
                        PRINT mi$, x+5, y+ypos, TRUE
                        INC ypos, fh
                ELSE
                        DRAWLINE x, y+ypos, x+width, y+ypos, 0
                ENDIF
        NEXT

        IF (item>0 AND gui.activeitem = id AND gui.mouselclick)
                numitems=0
                LOCAL i=0
                FOREACH mi$ IN menuitems$[]
                        IF mi$<>"---"
                                IF item=numitems THEN RETURN i
                                INC numitems
                        ENDIF
                        INC i
                NEXT
        ENDIF
        RETURN 0
ENDFUNCTION

//toads widget (show a message and fade away after a period)
FUNCTION toast: id, x, y, color, text$, BYREF timer
        LOCAL fw, fh
        GETFONTSIZE fw, fh
        LOCAL alpha=timer/10.0
        IF alpha<0.1 THEN RETURN -1
        IF alpha>1.0 THEN alpha = 0.8
        LOCAL width = LEN(text$, TRUE)

        IF gui.hotitem = id
                IF (gui.activeitem = 0 AND gui.mouselclick)
                        gui.activeitem = id
                        timer = 0
                ENDIF
        ENDIF

        IF (gui.inregion(x-4, y-4, width+8, fh+8))
                gui.prehotitem = id
        ENDIF

        ALPHAMODE -alpha
        DRAWRECT x-4, y-4, width+8, fh+8, color
        PRINT text$, x,y, TRUE
        ALPHAMODE 0
ENDFUNCTION
 

Also you can download the whole project.

EDIT:
- added SliderH (horizontal slider)
- added PopupMenu
- added Toaster (fade away message)

[attachment deleted by admin]
« Last Edit: 2013-Apr-23 by Albert »

Offline Wampus

  • Prof. Inline
  • *****
  • Posts: 1004
    • View Profile
Re: Immediate Mode GUI
« Reply #1 on: 2010-Dec-16 »
Well...this is superb=D

Immediate Mode GUIs, eh? I am going to look up more about them. I would like to use something like this for a complex map, character and AI testing program I need to write. Sometimes I will need information boxes up and be able to change settings on the fly while the game is running.

Are you going to develop it further? Add other features?

Offline Kitty Hello

  • code monkey
  • Administrator
  • Prof. Inline
  • *******
  • Posts: 10689
  • here on my island the sea says 'hello'
    • View Profile
    • http://www.glbasic.com
Re: Immediate Mode GUI
« Reply #2 on: 2010-Dec-16 »
Wow, that's very little code you're using.  :blink:

Did I do anything wrong with DDgui?

Offline Albert

  • Dr. Type
  • ****
  • Posts: 257
    • View Profile
    • Blog
Re: Immediate Mode GUI
« Reply #3 on: 2010-Dec-16 »
Hello!
I'm developing it further, adding new widgets to it, as I'm using IMGUI to improve my leveleditor.
As it is told in the tutorial, it's not a complete GUI system as DDGUI is, and a lot of thing cannot be do with IMGUI. But if you want to add a quick button or a slider into your game, then you can do it without too much inicialization.

Offline Kitty Hello

  • code monkey
  • Administrator
  • Prof. Inline
  • *******
  • Posts: 10689
  • here on my island the sea says 'hello'
    • View Profile
    • http://www.glbasic.com
Re: Immediate Mode GUI
« Reply #4 on: 2010-Dec-16 »
The menu is ace!

Offline Wampus

  • Prof. Inline
  • *****
  • Posts: 1004
    • View Profile
Re: Immediate Mode GUI
« Reply #5 on: 2010-Dec-17 »
Albert I think I will do what you did and follow those tutorials about Immediate Mode GUIs, or use what you've done and add what I need.

By the New Year I want to have a GUI ready where I can turn windows off & on and move them about that will have virtual screens for the iPad (1024x768), iPhone Retina (960x640) and older iPhone (480x320) all running in realtime. Since the code to a game I'm writing for these systems will completely separate display, input and the game engine mechanics it should be possible to run the game displays and inputs inside virtual windows. I also want windows I can turn off and on that allow me to edit maps, game agents, reset the game to the beginning or jump to other parts and also edit other settings while the game is running in realtime. An immediate-mode GUI is exactly what I need for this kind of thing.

Gernot, as far as I'm aware these Immediate-Mode GUIs work very differently to conventional GUIs. They're simplistic but very good for realtime processing - great for games.

Offline Albert

  • Dr. Type
  • ****
  • Posts: 257
    • View Profile
    • Blog
Re: Immediate Mode GUI
« Reply #6 on: 2010-Dec-17 »
Ragaril, please keep in mind, that it's not designed to work with Windows. I added a window widget just for fun, but you can't bring a window to front or back, unless you write a little windows manager.
If you see Sol's other tutorials, you may find a PDF about IMGUI in J2ME devices. You can see that IMGUI is good for different screen sizes, because IMGUI is a dynamic system. You also may found in that PDF some J2ME screenshot about listboxs and other goodness, but there are only little information about this.
In the PDF there was a formula to complex, scrollable listbox:
gui.StartListbox(1, ...)
gui.ListItem(1, ...)
gui.ListItem(1, ...)
.....
gui.EndListbox(1, Count)
If you crate ListBox or some another cool widget please share with us.
In the PDF there are also some links, I followed one to a forum, where some guy developed IMGUI further.
« Last Edit: 2010-Dec-17 by Albert »

Offline Wampus

  • Prof. Inline
  • *****
  • Posts: 1004
    • View Profile
Re: Immediate Mode GUI
« Reply #7 on: 2010-Dec-17 »
Thanks for the tips Albert. If I do create a listbox or whatnot, I'll post it. I just need some way to create an extensive testing environment where I can change many variables without having to change and recompile code or alter an ini file.

Offline DmitryK

  • Mc. Print
  • *
  • Posts: 44
  • ......................................
    • View Profile
    • DK's mobile games
Re: Immediate Mode GUI
« Reply #8 on: 2010-Dec-22 »
Albert, thank you for sharing that!

this is my five cents, hope it'll be useful:

1. I changed "button" function for sprite support
if you don't send last param "image" (sprite id) the function works as before
also text is horizontal centered now

2. I joined sliderh and sliderv fuctions to one - slider
now slider can be any width (not only 16), both width and height are sent as params
also added sprite support - two last params

Code: GLBasic [Select]
//Button widget (clickable)
FUNCTION button: id, x, y, _width, _height, color, text$, image=-1 //new   image - sprite id
        LOCAL fw, fh
        LOCAL width, height     // new

        //new---------------------------------
        IF image=-1
                width = _width
                height = _height
        ELSE
                GETSPRITESIZE image, width, height
        ENDIF
        //end new-----------------------------

        GETFONTSIZE fw, fh

        IF gui.hotitem = id
                IF (gui.activeitem = 0 AND gui.mouselclick)
                        gui.activeitem = id
                ENDIF
        ENDIF
        IF gui.inregion(x,y,width,height)
                gui.prehotitem = id
        ENDIF
        IF gui.kbditem = 0
                gui.kbditem = id
        ENDIF

    // selected outline draw
        IF gui.kbditem = id AND image=-1 //change -> AND image=-1
                DRAWRECT x-1, y-1, width+4, height+4, RGB(255, 0, 0)
        ENDIF

    IF gui.kbditem = id AND image=-1 //change
                DRAWRECT x+1, y+1, width, height, RGB(0, 0, 0)
        ENDIF

        IF gui.hotitem = id
                IF gui.activeitem = id
                  IF image=-1 //new
                        DRAWRECT x+2, y+2, width, height, RGB(255, 255, 255)
                  ELSE  // new
                    ALPHAMODE -0.8
                        DRAWSPRITE image, x+2, y+2 //new
                  ENDIF // new
                ELSE
                  IF image=-1 //new
                        DRAWRECT x, y, width, height, RGB(255, 255, 255)
                  ELSE
                    ALPHAMODE -1
                    DRAWSPRITE image, x, y //new
                  ENDIF
                ENDIF
        ELSE
          IF image=-1 //new
                DRAWRECT x, y, width, height, color
          ELSE
            ALPHAMODE -0.8
            DRAWSPRITE image, x, y //new
          ENDIF
        ENDIF

        PRINT text$,  x+(width-LEN(text$,TRUE))/2, y+(height-fh)/2, TRUE //change -> x+(width-LEN(text$,TRUE))/2

        //KBDITEM stb...
        IF gui.kbditem = id
                IF gui.tab = 1
                        gui.kbditem = 0
                        IF gui.shift THEN gui.kbditem = gui.lastwidget
                        gui.tab = -1
                ENDIF
                IF gui.keyentered$="\n" //ENTER
                        RETURN 1
                ENDIF
        ENDIF

        gui.lastwidget = id

        IF gui.mouselclick = 0 AND gui.hotitem = id AND gui.activeitem = id THEN RETURN 1

        RETURN 0
ENDFUNCTION

//slider widget (vertical and horizontal)
FUNCTION slider: id, x, y, _width, _height, maximum, BYREF value, slider_image=-1, pointer_image=-1
        STATIC marginH = 2
        STATIC marginW = 2

        //new-----------------------------------
        LOCAL width, height, val, mousepos, xpos, ypos, slider_size, pointer_size, slider_h // true, false

        IF slider_image=-1
                width = _width
                height = _height
        ELSE
                GETSPRITESIZE slider_image, width, height
                GETSPRITESIZE pointer_image, pointer_size, pointer_size
        ENDIF

        IF width >= height // horizontal slider
          slider_h = TRUE
          slider_size = width
          IF slider_image=-1 THEN pointer_size = height - marginH*2
          xpos = ((width-pointer_size -marginW*2) * value) / maximum
          ypos = 0
        ELSE               // vertical slider
          slider_h = FALSE
          slider_size = height
          IF slider_image=-1 THEN pointer_size = width - marginW*2
          xpos = 0
          ypos = (height-pointer_size - marginH*2) - ((height-pointer_size - marginH*2) * value) / maximum
        ENDIF
        //end new ------------------------------

        IF gui.hotitem = id
                IF (gui.activeitem = 0 AND gui.mouselclick)
                        gui.activeitem = id
                ENDIF
        ENDIF
        IF (gui.inregion(x,y, width, height))
                gui.prehotitem = id
        ENDIF
        IF gui.kbditem = 0
                gui.kbditem = id
        ENDIF

    //selected outline draw
        IF gui.kbditem = id AND slider_image=-1 THEN DRAWRECT x-1, y-1, width+2, height+2, RGB(255, 0, 0)
       
    //slider itself draw
    IF slider_image=-1 THEN DRAWRECT x, y, width, height, RGB(50, 50, 50)

    // pointer draw
        IF (gui.activeitem = id OR gui.hotitem = id)
          IF slider_image=-1
                DRAWRECT x+marginW + xpos, y+marginH + ypos, pointer_size, pointer_size, RGB(255,255,255) //change
          ELSE
            ALPHAMODE -1
            DRAWSPRITE slider_image, x, y
            DRAWSPRITE pointer_image, x+marginW + xpos, y+ypos
          ENDIF
        ELSE
          IF slider_image=-1
                DRAWRECT x+marginW + xpos, y+marginH + ypos, pointer_size, pointer_size, RGB(200,200,200) //change
          ELSE
            ALPHAMODE -0.8
            DRAWSPRITE slider_image, x, y
            DRAWSPRITE pointer_image, x+marginW + xpos, y+ypos
          ENDIF
        ENDIF

    //keyboard management
        IF gui.kbditem = id
                IF gui.tab = 1
                        gui.kbditem = 0
                        IF gui.shift THEN gui.kbditem = gui.lastwidget
                        gui.tab = -1
                ENDIF
                IF gui.left = 1 OR gui.down = 1 //change
                        IF (value > 0)
                                DEC value, maximum/slider_size //change -> maximum/slider_size
                                IF value < 0 THEN value = 0
                                RETURN 1
                        ENDIF
                ENDIF
                IF gui.right = 1 OR gui.up = 1
                        IF (value < maximum)
                                INC value, maximum/slider_size //change -> maximum/slider_size
                                IF value > maximum THEN value = maximum
                                RETURN 1
                        ENDIF
                ENDIF
        ENDIF

        gui.lastwidget = id

    //mouse management
        IF gui.activeitem = id
                IF slider_h //new
                        mousepos = gui.mousex - (x+marginW)
                ELSE
                        mousepos = gui.mousey - (y+marginH)
                ENDIF
                IF (mousepos < 0) THEN mousepos = 0
                IF (mousepos > slider_size) THEN mousepos = slider_size
                IF slider_h //new
                  val = (mousepos*maximum) / slider_size // for horiz
                ELSE
                  val = (slider_size-(mousepos*maximum)) / slider_size //for vert
                ENDIF
                IF (val <> value)
                        value = val
                        RETURN 1
                ENDIF
        ENDIF

        RETURN 0
ENDFUNCTION



[attachment deleted by admin]
Our life is just a Game!

Offline Albert

  • Dr. Type
  • ****
  • Posts: 257
    • View Profile
    • Blog
Re: Immediate Mode GUI
« Reply #9 on: 2010-Dec-22 »
Neat! I like it.
I found some bug in my IMGUI code, I will rerelease here when I will have some more spare time :)

Here is a screenshot. I used my IMGUI code in my old jump&run game's level editor:

Offline Schranz0r

  • Premium User :)
  • Administrator
  • Prof. Inline
  • *******
  • Posts: 5013
  • O Rly?
    • View Profile
Re: Immediate Mode GUI
« Reply #10 on: 2010-Dec-22 »
WOW  :blink:
I <3 DGArray's :D

PC:
AMD RYzen 7 1700 @3.9Ghz, 16GB HyperX Fury 2666Mhz Ram, ASUS ROG GTX 1060 STRIX 6GB, Windows 10 Pro 64Bit, MSi Tomahawk B350 Mainboard

Offline erico

  • Community Developer
  • Prof. Inline
  • ******
  • Posts: 4177
    • View Profile
    • Portfolio
Re: Immediate Mode GUI
« Reply #11 on: 2010-Dec-23 »
 :O

Offline WPShadow

  • Administrator
  • Prof. Inline
  • *******
  • Posts: 1665
    • View Profile
    • http://lostrevenant.blogspot.com
Re: Immediate Mode GUI
« Reply #12 on: 2010-Dec-27 »
 :blink: looks great  :good:
AMD X2 4600, 2 GB Ram, ATI X1950 XTX, XP PRO SP2: GLB Premium 10.beta_dingsi, <(´.´<) Kirby Dance (>`.`)>
http://lostrevenant.blogspot.com
alea iacta est

MrTAToad

  • Guest
Re: Immediate Mode GUI
« Reply #13 on: 2011-Jan-23 »
Will you be able to add in radio buttons, tabs and edit boxes ?

Offline Albert

  • Dr. Type
  • ****
  • Posts: 257
    • View Profile
    • Blog
Re: Immediate Mode GUI
« Reply #14 on: 2011-Jan-23 »
IMGUI is about: "you store all the data, not the GUI object". So you can add radio buttons and tabs, but the control will be not in the widget. I've just added to my program a Graphics details setting with simple radio buttons. I used only the basic IMGUI widget called button()



There is my Settings() function (I deleted the other settings to make smaller this code, and I'm using a big font):
Code: GLBasic [Select]

GLOBAL GraphicsDetail=2 //High

Settings()

FUNCTION Settings:
        LOCAL vege=0
        LOCAL mx = 10
        LOCAL mxg = 150
        LOCAL my
        LOCAL tmp, color
        WHILE vege<>1
                PRINT "Details",mx,my,TRUE
                IF GraphicsDetail=0
                        color=RGB(128,128,128)
                ELSE
                        color=RGB(0,0,0)
                ENDIF
                tmp=button(5, mxg, my+10, 100, 30, color, "Low")
                IF tmp THEN GraphicsDetail=0
                IF GraphicsDetail=1
                        color=RGB(128,128,128)
                ELSE
                        color=RGB(0,0,0)
                ENDIF
                tmp=button(6, mxg+110, my+10, 100, 30, color, "Medium")
                IF tmp THEN GraphicsDetail=1
                IF GraphicsDetail=2
                        color=RGB(128,128,128)
                ELSE
                        color=RGB(0,0,0)
                ENDIF
                tmp=button(7, mxg+220, my+10, 100, 30, color, "High")
                IF tmp THEN GraphicsDetail=2
                SHOWSCREEN //
        WEND
ENDFUNCTION
 
Also Tabs is only another radio buttons, but you draw other content if the user click on other tab. You could make nice graphics to your widgets I'm using really simple one (DRAWRECT)
« Last Edit: 2011-Jan-23 by Albert »