Quick Links: Download Gideros Studio | Gideros Documentation | Gideros community chat | DONATE
Responsive ui with imgui. — Gideros Forum

Responsive ui with imgui.

As mentioned in a previous post I am creating a password manager with gideros and imgui. I am trying to figure out how to create a GUI that is adaptable for both desktop and mobile. For now I have selected a very high resolution 16/9 portrait. Do you have any advice for how to manage a non-game related GUI that is scalable and resizable?
Thanks!

Comments

  • i'm not sure if it would be mobile-friendly enough but in any case you can set scaling, see e.g. topmenu/windows/menu scaling option in my app:
    https://longtitle-productions.itch.io/fragmenter
    imgui:setScale(value)

    Likes: MoKaLux, giovifav

    +1 -1 (+2 / -0 )Share on Facebook
  • piepie Member
    edited December 2023 Accepted Answer
    Hi I can think of two ways to do it:
    1) let gideros handle that for you with "stretch" scale mode or any other scale mode that suits your app. In project properties (right click on the project name in the project tree)



    2) Let it handle to imgui: I copypasted pieces from a project therefore there might be some issues here (it's not ready to run)

    I am not sure that this is the best way to do it but it works for me:
    there is a onWindowsResize function that sets IO displaysize, get every screen measure and saves them into a screenmeasures var.

    whenever the app is resized it is called and update the measures.

    Setting elements sizes in relative values based on "screenmeasures" makes the trick work. ie.
    ui:setNextWindowSize(screenmeasures.w, screenmeasures.h) for a fullscreen window
    ui:setNextWindowSize(screenmeasures.w*.5, screenmeasures.h) for a window that covers half of the screen.

    Then I have a function to build the desired font size depending on the screen resolution. FontAtlas must be set at the beginning and I've never had a reason to update the font size on the run, but I guess it might be possible to update the fontAtlas too: my need was only to have bigger fonts on mobile devices and smaller on desktop.

    function onWindowResize(rt)
    	local minX, minY, maxX, maxY = application:getLogicalBounds()
     
    	local sx = application:getLogicalScaleX()
    	local sy = application:getLogicalScaleY()
     
    	local our_DPI = application:getScreenDensity() 
     
     
    	ui:setScale(1 / sx, 1 / sy)
    	-- move UI to top left corner
    	ui:setPosition(minX, minY)
    	-- resize display area
    	IO:setDisplaySize((maxX - minX) * sx, (maxY - minY) * sy)
     
    	if rt then
    		rt = {
    			x  = minX,
    			X  = maxX,
    			y  = minY,
    			Y  = maxY,
    			Sx = sx,
    			Sy = sy,
    			w  = (maxX - minX) * sx,
    			h  = (maxY - minY) * sy,
    			dpi = our_DPI
    		}
     
    		-- android navbar
    		if our_DPI then
    		-- 0.3 is a magic number that appears to be working on most devices
    			local navbar_height_int = our_DPI * 0.3 
     
    			rt.nbh = navbar_height_int
     
    		else --there is no android navbar on desktop
    			rt.nbh = 0 
    		end
     
    		return rt
    	end
    end
     
    screenmeasures = onWindowResize(true)
     
    --screenmeasures stores the values we need in order to center/position stuff on screen: (true) neans that the function must return those values (see above)
     
    --update window size: it is called by applicationResize event
    function updateScreen()
    	screenmeasures = onWindowResize(true)
     
    end
     
    local function getFontScale(par)
    	local fontsize = {	
    		h2 = 98,
    		p = 82
    		}
     
    	local screenbasex = 1080
     
    	local SX = screenmeasures.w/screenbasex
     
    	return fontsize[par]*SX
    end
     
    local FontAtlas = IO:getFonts()
    local fonts = FontAtlas:addFonts{ {"myfont.ttf", getFontScale("p"), text_options}, 
    						{"myfont-Bold.ttf", getFontScale("h2"), text_options} }
     
     
    local function drawWindow()
     
    	ui:setNextWindowSize(screenmeasures.w, screenmeasures.h)
    	ui:setNextWindowPos(screenmeasures.x, screenmeasures.y)
    	window02 = ui:beginWindow(
    ...
     
     
     
    end
     
     
    stage:addEventListener("applicationResize", updateScreen) --check if container app resizes


    hope this helps :)

    Likes: MoKaLux, giovifav

    +1 -1 (+2 / -0 )Share on Facebook
  • giovifavgiovifav Member
    edited December 2023
    Thank you very much everyone, especially pie.
    I used the second method you suggested, with a little adjustment it is exactly what I was looking for. I added font management in applicationResize and now it behaves almost like it was a responsive website!
    Gideros has a small but kind and passionate community.
    require "ImGui"
     
    application:setBackgroundColor(0x262626) -- hex format
    local ui = ImGui.new()
    local IO = ui:getIO()
    stage:addChild(ui)
    ui:setDarkStyle()
    local fontTitle
    local fontText
     
    function onWindowResize(rt)
    	local minX, minY, maxX, maxY = application:getLogicalBounds()
    	local sx = application:getLogicalScaleX()
    	local sy = application:getLogicalScaleY()
    	local our_DPI = application:getScreenDensity() 
    	ui:setScale(1 / sx, 1 / sy)
    	-- move UI to top left corner
    	ui:setPosition(minX, minY)
    	-- resize display area
    	IO:setDisplaySize((maxX - minX) * sx, (maxY - minY) * sy)
    	if rt then
    		rt = {
    			x  = minX,
    			X  = maxX,
    			y  = minY,
    			Y  = maxY,
    			Sx = sx,
    			Sy = sy,
    			w  = (maxX - minX) * sx,
    			h  = (maxY - minY) * sy,
    			dpi = our_DPI, 
    			dummyH = ((maxY - minY) * sy) * 0.01,
    		}
    		local Style = ui:getStyle()
    		Style:setWindowPadding(rt.w * 0.1,rt.w * 0.1)
    		-- android navbar
    		if our_DPI then
    		-- 0.3 is a magic number that appears to be working on most devices
    			local navbar_height_int = our_DPI * 0.3 
    			rt.nbh = navbar_height_int
    		else --there is no android navbar on desktop
    			rt.nbh = 0 
    		end
    		local function getFontScale(par)
    			local fontsize = {	
    				title = 150,
    				text = 60
    				}
    			local screenbasex = 1920
    			local SX = rt.w/screenbasex
    			return fontsize[par]*SX
    		end
     
    		local FontAtlas = IO:getFonts()
    		fontTitle = FontAtlas:addFont("fonts/Poppins-Bold.ttf", getFontScale("title")) 
    		fontText = FontAtlas:addFont("fonts/Poppins-Regular.ttf", getFontScale("text"))
    		FontAtlas:build()
    		return rt
    	end
    	end
    screenmeasures = onWindowResize(true)
    stage:addEventListener("applicationResize", function() screenmeasures = onWindowResize(true) end) --check if container app resizes
    application:setWindowSize(800,600)

    Likes: keszegh, MoKaLux, pie

    +1 -1 (+3 / -0 )Share on Facebook
  • I'm glad it helped :)
    I wonder if it is better to define the FontAtlas outside the function scope and overwrite it instead of building a new one everytime it's needed:
    I don't know how imgui handles that internally, but if there is something still referenced there, the local values can't be garbage collected. Overwriting the same one should avoid the potential issue.
     
    ...
    ui:setDarkStyle()
    local fontTitle
    local fontText
    local FontAtlas --here
     
    function onWindowResize(rt)
    ...
    		FontAtlas = IO:getFonts() --just like that
    		fontTitle = FontAtlas:addFont("fonts/Poppins-Bold.ttf", getFontScale("title")) 
    		fontText = FontAtlas:addFont("fonts/Poppins-Regular.ttf"

    Likes: MoKaLux

    +1 -1 (+1 / -0 )Share on Facebook
  • To be on the safe side, I made the change. I didn't see any improvement in performance but the application is so light that it doesn't make a difference. I should learn how to use the profiler.
Sign In or Register to comment.