hoffstadt / DearPyGui

Dear PyGui: A fast and powerful Graphical User Interface Toolkit for Python with minimal dependencies
https://dearpygui.readthedocs.io/en/latest/
MIT License
12.94k stars 676 forks source link

Draw list placed below title bar in window but rectangle pmin [0, 0] is placed correctly #1550

Open michaelis79 opened 2 years ago

michaelis79 commented 2 years ago

Version of Dear PyGui

Version: 1.2.3 Operating System: Windows 10

My Issue/Question

The draw list is placed underneath the windows titlebar. But the rectangle with pmin [0, 0] is correctly draw in top left corner just below the title bar. So there is a mismatch between draw list and rectangle coordinates. Problem disappears when there is no title bar. The coordinates in the bottom left corner is of the drawlist when mouse is on title bar.

Screenshots/Video

image

Standalone, minimal, complete and verifiable example

import dearpygui.dearpygui as dpg

SUITABLE_STATUSBAR_HEIGHT = 36 # centers the default font vertically, 2022-01-14
STATUSBAR_OFFSET_FROM_BOTTOM = 72 # offset from viewport bottom, 2022-01-14

def viewport_resize_callback(sender, app_data, user_data):
    dpg.set_item_pos('statusbar', [0, dpg.get_viewport_height()-72])
    dpg.set_item_width('statusbar', dpg.get_viewport_width())

def mouse_move_callback(sender, app_data, user_data):
    # for showing mouse pos only when cursor in drawing area
    mouse_x, mouse_y = app_data
    pos_x, pos_y = dpg.get_item_pos(item='draw_window')

    x = mouse_x - pos_x
    y = mouse_y - pos_y

    # if outside draw list then don't show coordinates
    if x < 0 or y < 0 or x > dpg.get_item_width(item='drawlist') or y > dpg.get_item_height(item='drawlist'):
        x = ''
        y = ''

    dpg.set_value(item='statbartext', value=f'x: {x} , y: {y}')

if __name__ == '__main__':
    dpg.create_context()
    dpg.create_viewport(title='Bombus', width=500, height=500)

    dpg.set_viewport_resize_callback(viewport_resize_callback)

    with dpg.window(tag='draw_window', width=400.0, height=400.0, pos=[20.0, 20.0], no_title_bar=True):
        with dpg.drawlist(width=400.0, height=400.0, tag='drawlist', parent='draw_window'):
            dpg.draw_rectangle(pmin=[0.0, 0.0], pmax=[400.0, 400.0])

    with dpg.window(width=100, height=SUITABLE_STATUSBAR_HEIGHT,
                    tag='statusbar',
                    min_size=[dpg.get_viewport_width(), SUITABLE_STATUSBAR_HEIGHT],
                    max_size=[2560, SUITABLE_STATUSBAR_HEIGHT],
                    no_title_bar=True,
                    no_move=True):
        dpg.add_text(default_value='', tag='statbartext')

    with dpg.handler_registry():
        dpg.add_mouse_move_handler(callback=mouse_move_callback)

    # dpg.bind_item_handler_registry(item='drawarea', handler_registry='mouse_move')

    dpg.show_style_editor()

    dpg.setup_dearpygui()
    dpg.show_viewport()
    dpg.start_dearpygui()
    dpg.destroy_context()
hoffstadt commented 2 years ago

Hi, shouldn't you have to subtract the title bar height?

darwinharianto commented 2 years ago

Sorry, How can i get the title bar height?

lukaslcf commented 1 year ago

Sorry for reviving a dead thread after a year, but I am running into the same issue. Did you find any solution in the end @darwinharianto ?

v-ein commented 1 year ago

I've just looked at the source code and DPG doesn't seem to report the height of the title bar. However, ImGui does have an internal-looking function for that (i.e. not API), and the title bar height is always computed as (font_size + 2 * frame_padding.y).

You can get the font size via dpg.get_text_size("") - without text, should probably work even on the 1st frame, but maybe won't - try it out. Worst case you'll need a 1-frame delay of your initialization.

As for the frame padding, I'm not sure if there's a way to retrieve it, but certainly you can set it to your own value and use that value; or you can rely on ImGui's default value of 3 pixels (don't forget to multiply by 2 per the formula above).

    FramePadding            = ImVec2(4,3);      // Padding within a framed rectangle (used by most widgets)

Note that on high DPI screens, like Retina found on MacBook, those 3 pixels might get scaled to 6 - I don't have a Mac and can't check it right away. ImGui's code contains a function to do that scaling, but I couldn't find any real calls to it, so maybe it's not scaled after all.

lukaslcf commented 1 year ago

Thanks a lot for the reply. It is very informative. I tried and it seems to work quite well. Indeed, for high DPI monitors, pixels need to be multiplied by 2.

On 2 Feb 2023, at 16:39, Vladimir Ein @.***> wrote:

 I've just looked at the source code and DPG doesn't seem to report the height of the title bar. However, ImGui does have an internal-looking function for that (i.e. not API), and the title bar height is always computed as (font_size + 2 * frame_padding.y).

You can get the font size via dpg.get_text_size("") - without text, should probably work even on the 1st frame, but maybe won't - try it out. Worst case you'll need a 1-frame delay of your initialization.

As for the frame padding, I'm not sure if there's way to retrieve it, but certainly you can set it to your own value and use that value; or you can rely on ImGui's default value of 3 pixels (don't forget to multiply by 2 per the formula above).

FramePadding            = ImVec2(4,3);      // Padding within a framed rectangle (used by most widgets)

Note that on high DPI screens, like Retina found on MacBook, those 3 pixels might get scaled to 6 - I don't have a Mac and can't check it right away; ImGui's code contais a function to do that but I couldn't find any real calls to it.

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.

v-ein commented 1 year ago

Glad that it worked!

Bad news about scaling: it's not a hard-coded "2", but a value computed somewhere inside of ImGui, and it seems DPG can't tell you that value.

In ImGui, it's stored in the variable io.DisplayFramebufferScale, and its value is computed differently for different backends (e.g. GLFW vs. Marmalade). Here's a comment that says it's either 1 or 2, but I'm not sure how much one can rely on it:

    ImVec2          FramebufferScale;       // Amount of pixels for each unit of DisplaySize. Based on io.DisplayFramebufferScale. Generally (1,1) on normal display, (2,2) on OSX with Retina display.

There's a function in DPG named get_global_font_scale() but it seems to be unrelated to this scaling.

Ideally, in your case you'd need a new function in DPG that would return the display scale (probably a part of get_app_configuration()), or a function that would return the title bar size, or both.

I'll probably dive deeper into this scaling mess later on because I'm getting weird results on Retina, but unfortunately it's not on my near-term plans.