Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

lwiklendt
Copy link
Contributor

Proposed solution to issue #525

@sanbox-irl
Copy link
Member

Don't mind this @lwiklendt, but is there a reason we shouldn't just expose an &Style in the UI? This does add some maintenance burden onto the repo

@lwiklendt
Copy link
Contributor Author

I don't understand myself why originally &Style wasn't exposed. I think maybe @Gekkio wrote the clone version Ui::clone_style(&self) -> Style but I don't know how to get to the "0.1-dev" branch to see if there's a reason given. I agree if there are no problems, a Ui::style(&self) -> &Style would certainly be preferable.

@sanbox-irl
Copy link
Member

sanbox-irl commented Sep 20, 2021

Okay, I have some answers for you on why it's set up the way it is -- effectively, we violate memory safety if we give an &Style.

I created this simple program:

        let style = ui.style();
        let _t = ui.push_style_var(imgui::StyleVar::Alpha(0.2));

        let new_style = ui.style();

        println!(
            "equals, {}\n{:?}\n{:?}",
            style == new_style,
            style,
            new_style
        );

    // in ui...
    pub fn style(&self) -> &crate::Style {
        self.ctx.style()
    }

My expectation was that this would yield true and alpha in the style struct would be set to 1.0, the global default. Unfortunately, it yielded true, but with alpha at 0.2. This means that we held the immutable pointer to the C++ style struct in style while ImGui was mutating it when we called push_style_var. Obviously, we can't do, since the compiler will mess with this tremendously with optimizations it believes to be sound.

I think we have three options:

  1. accept this PR with the negative side effects referenced
  2. change the signature of style to &mut self, and yet return an &crate::Style (imgui's docs are explicit that we should not write to this data after calling NewFrame -- I assume push_style_var also does other work in addition to writing to this struct). This is kind of funky, since really push style var should be marked as mutable. I'd like to more to eventually have the ui methods use &mut self at some point, but our drop token method makes this complex.
  3. We can use a getter function that takes StyleVar and match on that -- it already corresponds (I believe) to each field in the style struct, so that gives us a compile time warning as we update imgui.
  4. give access to a raw ptr with some scare quotes in a safety doc. This can be accepted in addition to others.

What do you think?

@thomcc
Copy link
Member

thomcc commented Sep 20, 2021

I like 2, but I suspect it could require massive changes to peoples codebase to use. 3 and 4 might be the best option. Unfortunately, IIRC the style can be a number of different types, which... complicates things.

@lwiklendt
Copy link
Contributor Author

lwiklendt commented Sep 20, 2021

In the spirit of 3, there could be a Ui::get_style_var(&self, style_var: &mut StyleVar) where you supply (with dummy data) the variant you want to retrieve which gets filled with the correct data. It's probably not very "rusty" but it is kind of "imgui-y" considering functions like Ui::checkbox(&self, label: impl AsRef<str>, value: &mut bool) -> bool that take a mutable reference, albeit not with dummy data.

Although not all Style fields are represented by StyleVar. From imgui.h "The enum only refers to fields of ImGuiStyle which makes sense to be pushed/popped inside UI code". For example, Style::color_button_position is not represented in StyleVar.

@sanbox-irl
Copy link
Member

Although not all Style fields are represented by StyleVar. From imgui.h "The enum only refers to fields of ImGuiStyle which makes sense to be pushed/popped inside UI code". For example, Style::color_button_position is not represented in StyleVar.

I think that pretty much kills option 3.

I like 2, but I suspect it could require massive changes to peoples codebase to use. 3 and 4 might be the best option. Unfortunately, IIRC the style can be a number of different types, which... complicates things.

I suspect this is all correct -- I mostly pass around &Ui<'_> in my app, which just prevents this mutable thing from working.

I think a larger conversation about mutability in the codebase will have to wait, but for now, I'm in favor of accepting the PR as is with the addition of 4 (we will likely forget to update these functions as the style struct changes at some point, which we should endeavor to not do, but having the emergency escape of 4 will be useful).

@lwiklendt would you mind adding that option 4? should return a *const Style with safety docs indicating that it will never be non-null but that it may be mutated by dear imgui (and should never be recast to a *mut and mutated through). See here if you want to copy some rhetoric: https://github.com/ocornut/imgui/blob/master/imgui.h#L301

@thomcc
Copy link
Member

thomcc commented Sep 20, 2021

A better option might be an unsafe fn that returns a &Style that you arent allowed to hold across other calls into imgui, since it may be mutated. That's easier to document, at least.

@@ -173,4 +173,15 @@ impl<'ui> Ui<'ui> {
pub fn style_color(&self, style_color: StyleColor) -> [f32; 4] {
self.ctx.style()[style_color]
}
/// Returns a shared reference to the current [`Style`]. This function is tagged as `unsafe`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should note that users who would like to avoid unsafe can use clone_style().

/// [`ColorStackToken::pop`](crate::ColorStackToken::pop) or
/// [`StyleStackToken::pop`](crate::StyleStackToken::pop) will modify the values in the returned
/// shared reference. Therefore, you should not retain this reference across calls to push and
/// pop. The [`clone_style`](Ui::clone_style) version may instead be used to avoid `unsafe`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

apologies for the specifics, but can you format this as:

Returns a shared reference to the current [`Style`].

## Safety

This function is tagged as `unsafe`...etc

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries, it's good to keep a clean uniform style.

@sanbox-irl
Copy link
Member

left one comment, once that's resolved, good to merge. Thank you and apologies that you ran into hotel order issue of mutability of the Ui object. I have some ideas but wow they;'d be a lot of breaking changes

@sanbox-irl
Copy link
Member

Thank you!

@sanbox-irl sanbox-irl merged commit 7660776 into imgui-rs:main Sep 21, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants