Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to check if scrollbar is visible in the current window #7818

Closed
MayitaMayoso opened this issue Jul 25, 2024 · 6 comments
Closed

How to check if scrollbar is visible in the current window #7818

MayitaMayoso opened this issue Jul 25, 2024 · 6 comments

Comments

@MayitaMayoso
Copy link

MayitaMayoso commented Jul 25, 2024

Version/Branch of Dear ImGui:

Version 1.89.7, Branch: docking (master/docking/etc.)

Back-ends:

imgui_impl_glfw.cpp + imgui_impl_opengl3.cpp

Compiler, OS:

Debian 10 + GNUC

Question:

Is there a way to know if the scrollbar is visible other than pre-calculating if the size of the window / child window / frame exceeds the available region? Style has ScrollBarSize which I use for drawing some stuff but since the scrollbar only appears if there is something to scroll I was wondering if there is maybe any Getter I have missed when searching for an answer.

@ocornut
Copy link
Owner

ocornut commented Jul 25, 2024

Use ImGui::GetScrollMaxY() > 0.0f is there's scrolling, and window->ScrollbarY (imgui_internal.h) if there's a scrollbar. You can have a scrolling range without a scrollbar.

But it is also very likely that you may be facing a XY Problem because you normally should not need to know about this. Can you clarify/explain why do you want to know if a scrollbar is visible?

@MayitaMayoso
Copy link
Author

MayitaMayoso commented Jul 25, 2024

First of all thanks for the quick response as always. It worked perfectly!

I am doing some custom drawing within a child window. I have used the ScrollBarSize in order for the symbols to not go under the ScrollBar. But when there is no Scrollar you can see an empty space. I want to know if there is Scrollbar to decide if I deduce the size or not of the total size for my own calculations for the drawings.
image

@ocornut
Copy link
Owner

ocornut commented Jul 25, 2024

I want to know if there is Scrollbar to decide if I deduce the size or not of the total size for my own calculations for the drawings.

This seems to be a XY Problem indeed. You should not need to query scrollbar visibility.
You should call GetContentRegionAvail() instead to obtain the drawable size.

ImVec2 pos_min = ImGui::GetCursorScreenPos();
ImVec2 pos_max = pos_min + ImGui::GetContentRegionAvail();

If you are not sure what some positions/values are, draw them on screen:

ImGui::GetForegroundDrawList()->AddRect(pos_min, pos_max, IM_COL32(255, 0, 0, 255));

@MayitaMayoso
Copy link
Author

The problem is that I need the size of the scroll before ImGui knows there is a scroll(?). I begin with an empty child window and I get the available size. Next I use the DrawList functionalities to draw my elements. These calls are followed by moving the cursor in order to let ImGui know the space has been occupied and if exceeded the height of the window make the scrollbar appear.

void SymbolColorComponent::RenderSymbols()
{
	// Window parameters
	auto Style = ImGui::State(ImGuiCol_ChildBg, Color4::Grey(.5f, .1f));
	Vec2 WindowStart = ImGui::GetWindowPos() + ImGui::GetCursorPos();
	Vec2 WindowSize = ImGui::GetContentRegionAvail();
	ImGui::BeginChild(ImGui::GetID("Symbols"), WindowSize);
	if (ImGui::GetScrollMaxY())
	{
		WindowSize -= Vec2(ImGui::GetStyle().ScrollbarSize, 0.0f);
	}

	// Symbol parameters
	Vec2 SymbolStart = WindowStart - Vec2(0, ImGui::GetScrollY());
	Vec2 SymbolPos = SymbolStart;
	Vec2 SymbolSize(100);

	// Fixing symbol width to fit window span
	auto SymbolsHorizontalCount = std::floor(WindowSize.x / SymbolSize.x);
	SymbolSize.x += (WindowSize.x - SymbolSize.x * SymbolsHorizontalCount) / SymbolsHorizontalCount;

	ImGui::GetWindowDrawList()->PushClipRect(WindowStart, WindowStart + WindowSize);
	for (const auto& [Symbol, _] : mColors)
	{
		if (SymbolMatchFilter(Symbol))
		{
			RenderSymbol(Symbol, SymbolPos, SymbolSize);

			UpdateSymbol(Symbol, SymbolPos, SymbolSize);

			SymbolPos += SymbolSize * Vec2(1, 0);
			if (SymbolPos.x + SymbolSize.x > WindowStart.x + WindowSize.x + 1)
			{
				SymbolPos = Vec2(SymbolStart.x, SymbolPos.y + SymbolSize.y);
				ImGui::SetCursorPos(ImGui::GetCursorPos() + SymbolSize * Vec2(0, 1));
			}

			if (SymbolPos.y > WindowStart.y + WindowSize.y)
			{
				break;
			}
		}
	}
	ImGui::SetCursorPos(ImGui::GetCursorPos() + SymbolSize * Vec2(0, 1));
	ImGui::GetWindowDrawList()->PopClipRect();
	ImGui::EndChild();
}

@ocornut
Copy link
Owner

ocornut commented Jul 25, 2024

Some suggestions

(1)

Vec2 WindowStart = ImGui::GetWindowPos() + ImGui::GetCursorPos();

Use

Vec2 WindowStart = ImGui::GetCursorScreenPos()`

Avoid all functions returning local coordinates. They make everything more complicated.

Vec2 SymbolStart = WindowStart - Vec2(0, ImGui::GetScrollY());

This also simply:

Vec2 SymbolStart = ImGui::GetCursorScreenPos();

(2)
I don't understand your explanation above and I don't think you need to do most of this.
You only need to use GetCursorScreenPos() and GetContentRegionAvail().

(3)

These calls are followed by moving the cursor in order

This is illegal since 1.89: (#5548)

ImGui::SetCursorPos(ImGui::GetCursorPos() + SymbolSize * Vec2(0, 1));

You should do

ImGui::SetCursorPos(ImGui::GetCursorPos() + SymbolSize * Vec2(0, 1));
ImGui::Dummy({0,0});

or

ImGui::Dummy(SymbolSize * Vec2(0, 1));

See v1.89 release notes.

@ocornut
Copy link
Owner

ocornut commented Jul 25, 2024

In spite of multiple warnings in the comments, it has been such a recurrent issue that people are using GetWindowPos(), GetCursorPos() etc. they tend to be source of confusion and comlexity.

I have increased and boldened the warnings in comments. I have also moved next step forward by obsoleting GetContentRegionMax(), GetWindowContentRegionMin(), GetWindowContentRegionMax().

I have also reorganized headers a little bit to move GetContentRegionAvail() need to GetCursorScreenPos().
Those two functions are everyone's best friend and you really cater 99% of needs.
It will be my new crusade :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants