6#include <imgui_internal.h>
12 const ImVec4* colours = ImGui::GetStyle().Colors;
13 const ImVec2 p = GetCursorScreenPos();
14 ImDrawList* draw_list = GetWindowDrawList();
16 const float height = GetFrameHeight();
17 const float width = height * 1.55f;
18 const float radius = height * 0.50f;
20 if (InvisibleButton(str_id, ImVec2(width, height))) {
25 if (ImGui::IsItemHovered()) {
27 draw_list->AddCircleFilled(ImVec2(p.x + radius + (*v ? 1 : 0) * (width - radius * 2.0f), p.y + radius), radius - 1.5f, ImGui::GetColorU32(colours[ImGuiCol_ButtonHovered]));
30 draw_list->AddCircleFilled(ImVec2(p.x + radius + (*v ? 1 : 0) * (width - radius * 2.0f), p.y + radius), radius - 1.5f, ImGui::GetColorU32(colours[ImGuiCol_ButtonActive]));
61 bool ImageZoomAndPan(
ImTextureID user_texture_id,
const ImVec2& size,
float aspectRatio,
float& zoom, ImVec2& zoomCenter,
int panMouseButtonDrag,
int resetZoomAndPanMouseButton,
const ImVec2& zoomMaxAndZoomStep)
64 ImGuiWindow* window = GetCurrentWindow();
65 if (!window || window->SkipItems)
return rv;
66 ImVec2 curPos = ImGui::GetCursorPos();
67 const ImVec2 wndSz(size.x > 0 ? size.x : ImGui::GetWindowSize().x - curPos.x, size.y > 0 ? size.y : ImGui::GetWindowSize().y - curPos.y);
69 IM_ASSERT(wndSz.x != 0 && wndSz.y != 0 && zoom != 0);
72 ImRect bb(window->DC.CursorPos, ImVec2(window->DC.CursorPos.x + wndSz.x, window->DC.CursorPos.y + wndSz.y));
74 if (!ItemAdd(bb, 0))
return rv;
76 ImVec2 imageSz = wndSz;
77 ImVec2 remainingWndSize(0, 0);
78 if (aspectRatio != 0) {
79 const float wndAspectRatio = wndSz.x / wndSz.y;
80 if (aspectRatio >= wndAspectRatio) { imageSz.y = imageSz.x / aspectRatio; remainingWndSize.y = wndSz.y - imageSz.y; }
81 else { imageSz.x = imageSz.y * aspectRatio; remainingWndSize.x = wndSz.x - imageSz.x; }
84 if (ImGui::IsItemHovered()) {
85 const ImGuiIO& io = ImGui::GetIO();
86 if (io.MouseWheel != 0) {
88 const float zoomStep = zoomMaxAndZoomStep.y;
89 const float zoomMin = 1.f;
90 const float zoomMax = zoomMaxAndZoomStep.x;
91 if (io.MouseWheel < 0) { zoom /= zoomStep;
if (zoom < zoomMin) zoom = zoomMin; }
92 else { zoom *= zoomStep;
if (zoom > zoomMax) zoom = zoomMax; }
111 const bool scrollDown = io.MouseWheel <= 0;
112 const float zoomFactor = .5f / zoom;
113 if ((!scrollDown && zoomCenter.y > zoomFactor) || (scrollDown && zoomCenter.y < 1.f - zoomFactor)) {
114 const float slideFactor = zoomMaxAndZoomStep.y * 0.1f * zoomFactor;
116 zoomCenter.y += slideFactor;
117 if (zoomCenter.y > 1.f - zoomFactor) zoomCenter.y = 1.f - zoomFactor;
120 zoomCenter.y -= slideFactor;
121 if (zoomCenter.y < zoomFactor) zoomCenter.y = zoomFactor;
127 if (io.MouseClicked[resetZoomAndPanMouseButton]) { zoom = 1.f; zoomCenter.x = zoomCenter.y = .5f; rv =
true; }
128 if (ImGui::IsMouseDragging(panMouseButtonDrag, 1.f)) {
129 zoomCenter.x -= io.MouseDelta.x / (imageSz.x * zoom);
130 zoomCenter.y -= io.MouseDelta.y / (imageSz.y * zoom);
132 ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
136 const float zoomFactor = .5f / zoom;
138 if (zoomCenter.x < zoomFactor) zoomCenter.x = zoomFactor;
139 else if (zoomCenter.x > 1.f - zoomFactor) zoomCenter.x = 1.f - zoomFactor;
140 if (zoomCenter.y < zoomFactor) zoomCenter.y = zoomFactor;
141 else if (zoomCenter.y > 1.f - zoomFactor) zoomCenter.y = 1.f - zoomFactor;
144 ImVec2 uvExtension(2.f * zoomFactor, 2.f * zoomFactor);
145 if (remainingWndSize.x > 0) {
146 const float remainingSizeInUVSpace = 2.f * zoomFactor * (remainingWndSize.x / imageSz.x);
147 const float deltaUV = uvExtension.x;
148 const float remainingUV = 1.f - deltaUV;
150 float adder = (remainingUV < remainingSizeInUVSpace ? remainingUV : remainingSizeInUVSpace);
151 uvExtension.x += adder;
152 remainingWndSize.x -= adder * zoom * imageSz.x;
153 imageSz.x += adder * zoom * imageSz.x;
155 if (zoomCenter.x < uvExtension.x * .5f) zoomCenter.x = uvExtension.x * .5f;
156 else if (zoomCenter.x > 1.f - uvExtension.x * .5f) zoomCenter.x = 1.f - uvExtension.x * .5f;
159 if (remainingWndSize.y > 0) {
160 const float remainingSizeInUVSpace = 2.f * zoomFactor * (remainingWndSize.y / imageSz.y);
161 const float deltaUV = uvExtension.y;
162 const float remainingUV = 1.f - deltaUV;
164 float adder = (remainingUV < remainingSizeInUVSpace ? remainingUV : remainingSizeInUVSpace);
165 uvExtension.y += adder;
166 remainingWndSize.y -= adder * zoom * imageSz.y;
167 imageSz.y += adder * zoom * imageSz.y;
169 if (zoomCenter.y < uvExtension.y * .5f) zoomCenter.y = uvExtension.y * .5f;
170 else if (zoomCenter.y > 1.f - uvExtension.y * .5f) zoomCenter.y = 1.f - uvExtension.y * .5f;
174 ImVec2 uv0((zoomCenter.x - uvExtension.x * .5f), (zoomCenter.y - uvExtension.y * .5f));
175 ImVec2 uv1((zoomCenter.x + uvExtension.x * .5f), (zoomCenter.y + uvExtension.y * .5f));
186 ImVec2 startPos = bb.Min, endPos = bb.Max;
187 startPos.x += remainingWndSize.x * .5f;
188 startPos.y += remainingWndSize.y * .5f;
189 endPos.x = startPos.x + imageSz.x;
190 endPos.y = startPos.y + imageSz.y;
192 window->DrawList->AddImage(user_texture_id, startPos, endPos, uv0, uv1);
static const ImVec4 Colours[]
static const ImVec4 ColoursHovered[]
bool ImageZoomAndPan(ImTextureID user_texture_id, const ImVec2 &size, float aspectRatio, float &zoom, ImVec2 &zoomCenter, int panMouseButtonDrag, int resetZoomAndPanMouseButton, const ImVec2 &zoomMaxAndZoomStep)
bool ToggleButton(const char *str_id, bool *v)