dinau / imguin

Dear Imgui / CImGui, ImPlot/CImPlot wrapper for Nim language
MIT License
29 stars 2 forks source link

The setWindowAttrib Not effective #15

Closed sxzxs closed 1 month ago

sxzxs commented 1 month ago

in glfw_opengl3.nim file

  glfwWindowHint(GLFW_FLOATING, GLFW_TRUE)
  glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE)
  glfwWindowHint(GLFW_MAXIMIZED, GLFW_TRUE)
  glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE);

  var glfwWin = glfwCreateWindow(MainWinWidth, MainWinHeight)
  if glfwWin.isNil:
    quit(-1)
  setWindowAttrib(glfwWin, GLFW_DECORATED, GLfW_TRUE)

The setWindowAttrib can not effective. Can you help me, Thanks very much

dinau commented 1 month ago

GLFW_DECORATED is already TRUE.

Would you try setWindowAttrib(glfwWin, GLFW_DECORATED, GLFW_FALSE) ?

sxzxs commented 1 month ago

thanks, set false can work but setWindowAttrib(glfwWin, GLFWMouseButtonPassthrough, GLFW_FALSE) this not work 02B4CB58

import std/[strutils, math]
import nimgl/[opengl,glfw]

import imguin/[glfw_opengl]

import imguin/lang/imgui_ja_gryph_ranges

include /utils/setupFonts
include imguin/simple

when defined(windows):
  import tinydialogs

const MainWinWidth = 1024
const MainWinHeight = 804

proc glfwSetWindowAttrib*(window: GLFWWindow, attrib: int32, value: int32): void {.importc: "glfwSetWindowAttrib".}

#--------------
# Configration
#--------------

#  .--------------------------------------------..---------.-----------------------.------------
#  |         Combination of flags               ||         |     Viewport          |
#  |--------------------------------------------||---------|-----------------------|------------
#  | fViewport | fDocking | TransparentViewport || Docking | Transparent | Outside | Description
#  |:---------:|:--------:|:-------------------:||:-------:|:-----------:|:-------:| -----------
#  |  false    | false    |     false           ||    -    |     -       |   -     |
#  |  false    | true     |     false           ||    v    |     -       |   -     | (Default): Only docking
#  |  true     | -        |     false           ||    v    |     -       |   v     | Docking and outside of viewport
#  |    -      | -        |     true            ||    v    |     v       |   -     | Transparent Viewport and docking
#  `-----------'----------'---------------------'`---------'-------------'---------'-------------
var
 fDocking = true
 fViewport = true
 TransparentViewport = false
 #
block:
  if TransparentViewport:
    fViewport = true
  if fViewport:
    fDocking = true

#---------------------
# Forward definitions
#---------------------
proc winMain(hWin: glfw.GLFWWindow)

#------
# main
#------
proc main() =
  doAssert glfwInit()
  defer: glfwTerminate()

  if TransparentViewport:
    glfwWindowHint(GLFWVisible, GLFW_FALSE)

  glfwWindowHint(GLFWContextVersionMajor, 3)
  glfwWindowHint(GLFWContextVersionMinor, 3)
  glfwWindowHint(GLFWOpenglForwardCompat, GLFW_TRUE)
  glfwWindowHint(GLFWOpenglProfile, GLFW_OPENGL_CORE_PROFILE)
  glfwWindowHint(GLFWResizable, GLFW_TRUE)

  glfwWindowHint(GLFW_FLOATING, GLFW_TRUE)
  glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE)
  glfwWindowHint(GLFW_MAXIMIZED, GLFW_TRUE)
  glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE);
  #
  var glfwWin = glfwCreateWindow(MainWinWidth, MainWinHeight, "test")
  if glfwWin.isNil:
    quit(-1)

  setWindowAttrib(glfwWin, GLFWMouseButtonPassthrough, GLFW_TRUE)
  setWindowAttrib(glfwWin, GLFW_DECORATED, GLFW_FALSE)

  glfwWin.makeContextCurrent()
  defer: glfwWin.destroyWindow()

  glfwSwapInterval(1) # Enable vsync

  doAssert glInit() # OpenGL init

  # setup ImGui
  let context = igCreateContext(nil)
  defer: context.igDestroyContext()
  if fDocking:
    var pio = igGetIO()
    pio.ConfigFlags = pio.ConfigFlags or ImGui_ConfigFlags_DockingEnable.cint
    if fViewport:
      pio.ConfigFlags = pio.ConfigFlags or ImGui_ConfigFlags_ViewportsEnable.cint
      pio.ConfigViewports_NoAutomerge = true

  # GLFW + OpenGL
  const glsl_version = "#version 130" # GL 3.0 + GLSL 130
  doAssert ImGui_ImplGlfw_InitForOpenGL(cast[ptr GLFWwindow](glfwwin), true)
  defer: ImGui_ImplGlfw_Shutdown()
  doAssert ImGui_ImplOpenGL3_Init(glsl_version)
  defer: ImGui_ImplOpenGL3_Shutdown()
  glfwWin.winMain()

