-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathwindows.resize.go
267 lines (239 loc) · 10.1 KB
/
windows.resize.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
package imgui
const WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER float = 0.04 // Reduce visual noise by only highlighting the border after a certain time.
// Data for resizing from corner
type ImGuiResizeGripDef struct {
CornerPosN ImVec2
InnerDir ImVec2
AngleMin12, AngleMax12 int
}
var resize_grip_def = [4]ImGuiResizeGripDef{
{ImVec2{1, 1}, ImVec2{-1, -1}, 0, 3}, // Lower-right
{ImVec2{0, 1}, ImVec2{+1, -1}, 3, 6}, // Lower-left
{ImVec2{0, 0}, ImVec2{+1, +1}, 6, 9}, // Upper-left (Unused)
{ImVec2{1, 0}, ImVec2{-1, +1}, 9, 12}, // Upper-right (Unused)
}
// Data for resizing from borders
type ImGuiResizeBorderDef struct {
InnerDir ImVec2
SegmentN1, SegmentN2 ImVec2
OuterAngle float
}
var resize_border_def = [4]ImGuiResizeBorderDef{
{ImVec2{+1, 0}, ImVec2{0, 1}, ImVec2{0, 0}, IM_PI * 1.00}, // Left
{ImVec2{-1, 0}, ImVec2{1, 0}, ImVec2{1, 1}, IM_PI * 0.00}, // Right
{ImVec2{0, +1}, ImVec2{0, 0}, ImVec2{1, 0}, IM_PI * 1.50}, // Up
{ImVec2{0, -1}, ImVec2{1, 1}, ImVec2{0, 1}, IM_PI * 0.50}, // Down
}
func CalcResizePosSizeFromAnyCorner(window *ImGuiWindow, corner_target, corner_norm *ImVec2, out_pos, out_size *ImVec2) {
a := window.Pos.Add(window.Size)
var pos_min = ImLerpVec2WithVec2(corner_target, &window.Pos, *corner_norm) // Expected window upper-left
var pos_max = ImLerpVec2WithVec2(&a, corner_target, *corner_norm) // Expected window lower-right
var size_expected = pos_max.Sub(pos_min)
var size_constrained = CalcWindowSizeAfterConstraint(window, &size_expected)
*out_pos = pos_min
if corner_norm.x == 0.0 {
out_pos.x -= (size_constrained.x - size_expected.x)
}
if corner_norm.y == 0.0 {
out_pos.y -= (size_constrained.y - size_expected.y)
}
*out_size = size_constrained
}
func GetResizeBorderRect(window *ImGuiWindow, border_n int, perp_padding, thickness float) ImRect {
var rect = window.Rect()
if thickness == 0.0 {
rect.Max = rect.Max.Sub(ImVec2{1, 1})
}
if border_n == int(ImGuiDir_Left) {
return ImRect{ImVec2{rect.Min.x - thickness, rect.Min.y + perp_padding}, ImVec2{rect.Min.x + thickness, rect.Max.y - perp_padding}}
}
if border_n == int(ImGuiDir_Right) {
return ImRect{ImVec2{rect.Max.x - thickness, rect.Min.y + perp_padding}, ImVec2{rect.Max.x + thickness, rect.Max.y - perp_padding}}
}
if border_n == int(ImGuiDir_Up) {
return ImRect{ImVec2{rect.Min.x + perp_padding, rect.Min.y - thickness}, ImVec2{rect.Max.x - perp_padding, rect.Min.y + thickness}}
}
if border_n == int(ImGuiDir_Down) {
return ImRect{ImVec2{rect.Min.x + perp_padding, rect.Max.y - thickness}, ImVec2{rect.Max.x - perp_padding, rect.Max.y + thickness}}
}
IM_ASSERT(false)
return ImRect{}
}
// Handle resize for: Resize Grips, Borders, Gamepad
// Return true when using auto-fit (double click on resize grip)
func UpdateWindowManualResize(window *ImGuiWindow, size_auto_fit *ImVec2, border_held *int, resize_grip_count int, resize_grip_col *[4]ImU32, visibility_rect *ImRect) bool {
var g = GImGui
var flags = window.Flags
if (flags&ImGuiWindowFlags_NoResize != 0) || (flags&ImGuiWindowFlags_AlwaysAutoResize != 0) || window.AutoFitFramesX > 0 || window.AutoFitFramesY > 0 {
return false
}
if !window.WasActive { // Early out to avoid running this code for e.g. an hidden implicit/fallback Debug window.
return false
}
var ret_auto_fit = false
var resize_border_count int
if g.IO.ConfigWindowsResizeFromEdges {
resize_border_count = 4
}
var grip_draw_size = IM_FLOOR(ImMax(g.FontSize*1.35, window.WindowRounding+1.0+g.FontSize*0.2))
var grip_hover_inner_size = IM_FLOOR(grip_draw_size * 0.75)
var grip_hover_outer_size float
if g.IO.ConfigWindowsResizeFromEdges {
grip_hover_outer_size = WINDOWS_HOVER_PADDING
}
var pos_target = ImVec2{FLT_MAX, FLT_MAX}
var size_target = ImVec2{FLT_MAX, FLT_MAX}
// Resize grips and borders are on layer 1
window.DC.NavLayerCurrent = ImGuiNavLayer_Menu
// Manual resize grips
PushString("#RESIZE")
for resize_grip_n := int(0); resize_grip_n < resize_grip_count; resize_grip_n++ {
var def = &resize_grip_def[resize_grip_n]
size := window.Pos.Add(window.Size)
var corner = ImLerpVec2WithVec2(&window.Pos, &size, def.CornerPosN)
// Using the FlattenChilds button flag we make the resize button accessible even if we are hovering over a child window
var hovered, held bool
var resize_rect = ImRect{corner.Sub(def.InnerDir.Scale(grip_hover_outer_size)), corner.Add(def.InnerDir.Scale(grip_hover_inner_size))}
if resize_rect.Min.x > resize_rect.Max.x {
resize_rect.Min.x, resize_rect.Max.x = resize_rect.Max.x, resize_rect.Min.x
}
if resize_rect.Min.y > resize_rect.Max.y {
resize_rect.Min.y, resize_rect.Max.y = resize_rect.Max.y, resize_rect.Min.y
}
var resize_grip_id = window.GetIDInt(resize_grip_n) // == GetWindowResizeCornerID()
ButtonBehavior(&resize_rect, resize_grip_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren|ImGuiButtonFlags_NoNavFocus)
//GetForegroundDrawList(window).AddRect(resize_rect.Min, resize_rect.Max, IM_COL32(255, 255, 0, 255));
if hovered || held {
if resize_grip_n&1 != 0 {
g.MouseCursor = ImGuiMouseCursor_ResizeNESW
} else {
g.MouseCursor = ImGuiMouseCursor_ResizeNWSE
}
}
if held && g.IO.MouseDoubleClicked[0] && resize_grip_n == 0 {
// Manual auto-fit when double-clicking
size_target = CalcWindowSizeAfterConstraint(window, size_auto_fit)
ret_auto_fit = true
ClearActiveID()
} else if held {
// Resize from any of the four corners
// We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position
var clamp_min = ImVec2{-FLT_MAX, -FLT_MAX}
if def.CornerPosN.x == 1.0 {
clamp_min.x = visibility_rect.Min.x
}
if def.CornerPosN.y == 1.0 {
clamp_min.y = visibility_rect.Min.y
}
var clamp_max = ImVec2{+FLT_MAX, +FLT_MAX}
if def.CornerPosN.x == 0 {
clamp_max.x = visibility_rect.Max.x
}
if def.CornerPosN.y == 0 {
clamp_max.y = visibility_rect.Max.y
}
ls := def.InnerDir.Scale(grip_hover_outer_size)
rs := def.InnerDir.Scale(-grip_hover_inner_size)
var corner_target = g.IO.MousePos.Sub(g.ActiveIdClickOffset).Add(
ImLerpVec2WithVec2(&ls, &rs, def.CornerPosN)) // Corner of the window corresponding to our corner grip
corner_target = ImClampVec2(&corner_target, &clamp_min, clamp_max)
CalcResizePosSizeFromAnyCorner(window, &corner_target, &def.CornerPosN, &pos_target, &size_target)
}
// Only lower-left grip is visible before hovering/activating
if resize_grip_n == 0 || held || hovered {
var c = ImGuiCol_ResizeGrip
if held {
c = ImGuiCol_ResizeGripActive
} else {
if hovered {
c = ImGuiCol_ResizeGripHovered
}
}
resize_grip_col[resize_grip_n] = GetColorU32FromID(c, 1)
}
}
for border_n := ImGuiDir(0); border_n < ImGuiDir(resize_border_count); border_n++ {
var def = &resize_border_def[border_n]
var axis = ImGuiAxis_Y
if border_n == ImGuiDir_Left || border_n == ImGuiDir_Right {
axis = ImGuiAxis_X
}
var hovered, held bool
var border_rect = GetResizeBorderRect(window, int(border_n), grip_hover_inner_size, WINDOWS_HOVER_PADDING)
var border_id = window.GetIDInt(int(border_n) + 4) // == GetWindowResizeBorderID()
ButtonBehavior(&border_rect, border_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren)
//GetForegroundDrawLists(window).AddRect(border_rect.Min, border_rect.Max, IM_COL32(255, 255, 0, 255));
if (hovered && g.HoveredIdTimer > WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER) || held {
if axis == ImGuiAxis_X {
g.MouseCursor = ImGuiMouseCursor_ResizeEW
} else {
g.MouseCursor = ImGuiMouseCursor_ResizeNS
}
if held {
*border_held = int(border_n)
}
}
if held {
var clamp_min = ImVec2{-FLT_MAX, -FLT_MAX}
if border_n == ImGuiDir_Right {
clamp_min.x = visibility_rect.Min.x
}
if border_n == ImGuiDir_Down {
clamp_min.y = visibility_rect.Min.y
}
var clamp_max = ImVec2{+FLT_MAX, +FLT_MAX}
if border_n == ImGuiDir_Left {
clamp_max.x = visibility_rect.Max.x
}
if border_n == ImGuiDir_Up {
clamp_max.y = visibility_rect.Max.y
}
var border_target = window.Pos
switch axis {
case ImGuiAxis_X:
border_target.x = g.IO.MousePos.x - g.ActiveIdClickOffset.x + WINDOWS_HOVER_PADDING
case ImGuiAxis_Y:
border_target.y = g.IO.MousePos.y - g.ActiveIdClickOffset.y + WINDOWS_HOVER_PADDING
}
border_target = ImClampVec2(&border_target, &clamp_min, clamp_max)
min := ImMinVec2(&def.SegmentN1, &def.SegmentN2)
CalcResizePosSizeFromAnyCorner(window, &border_target, &min, &pos_target, &size_target)
}
}
PopID()
// Restore nav layer
window.DC.NavLayerCurrent = ImGuiNavLayer_Main
// Navigation resize (keyboard/gamepad)
if g.NavWindowingTarget != nil && g.NavWindowingTarget.RootWindow == window {
var nav_resize_delta ImVec2
if g.NavInputSource == ImGuiInputSource_Keyboard && g.IO.KeyShift {
nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard, ImGuiInputReadMode_Down, 0, 0)
}
if g.NavInputSource == ImGuiInputSource_Gamepad {
nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadDPad, ImGuiInputReadMode_Down, 0, 0)
}
if nav_resize_delta.x != 0.0 || nav_resize_delta.y != 0.0 {
const NAV_RESIZE_SPEED float = 600
nav_resize_delta = nav_resize_delta.Scale(ImFloor(NAV_RESIZE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y)))
yd := visibility_rect.Min.Sub(window.Pos).Sub(window.Size)
nav_resize_delta = ImMaxVec2(&nav_resize_delta, &yd)
g.NavWindowingToggleLayer = false
g.NavDisableMouseHover = true
resize_grip_col[0] = GetColorU32FromInt(uint(ImGuiCol_ResizeGripActive))
// FIXME-NAV: Should store and accumulate into a separate size buffer to handle sizing constraints properly, right now a constraint will make us stuck.
desired := window.SizeFull.Add(nav_resize_delta)
size_target = CalcWindowSizeAfterConstraint(window, &desired)
}
}
// Apply back modified position/size to window
if size_target.x != FLT_MAX {
window.SizeFull = size_target
MarkIniSettingsDirtyWindow(window)
}
if pos_target.x != FLT_MAX {
window.Pos = *ImFloorVec(&pos_target)
MarkIniSettingsDirtyWindow(window)
}
window.Size = window.SizeFull
return ret_auto_fit
}