Quick Links: Download Gideros Studio | Gideros Documentation | Gideros Development Center | Gideros community chat | DONATE
imGui bindings - Page 13 — Gideros Forum

imGui bindings

1910111315

Comments

  • SinisterSoftSinisterSoft Maintainer
    edited October 2020
    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
  • that does not matter i think. it would check if it is pressed or not, that's unambiguous.
  • v1.80 should be a nice release - they are adding in the tables.
    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
  • @rrraptor , thanks. although i also decided not to use the docking features as of now as i need fixed size windows (or at least fixed minimum size, which i did not see how to make), let's see when docking becomes part of the main branch.
  • rrraptorrrraptor Member
    edited October 2020
    keszegh said:

    i need fixed size windows (or at least fixed minimum size, which i did not see how to make)

    So you can do it like this:
    local function minSizeCallback(windowX, windowY, windowW, windowH, desiredW, desiredH)
    	-- do some math and return desired size
    	return desiredW, desiredH
    end
     
    local draw = true
     
    local function drawGui(e)
    	globalUI:newFrame(e)
     
    	globalUI:setNextWindowSizeConstraints(200, 100, 100000, 100000) -- min and max size
    	draw = ImGui:beginWindow("my window", nil, 0, minSizeCallback)
    	if (draw) then 
    		globalUI:text("Hello world")
    		globalUI:endWindow()
    	end
     
    	globalUI:render()
    	globalUI:endFrame()
    end

    Likes: keszegh

    +1 -1 (+1 / -0 )Share on Facebook
  • i'm not sure i get what happens on the video, but looks cool. : )

    Likes: rrraptor

    +1 -1 (+1 / -0 )Share on Facebook
  • rrraptorrrraptor Member
    edited October 2020
    keszegh said:

    i'm not sure i get what happens on the video, but looks cool. : )

    Im trying to make it work with gideros scale modes (letterbox and etc). So if application window scales up or down, mouse position calculates correctly.

    @hgy29 can you help with that?)

    I did it this way:
    added event listener for "applicationResize"
    double getApplicationProperty(lua_State* L, const char* name)
    {
        lua_getglobal(L, "application"); // application
        lua_getfield(L, -1, name);       // application[name]
        lua_getglobal(L, "application"); // application[name], application
        lua_call(L,1,1);                 // application[name](application)
        double value = luaL_checknumber(L, -1); // value, application.name
        lua_pop(L, 2);
     
        return value;
    }
     
    ImVec4 getApplicationBounds(lua_State* L)
    {
        lua_getglobal(L, "application");
        lua_getfield(L, -1, "getLogicalBounds");
        lua_getglobal(L, "application");
        lua_call(L,1,4);
        double minX = luaL_checknumber(L, -4);
        double minY = luaL_checknumber(L, -3);
        double maxX = luaL_checknumber(L, -2);
        double maxY = luaL_checknumber(L, -1);
        lua_pop(L, 5);
        // top left corner and size   
        return ImVec4(minX, minY, maxX - minX, maxY - minY);
    }
     
    ImVec2 getApplicationScale(lua_State* L)
    {
        double sx = getApplicationProperty(L, "getLogicalScaleX");
        double sy = getApplicationProperty(L, "getLogicalScaleY");
     
        return ImVec2(sx, sy);
    }
    // EventListener function
    void applicationResize(Event *)
    {
        app_scale = getApplicationScale(L);
        r_app_scale.x = 1.0f / app_scale.x;
        r_app_scale.y = 1.0f / app_scale.y;
        app_bounds = getApplicationBounds(L);
    }


    And when I calculate mouse position:
    static ImVec2 getMousePos(SpriteProxy* proxy, float x, float y, ImVec2 r_app_scale, ImVec4 app_bounds)
    {
        return ImVec2(
            (x * r_app_scale.x + app_bounds.x - proxy->x()) * 1.0f / proxy->scaleX(),
            (y * r_app_scale.y + app_bounds.y - proxy->y()) * 1.0f / proxy->scaleY()
        );
    }
     
    // EventListener for mouse events:
    ImGuiIO& io = ImGui::GetIO();
    // x, y - mouse position from MouseEvent (goes from 0 to window width/height)
    io.MousePos = getMousePos(proxy, x, y, r_app_scale, app_bounds);


    Is it OK or there is a better solution?
  • rrraptorrrraptor Member
    edited October 2020
    Spent whole day trying to make dockbuilder work and here is the result:

    Code:
    -- flags to emulate fullscreen window
    local window_flags = ImGui.WindowFlags_NoTitleBar | ImGui.WindowFlags_NoCollapse | ImGui.WindowFlags_NoResize | ImGui.WindowFlags_NoMove | ImGui.WindowFlags_NoBringToFrontOnFocus | ImGui.WindowFlags_NoNavFocus
     
    EditorScene = Core.class(Sprite)
     
    function EditorScene:init()
    	self.imgui = ImGui.new()
    	self:addChild(self.imgui)
     
    	local IO = self.imgui:getIO()
    	IO:setIniFilename(nil) -- disable INI file
    	IO:addConfigFlags(ImGui.ConfigFlags_DockingEnable)
     
    	self:addEventListener("enterFrame", self.drawGUI, self)
    end
    --
    function EditorScene:drawGUI(e)
    	local UI = self.imgui
     
    	UI:newFrame(e)
    	local dockspace_id = UI:getID("root")
     
    	if (not UI:dockBuilderCheckNode(dockspace_id)) then -- called once
    		self:createDock(UI, dockspace_id)
    	end
     
    	local IO = self.imgui:getIO()
    	UI:setNextWindowPos(0, 0)
    	UI:setNextWindowSize(IO:getDisplaySize())
     
    	UI:pushStyleVar(ImGui.StyleVar_WindowRounding, 0)
    	UI:pushStyleVar(ImGui.StyleVar_WindowBorderSize, 0)
    	UI:pushStyleVar(ImGui.StyleVar_WindowPadding, 0, 0)
    	UI:beginWindow("DockSpace Demo", nil, window_flags)
    	UI:popStyleVar(3)
     
    	UI:dockSpace(dockspace_id, 0, 0)
        UI:endWindow()
     
    	if (UI:beginWindow("Log", nil)) then 
    		UI:value("Random", math.random()) 
    	end
        UI:endWindow()
     
    	if (UI:beginWindow("Properties", nil)) then
    	end
        UI:endWindow()
     
    	if (UI:beginWindow("Grid", nil)) then
    	end
        UI:endWindow()
     
    	UI:render()
    	UI:endFrame()
    end
    --
    function EditorScene:createDock(UI, dockspace_id)
    	UI:dockBuilderRemoveNode(dockspace_id) -- clear existing layout
    	UI:dockBuilderAddNode(dockspace_id) -- add empty node
     
    	-- split main node into 2 (left and right node), return left panel id AND modified dockspace id
    	local dock_id_left,_,dockspace_id= UI:dockBuilderSplitNode(dockspace_id, ImGui.Dir_Left, 0.2, nil, dockspace_id)
     
    	-- split right node into 2, return bottom panel id
    	local dock_id_bottom = UI:dockBuilderSplitNode(dockspace_id, ImGui.Dir_Down, 0.2, nil, dockspace_id)
     
    	-- split right node into 2 (but in different direction), return top panel id
    	local dock_id_top = UI:dockBuilderSplitNode(dockspace_id, ImGui.Dir_Up, 0.7, nil, dockspace_id)
     
    	UI:dockBuilderDockWindow("Log", dock_id_bottom)
    	UI:dockBuilderDockWindow("Grid", dock_id_up)
    	UI:dockBuilderDockWindow("Properties", dock_id_prop)
    	UI:dockBuilderFinish(dockspace_id)
    end

    Also, Ive noticed this:

    ini file contains imgui window settings.
    You can disable it like I did ( IO:setIniFilename(nil) ). But I want to make it so it will be stored somewhere in gideros documents folder ("|D|imgui.ini" or something like that). Same for .log file ( ImGui:logToFile() )
    imgui_dockbuilder_test.png
    942 x 557 - 5K
    image.png
    188 x 106 - 4K

    Likes: MoKaLux

    +1 -1 (+1 / -0 )Share on Facebook
  • I will play with it and see what I can do for the wiki :) thank you rrraptor for yet another great contribution to gideros <3 .
    my growING GIDEROS github repositories: https://github.com/mokalux?tab=repositories
  • hgy29hgy29 Maintainer
    rrraptor said:

    Is it OK or there is a better solution?

    I guess it won't work if you put your imgui sprite inside another sprite with its own transform. Ideally you would want to retrieve mouse coordinate in logical stage space such as what Gideros reports in lua, then perform th equivalent of globalToLocal on your sprite. The latter is easy if you have a lua context, but I am not sure to get the former directly from gideros, without having to mimic it like you do.

  • rrraptorrrraptor Member
    edited October 2020
    MoKaLux said:

    I will play with it and see what I can do for the wiki :)<3 .</p>

    Dockbuilder and imgui docking branch is in BETA, so idk if it worth to mention.
    hgy29 said:

    rrraptor said:

    Is it OK or there is a better solution?

    I guess it won't work if you put your imgui sprite inside another sprite with its own transform. Ideally you would want to retrieve mouse coordinate in logical stage space such as what Gideros reports in lua, then perform th equivalent of globalToLocal on your sprite. The latter is easy if you have a lua context, but I am not sure to get the former directly from gideros, without having to mimic it like you do.

    Well I can do something like
    auto curr = proxy;
    while (curr)
    {
    curr->matrix().transformPoint(x, y, newX, newY);
    curr = curr->parent();
    }
    ?
  • hgy29hgy29 Maintainer
    That would do localToGlobal transform while you want the opposite, but yes that's the idea, or just call globalToLocal lua function. Also avoid using "auto" as I am not sure all compilers (I mean for each platform) support C++11.
  • hgy29 said:

    Also avoid using "auto" as I am not sure all compilers (I mean for each platform) support C++11.

    Im not using it :) Just for this example.
    hgy29 said:

    That would do localToGlobal transform while you want the opposite, but yes that's the idea, or just call
    lua function.

    Ah, why it does not work xD

    Anyways, I can take code from here. https://github.com/gideros/gideros/blob/2e4aa2fd3550a7c4d2da9a5d9ac755bfe68d4eae/2dsg/sprite.cpp#L696


    globaltolocal.png
    446 x 125 - 11K
  • hgy29hgy29 Maintainer
    rrraptor said:


    Ah, why it does not work xD

    Because that symbol is not exported in the DLL... Welcome to the wonderful world of cross platform nightmares...

  • hgy29 said:

    That would do localToGlobal transform while you want the opposite, but yes that's the idea, or just call globalToLocal lua function.

    Done.
    static ImVec2 getMousePos(SpriteProxy* proxy, float x, float y, ImVec2 r_app_scale, ImVec4 app_bounds)
    {
        std::stack<const Sprite*> stack;
     
        x = x * r_app_scale.x + app_bounds.x;
        y = y * r_app_scale.y + app_bounds.y;
     
        const Sprite* curr = proxy;
        while (curr)
        {
            stack.push(curr);
            curr = curr->parent();
        }
     
        float z;
        while (!stack.empty())
        {
            stack.top()->matrix().inverseTransformPoint(x, y, 0, &x, &y, &z);
            stack.pop();
        }
     
        return ImVec2(x, y);
    }
  • This is looking amazing - should be great to use with new Editor utilities and Gideros based business apps.

    Likes: MoKaLux

    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
    +1 -1 (+1 / -0 )Share on Facebook
  • is there anything missing or is it ready to work with? i'm enthusiastic about rebuilding my gui with imgui, just i lack the time so it will come a bit later. in any case i hope in next gideros release we will have an imgui plugin we can depend on. thanks again for it, it is amazing
  • rrraptorrrraptor Member
    edited November 2020
    keszegh said:

    is there anything missing or is it ready to work with?

    Missing drag&drop functions and maybe something else...
    File functions works, so you can use this:
    local IO = self.imgui:getIO()
    IO:setLogFilename("|D|imgui_log.txt") -- "%temp%\gideros\ProjectName\documents\imgui_log.txt" on windows
    self.imgui:logToFile()
    self.imgui:logText("Hello world")
    self.imgui:logFinish()
    Same for ini file.
  • thanks @rrraptor, so the resize etc sprite-like behaviour of imgui object is working now as expected? great
  • keszegh said:

    so the resize etc sprite-like behaviour of imgui object is working now as expected?

    It must be :D But I need to do more tests.

    Likes: keszegh

    +1 -1 (+1 / -0 )Share on Facebook
  • rrraptorrrraptor Member
    edited November 2020
    @hgy29
    Can you help a bit?)

    I have a function that returns a table of "ImGuiTabItem" instances.
    int TabBar_GetTabs(lua_State* L)
    {
        Binder binder(L);
        ImGuiTabBar* tabBar = static_cast<ImGuiTabBar*>(binder.getInstance("ImGuiTabBar", 1));
        int count = tabBar->Tabs.Size;
        lua_createtable(L, count, 0);
        for (int i = 0; i < count; i++)
        {
            binder.pushInstance("ImGuiTabItem", &tabBar->Tabs[i]);
            lua_setintfield(L, -2, i + 1);
        }
        return 1;
    }
    And I have a function that expects an "ImGuiTabItem" instance as argument and return its name.
    int TabBar_GetTabName(lua_State* L)
    {
        Binder binder(L);
        ImGuiTabBar* tabBar = static_cast<ImGuiTabBar*>(binder.getInstance("ImGuiTabBar", 1));
        ImGuiTabItem* tab = static_cast<ImGuiTabItem*>(binder.getInstance("ImGuiTabItem", 2));
        lua_pushstring(L, tabBar->GetTabName(tab));
        return 1;
    }
    lua:
    local dockNode = UI:dockBuilderGetNode(dock_id_top) -- OK
    local tabBar = dockNode:getTabBar() -- OK
    local t = tabBar:getTabs() -- OK
    tabBar:getTabName(t[1]) -- sometimes this line works ok, sometimes it leads to a crush
    So I added new function:
    int TabBar_GetTab(lua_State* L) // retruns single tab instance by index
    {
        Binder binder(L);
        ImGuiTabBar* tabBar = static_cast<ImGuiTabBar*>(binder.getInstance("ImGuiTabBar", 1));
        int count = tabBar->Tabs.Size;
        int index = luaL_checkinteger(L, 2) - 1;
        LUA_ASSERT(L, index >= 0 && index <= count, "Tab index is out of bounds.");
        binder.pushInstance("ImGuiTabItem", &tabBar->Tabs[index]);
        return 1;
    }
    in lua:
    local dockNode = UI:dockBuilderGetNode(dock_id_top)
    local tabBar = dockNode:getTabBar()
    local tab0 = tabBar:getTab(1)
    local tab1 = tabBar:getTab(2)
    print(tabBar:getTabName(tab0)) -- always OK
    print(tabBar:getTabName(tab1)) -- always OK
    So whats wrong with "getTabs" function?)
  • hgy29hgy29 Maintainer
    edited November 2020
    I think your lua_setintfield function is the problem, I am not sure what it does, but why didn't you use lua_rawseti instead ?
    EDIT: if lua_setintfield is the same as defined here https://github.com/hgy29/gideros/blob/master/plugins/imgui/source/Common/imgui_bindings.cpp#L3767, then it should work well in theory, so it may be something else after all
  • hgy29 said:

    I think your lua_setintfield function is the problem, I am not sure what it does, but why didn't you use lua_rawseti instead ?

    Keep forgetting about "lua_rawseti"/"lua_rawgeti" :hushed:
    hgy29 said:

    EDIT: if lua_setintfield is the same as defined here https://github.com/hgy29/gideros/blob/master/plugins/imgui/source/Common/imgui_bindings.cpp#L3767, then it should work well in theory, so it may be something else after all

    Weird, everything works on my second PC perfectly...
  • rrraptorrrraptor Member
    edited November 2020
    @hgy29 one more question :)
    Do I need to free memory in the "destroyImGui" function (called when imgui instance garbage collected)? Delete proxy, delete event listener and etc.
  • rrraptorrrraptor Member
    edited November 2020
    Added drag&drop, but its target only accepts "string" and "number" types.
    Example from demo:

    Code in lua:
    local names = {
    	"Bobby", "Beatrice", "Betty",
    	"Brianna", "Barry", "Bernard",
    	"Bibi", "Blaine", "Bryn"
    }
    -- modes:
    local Mode_Copy = 0
    local Mode_Move = 1
    local Mode_Swap = 2
     
    local mode = 0 -- current mode
    function EditorScene:drawGUI(e)
    	UI:newFrame(e)
     
    	if (UI:radioButton("Copy", mode == Mode_Copy)) then mode = Mode_Copy end UI:sameLine()
    	if (UI:radioButton("Move", mode == Mode_Move)) then mode = Mode_Move end UI:sameLine()
    	if (UI:radioButton("Swap", mode == Mode_Swap)) then mode = Mode_Swap end
     
    	for i,v in ipairs(names) do
    		UI:pushID(i)
    		if (((i-1) % 3) ~= 0) then UI:sameLine() end
     
    		UI:button(v, 60, 60)
     
    		if (UI:beginDragDropSource(ImGui.DragDropFlags_None)) then
    			--UI:setStrDragDropPayload("DND_DEMO_CELL", "ID_"..i) -- used for strings
    			UI:setNumDragDropPayload("DND_DEMO_CELL", i) -- used for numbers
     
    			if (mode == Mode_Copy) then UI:text(("Copy %s"):format(v)) end
    			if (mode == Mode_Move) then UI:text(("Move %s"):format(v)) end
    			if (mode == Mode_Swap) then UI:text(("Swap %s"):format(v)) end
    			UI:endDragDropSource()
    		end
     
    		if (UI:beginDragDropTarget()) then
    			local payload = UI:acceptDragDropPayload("DND_DEMO_CELL")
    			if (payload) then
    				--local payload_n = tonumber(payload:getStrData():sub(4))  -- if "setStrDragDropPayload" was used
    				local payload_n = payload:getNumData() -- if "setNumDragDropPayload" was used
     
    				if (mode == Mode_Copy) then
    					names[i] = names[payload_n];
    				end
    				if (mode == Mode_Move) then
    					names[i] = names[payload_n];
    					names[payload_n] = "";
    				end
     
    				if (mode == Mode_Swap) then
    					names[i], names[payload_n] = names[payload_n], names[i]
    				end
    			end
    			UI:endDragDropTarget()
    		end
    		UI:popID()
    	end
    	UI:render()
    	UI:endFrame()
    end
    d&d.png
    202 x 213 - 8K
  • rrraptorrrraptor Member
    edited November 2020
Sign In or Register to comment.