#---------
# winMain
#---------
proc winMain(hWin: glfw.GLFWWindow) =
  var
    showDemoWindow = true
    showAnotherWindow = false
    showFirstWindow = true
    fval = 0.5f
    counter = 0
    sBuf = newString(200)
    sFnameSelected{.global.}:string
    clearColor:ccolor

  if TransparentViewport:
    clearColor = ccolor(elm:(x:0f, y:0f, z:0f, w:0.0f)) # Transparent
  else:
    clearColor = ccolor(elm:(x:0f, y:0f, z:0f, w:0.0f)) # Transparent
    #clearColor = ccolor(elm:(x:0.25f, y:0.65f, z:0.85f, w:0.0f))

  igStyleColorsClassic(nil)

  # Add multibytes font
  discard setupFonts()

  var pio = igGetIO()

  # main loop
  while not hWin.windowShouldClose:
    glfwPollEvents()

    # start imgui frame
    ImGui_ImplOpenGL3_NewFrame()
    ImGui_ImplGlfw_NewFrame()
    igNewFrame()

    if showDemoWindow:
      igShowDemoWindow(addr showDemoWindow)

    # show a simple window that we created ourselves.
    if showFirstWindow:
      igBegin("Nim: Dear ImGui test with Futhark", addr showFirstWindow, 0)
      defer: igEnd()
      var s = "GLFW v" & $glfwGetVersionString()
      igText(s.cstring)
      s = "OpenGL v" & ($cast[cstring](glGetString(GL_VERSION))).split[0]
      igText(s.cstring)
      igInputTextWithHint("InputText" ,"Input text here" ,sBuf)
      s = "Input result:" & sBuf
      igText(s.cstring)
      igCheckbox("Demo window", addr showDemoWindow)
      igCheckbox("Another window", addr showAnotherWindow)
      igSliderFloat("Float", addr fval, 0.0f, 1.0f, "%.3f", 0)
      igColorEdit3("Background color", clearColor.array3, 0.ImGuiColorEditFlags)

      # Show file open dialog
      when defined(windows):
        if igButton("Open file", ImVec2(x: 0, y: 0)):
           sFnameSelected = openFileDialog("File open dialog", getCurrentDir() / "\0", ["*.nim", "*.nims"], "Text file")
        igSameLine(0.0f, -1.0f)
        # ヒント表示
        if igIsItemHovered(Imgui_HoveredFlagsDelayShort.cint) and igBeginTooltip():
          igText("[Open file]")
          const ary = [0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f]
          igPlotLines("Curve", ary, overlayText = "Overlay string")
          igText("Sin(time) = %.2f", sin(igGetTime()));
          igEndTooltip();
        let (_,fname,ext) = sFnameSelected.splitFile()
        igText("Selected file = %s", (fname & ext).cstring)
      # Counter up
      if igButton("Button", ImVec2(x: 0.0f, y: 0.0f)):
        inc counter
      igSameLine(0.0f, -1.0f)
      igText("counter = %d", counter)
      igText("Application average %.3f ms/frame (%.1f FPS)".cstring, (1000.0f / igGetIO().Framerate.float).cfloat, igGetIO().Framerate)
      igSeparatorText(ICON_FA_WRENCH & " Icon font test ")
      igText(ICON_FA_TRASH_CAN & " Trash")
      igText(ICON_FA_MAGNIFYING_GLASS_PLUS &
        " " & ICON_FA_POWER_OFF &
        " " & ICON_FA_MICROPHONE &
        " " & ICON_FA_MICROCHIP &
        " " & ICON_FA_VOLUME_HIGH &
        " " & ICON_FA_SCISSORS &
        " " & ICON_FA_SCREWDRIVER_WRENCH &
        " " & ICON_FA_BLOG)

    # show further samll window
    if showAnotherWindow:
      igBegin("imgui Another Window", addr showAnotherWindow, 0)
      igText("Hello from imgui")
      if igButton("Close me", ImVec2(x: 0.0f, y: 0.0f)):
        showAnotherWindow = false
      igEnd()

    discard igBegin("Father window", addr(showDemoWindow), cint(ImGui_WindowFlags_NoBackground) or cint(ImGui_WindowFlags_NoDecoration) or cint(ImGui_WindowFlags_AlwaysAutoResize))

    igPushStyleVar_Float(cint(ImGui_StyleVar_ChildRounding), 10)
    igPushStyleColor_U32(cint(ImGui_Col_ChildBg), ImU32(0x50eeee50))
    if igBeginChild_Str("child", ImVec2(x: 200 , y: 200), int(ImGuiChildFlags_None) or int(ImGui_ChildFlags_Border), cint(ImGuiWindowFlags_None)):
      igText("Sub window")

    igEndChild()
    igPopStyleVar(1)
    igPopStyleColor(1)

    igend()

    # render
    igRender()
    glClearColor(clearColor.elm.x, clearColor.elm.y, clearColor.elm.z, clearColor.elm.w)
    glClear(GL_COLOR_BUFFER_BIT)
    ImGui_ImplOpenGL3_RenderDrawData(igGetDrawData())

    if 0 != (pio.ConfigFlags and ImGui_ConfigFlags_ViewportsEnable.cint):
      var backup_current_window = glfwGetCurrentContext()
      igUpdatePlatformWindows()
      igRenderPlatformWindowsDefault(nil, nil)
      backup_current_window.makeContextCurrent()

    hWin.swapBuffers()
    if not showFirstWindow and not showDemoWindow and not showAnotherWindow:
      hwin.setWindowShouldClose(true) # End program

