linebender / druid

A data-first Rust-native UI design toolkit.
https://linebender.org/druid/
Apache License 2.0
9.53k stars 569 forks source link

WindowSizePolicy::Content leaves a gap on Windows #2030

Open ghost opened 2 years ago

ghost commented 2 years ago

Building from git+https://github.com/linebender/druid.git?branch=master#b6d389dec1aaafb239e7f0e72caac0d9de4285b6.

For code,

use druid::widget::{TextBox};
use druid::{AppLauncher, Data, Lens, PlatformError, Widget, WidgetExt, WindowDesc};

#[derive(Clone, Data, Lens)]
struct State {
    input: String,
}

fn main() -> Result<(), PlatformError> {
    let main_window = WindowDesc::new(ui_builder())
        .show_titlebar(true)
        .window_size_policy(druid::WindowSizePolicy::Content);
    let initial_state = State { input: String::new() };
    AppLauncher::with_window(main_window)
        .launch(initial_state)
}

fn ui_builder() -> impl Widget<State> {
    TextBox::new()
        .lens(State::input)
        .fix_width(350.0)
}

When show_titlebar is true, the main window size is perfect: https://snipboard.io/d2U4pv.jpg

When show_titlebar is false, the main window size is too tall, leaving a gap between the text box and the bottom border of the main window: https://snipboard.io/1o9ts4.jpg

This bug only happens on Windows. On Macos, both cases are fine.

Windows version info: 20H2 (OS Build 19042.1288)


Additional info: height of the gap changes with font family. For example, after I changed textbox's font to the monospace family, the gap got visibly bigger.

HoNile commented 2 years ago

I've looked at this a bit and I can say that the issue come from content_insets which call GetWindowInfo. So GetWindowInfo under a certain height (if there is no title bar), return incorrect values (this is not linked to TextBox or font size).

On my computer the minimum height needs to get correct value information for a window is 39.0.

Example, the code below is fine and if we put bigger height than 39.0 it will work too:

use druid::widget::{TextBox};
use druid::{AppLauncher, Data, Lens, PlatformError, Widget, WidgetExt, WindowDesc};

#[derive(Clone, Data, Lens)]
struct State {
    input: String,
}

fn main() -> Result<(), PlatformError> {
    let main_window = WindowDesc::new(ui_builder())
        .show_titlebar(true)
        .window_size_policy(druid::WindowSizePolicy::Content);
    let initial_state = State { input: String::new() };
    AppLauncher::with_window(main_window)
        .launch(initial_state)
}

fn ui_builder() -> impl Widget<State> {
    TextBox::new()
        .lens(State::input)
        .fix_width(350.0)
        .fix_height(39.0)
}

I have tried others win32 functions, but they all give me the same height (GetClientRect, GetWindowRect and GetWindowPlacement).

HoNile commented 2 years ago

Looking at this I found that if there is no title bar, the window can't be resized to be not visible there is a minimum size, which I think is linked to (or cause) this issue.

Here a window with a title bar, resize to its minimum: title_min

And here without tile bar, resize to its minimum: no_title_min

I was not using druid::WindowSizePolicy::Content so there is no call to content_insets and GetWindowInfo.