#------
# main
#------
main()
dinau commented 1 month ago

I don't know detail you want to do.
But comment out this line,

glfwWindowHint(GLFW_FLOATING, GLFW_TRUE)

works well ?

sxzxs commented 1 month ago

I want ceate a [topmost , transparent, MouseButtonPassthrough] window, So i can use drawlist to draw line. Now , setWindowAttrib(glfwWin, GLFWMouseButtonPassthrough, GLFW_TRUE) not work. I have use another win32 function to do this

msetTransparent(int(getWin32Window(glfwWin)), 255)
proc msetTransparent*(hwnd: int, alpha: range[0..255]) =
  ## Set the window to be translucent. A value of 0 sets the window to be fully
  ## transparent.
  SetWindowLongPtr(hwnd, GWL_EXSTYLE,
    WS_EX_TRANSPARENT or WS_EX_LAYERED or GetWindowLongPtr(hwnd, GWL_EXSTYLE))
  SetLayeredWindowAttributes(hwnd, 0, BYTE alpha, LWA_ALPHA)

image image

dinau commented 1 month ago

Sorry I'm not familiar with GLFW and ImGui,
so it would be better to try to use simple C++ program included ImGui project
whether it (topmost,transparent, etc) works well or not.
If it doesn't works well, you should ask ImGui author.

dinau commented 1 month ago

I've found this discussion in ImGui issue,
GLFW Mouse Passthrough Broken in Docking Branch
https://github.com/ocornut/imgui/issues/4635
So in Makefile added

OPT += --passC:-DGLFW_MOUSE_PASSTHROUGH

But it was no effect.

I think just set true in nim source file (based on your source code)

...
TransparentViewport = true
'''

is nearly your intentions by any chance?

tranparent_viewport

sxzxs commented 1 month ago

It seems that it is really a matter of compilation options.
if just set TransparentViewport = true , I can not draw line in screen. I have achieved a similar effect by using win32 to set the layered window above and mouse penetration.

import std/[strutils, math]
import nimgl/[opengl,glfw]

import imguin/[glfw_opengl]

import imguin/lang/imgui_ja_gryph_ranges

include /utils/setupFonts
include imguin/simple
import winim
import wNim

when defined(windows):
  import tinydialogs

const MainWinWidth = 1024
const MainWinHeight = 804

proc glfwSetWindowAttrib*(window: GLFWWindow, attrib: int32, value: int32): void {.importc: "glfwSetWindowAttrib".}

#--------------
# Configration
#--------------

#  .--------------------------------------------..---------.-----------------------.------------
#  |         Combination of flags               ||         |     Viewport          |
#  |--------------------------------------------||---------|-----------------------|------------
#  | fViewport | fDocking | TransparentViewport || Docking | Transparent | Outside | Description
#  |:---------:|:--------:|:-------------------:||:-------:|:-----------:|:-------:| -----------
#  |  false    | false    |     false           ||    -    |     -       |   -     |
#  |  false    | true     |     false           ||    v    |     -       |   -     | (Default): Only docking
#  |  true     | -        |     false           ||    v    |     -       |   v     | Docking and outside of viewport
#  |    -      | -        |     true            ||    v    |     v       |   -     | Transparent Viewport and docking
#  `-----------'----------'---------------------'`---------'-------------'---------'-------------
var
 fDocking = true
 fViewport = true
 TransparentViewport = false
 #
block:
  if TransparentViewport:
    fViewport = true
  if fViewport:
    fDocking = true

proc getWin32Window(window: GLFWWindow): uint64 {.importc: "glfwGetWin32Window".}

proc msetTransparent*(hwnd: int, alpha: range[0..255]) =
  ## Set the window to be translucent. A value of 0 sets the window to be fully
  ## transparent.
  SetWindowLongPtr(hwnd, GWL_EXSTYLE,
    WS_EX_TRANSPARENT or WS_EX_LAYERED or GetWindowLongPtr(hwnd, GWL_EXSTYLE))
  SetLayeredWindowAttributes(hwnd, 0, BYTE alpha, LWA_ALPHA)

#---------------------
# Forward definitions
#---------------------
proc winMain(hWin: glfw.GLFWWindow)

#------
# main
#------
proc main() =
  doAssert glfwInit()
  defer: glfwTerminate()

  if TransparentViewport:
    glfwWindowHint(GLFWVisible, GLFW_FALSE)

  glfwWindowHint(GLFWContextVersionMajor, 3)
  glfwWindowHint(GLFWContextVersionMinor, 3)
  glfwWindowHint(GLFWOpenglForwardCompat, GLFW_TRUE)
  glfwWindowHint(GLFWOpenglProfile, GLFW_OPENGL_CORE_PROFILE)
  glfwWindowHint(GLFWResizable, GLFW_TRUE)

  glfwWindowHint(GLFW_FLOATING, GLFW_TRUE)
  glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE)
  glfwWindowHint(GLFW_MAXIMIZED, GLFW_TRUE)
  glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE);
  #
  var glfwWin = glfwCreateWindow(MainWinWidth, MainWinHeight, "test")
  if glfwWin.isNil:
    quit(-1)

  #setWindowAttrib(glfwWin, GLFWMouseButtonPassthrough, GLFW_FALSE)
  setWindowAttrib(glfwWin, GLFW_DECORATED, GLFW_FALSE)

  echo uint64(getWin32Window(glfwWin))
  msetTransparent(int(getWin32Window(glfwWin)), 255)

  glfwWin.makeContextCurrent()
  defer: glfwWin.destroyWindow()

  glfwSwapInterval(1) # Enable vsync

  doAssert glInit() # OpenGL init

  # setup ImGui
  let context = igCreateContext(nil)
  defer: context.igDestroyContext()
  if fDocking:
    var pio = igGetIO()
    pio.ConfigFlags = pio.ConfigFlags or ImGui_ConfigFlags_DockingEnable.cint
    if fViewport:
      pio.ConfigFlags = pio.ConfigFlags or ImGui_ConfigFlags_ViewportsEnable.cint
      pio.ConfigViewports_NoAutomerge = false

  # GLFW + OpenGL
  const glsl_version = "#version 130" # GL 3.0 + GLSL 130
  doAssert ImGui_ImplGlfw_InitForOpenGL(cast[ptr GLFWwindow](glfwwin), true)
  defer: ImGui_ImplGlfw_Shutdown()
  doAssert ImGui_ImplOpenGL3_Init(glsl_version)
  defer: ImGui_ImplOpenGL3_Shutdown()
  glfwWin.winMain()

#---------
# winMain
#---------
proc winMain(hWin: glfw.GLFWWindow) =
  var
    showDemoWindow = true
    showAnotherWindow = false
    showFirstWindow = true
    fval = 0.5f
    counter = 0
    sBuf = newString(200)
    sFnameSelected{.global.}:string
    clearColor:ccolor

  if TransparentViewport:
    clearColor = ccolor(elm:(x:0f, y:0f, z:0f, w:0.0f)) # Transparent
  else:
    clearColor = ccolor(elm:(x:0f, y:0f, z:0f, w:0.0f)) # Transparent
    #clearColor = ccolor(elm:(x:0.25f, y:0.65f, z:0.85f, w:0.0f))

  igStyleColorsClassic(nil)

  # Add multibytes font
  discard setupFonts()

  var pio = igGetIO()

  # main loop
  while not hWin.windowShouldClose:
    glfwPollEvents()

    # start imgui frame
    ImGui_ImplOpenGL3_NewFrame()
    ImGui_ImplGlfw_NewFrame()
    igNewFrame()

    var windowcls = ImGuiWindowClass()
    windowcls.ViewportFlagsOverrideSet = int32(ImGuiViewportFlags_NoAutoMerge)

    # render window

    var main_view_port = igGetMainViewport()
    #[
    igSetNextWindowPos(struct_ImVec2(x: main_view_port.WorkPos.x, y: main_view_port.WorkPos.y), 0, struct_ImVec2(x: 0, y: 0))
    igSetNextWindowSize(struct_ImVec2(x: main_view_port.WorkSize.x, y: main_view_port.WorkSize.y), 0)
    if igBegin("render", addr(showDemoWindow), int(ImGuiWindowFlags_NoBackground) or int(ImGuiWindowFlags_NoTitleBar) or int(ImGuiWindowFlags_NoResize)):
        var list = igGetBackgroundDrawList(main_view_port)
        ImDrawList_AddLine(list, ImVec2(x: 200, y: 200), ImVec2(x: 1000, y: 1000), ImU32(0xeeeeeeee), 2.0)
    igEnd()
    ]#

    #ImDrawList_AddLine(igGetBackgroundDrawList(main_view_port), ImVec2(x: 200, y: 200), ImVec2(x: 1000, y: 1000), ImU32(0xeeeeeeee), 2.0)
    ImDrawList_AddLine(igGetForegroundDrawList_ViewportPtr(main_view_port), ImVec2(x: 200, y: 200), ImVec2(x: 1000, y: 1000), ImU32(0xeeeeeeee), 2.0)

    igSetNextWindowClass(addr(windowcls))
    if showDemoWindow:
      igShowDemoWindow(addr showDemoWindow)

    # show a simple window that we created ourselves.
    igSetNextWindowClass(addr(windowcls))
    if showFirstWindow:
      igBegin("Nim: Dear ImGui test with Futhark", addr showFirstWindow, 0)
      defer: igEnd()
      var s = "GLFW v" & $glfwGetVersionString()
      igText(s.cstring)
      s = "OpenGL v" & ($cast[cstring](glGetString(GL_VERSION))).split[0]
      igText(s.cstring)
      igInputTextWithHint("InputText" ,"Input text here" ,sBuf)
      s = "Input result:" & sBuf
      igText(s.cstring)
      igCheckbox("Demo window", addr showDemoWindow)
      igCheckbox("Another window", addr showAnotherWindow)
      igSliderFloat("Float", addr fval, 0.0f, 1.0f, "%.3f", 0)
      igColorEdit3("Background color", clearColor.array3, 0.ImGuiColorEditFlags)

      # Show file open dialog
      when defined(windows):
        if igButton("Open file", ImVec2(x: 0, y: 0)):
           sFnameSelected = openFileDialog("File open dialog", getCurrentDir() / "\0", ["*.nim", "*.nims"], "Text file")
        igSameLine(0.0f, -1.0f)
        # ヒント表示
        if igIsItemHovered(Imgui_HoveredFlagsDelayShort.cint) and igBeginTooltip():
          igText("[Open file]")
          const ary = [0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f]
          igPlotLines("Curve", ary, overlayText = "Overlay string")
          igText("Sin(time) = %.2f", sin(igGetTime()));
          igEndTooltip();
        let (_,fname,ext) = sFnameSelected.splitFile()
        igText("Selected file = %s", (fname & ext).cstring)
      # Counter up
      if igButton("Button", ImVec2(x: 0.0f, y: 0.0f)):
        inc counter
      igSameLine(0.0f, -1.0f)
      igText("counter = %d", counter)
      igText("Application average %.3f ms/frame (%.1f FPS)".cstring, (1000.0f / igGetIO().Framerate.float).cfloat, igGetIO().Framerate)
      igSeparatorText(ICON_FA_WRENCH & " Icon font test ")
      igText(ICON_FA_TRASH_CAN & " Trash")
      igText(ICON_FA_MAGNIFYING_GLASS_PLUS &
        " " & ICON_FA_POWER_OFF &
        " " & ICON_FA_MICROPHONE &
        " " & ICON_FA_MICROCHIP &
        " " & ICON_FA_VOLUME_HIGH &
        " " & ICON_FA_SCISSORS &
        " " & ICON_FA_SCREWDRIVER_WRENCH &
        " " & ICON_FA_BLOG)

    # show further samll window
    igSetNextWindowClass(addr(windowcls))
    if showAnotherWindow:
      igBegin("imgui Another Window", addr showAnotherWindow, 0)
      igText("Hello from imgui")
      if igButton("Close me", ImVec2(x: 0.0f, y: 0.0f)):
        showAnotherWindow = false
      igEnd()

    discard igBegin("Father window", addr(showDemoWindow), cint(ImGui_WindowFlags_NoBackground) or cint(ImGui_WindowFlags_NoDecoration) or cint(ImGui_WindowFlags_AlwaysAutoResize))

    igPushStyleVar_Float(cint(ImGui_StyleVar_ChildRounding), 10)
    igPushStyleColor_U32(cint(ImGui_Col_ChildBg), ImU32(0x50eeee50))
    if igBeginChild_Str("child", ImVec2(x: 200 , y: 200), int(ImGuiChildFlags_None) or int(ImGui_ChildFlags_Border), cint(ImGuiWindowFlags_None)):
      igText("Sub window")

    igEndChild()
    igPopStyleVar(1)
    igPopStyleColor(1)

    igend()

    # render
    igRender()
    glClearColor(clearColor.elm.x, clearColor.elm.y, clearColor.elm.z, clearColor.elm.w)
    glClear(GL_COLOR_BUFFER_BIT)
    ImGui_ImplOpenGL3_RenderDrawData(igGetDrawData())

    if 0 != (pio.ConfigFlags and ImGui_ConfigFlags_ViewportsEnable.cint):
      var backup_current_window = glfwGetCurrentContext()
      igUpdatePlatformWindows()
      igRenderPlatformWindowsDefault(nil, nil)
      backup_current_window.makeContextCurrent()

    hWin.swapBuffers()
    if not showFirstWindow and not showDemoWindow and not showAnotherWindow:
      hwin.setWindowShouldClose(true) # End program

#------
# main
#------
main()
dinau commented 1 month ago

Your code works well. But it is difficult for me :-)

sxzxs commented 1 month ago

always call this can avalible

        static ImGuiViewport* viewport = ImGui::GetMainViewport();
        viewport->Flags |= ImGuiViewportFlags_NoInputs;