-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathResize Controls.ipf
374 lines (318 loc) · 12.2 KB
/
Resize Controls.ipf
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
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
#pragma rtGlobals=1 // Use modern global access method.
#pragma version=6.20 // shipped with Igor 6.20A
#pragma IgorVersion=6.1
#pragma moduleName=ResizeControls
// The ResizeControlsPanel procedure implements the resize behavior of individual controls in panel.
// When the panel is resized, each edge of each control is (optionally) moved or resized
// according to the selected mode.
//
// Controls can be moved relative to the panel's or subwindows' edges,
// or relative to user guides.
//
// A table-like editor of these behaviors is implemented by
// #include <Resize Controls Panel>
//
// After including Resize Controls Panel.ipf,
// call the ShowResizeControlsPanel() function to display the editor
// or choose "Edit Controls Resized Positions" from Igor's Panel menu.
//
// NOTE:
// Control resizing information is stored in each control's userData(ResizeControlsInfo),
// and the window resizing information is stored in the panel's userData(ResizeControlsInfo)
//
// Revision History:
// JP090429, version 6.1B07 (initial version)
// JP090612, version 6.1 (initial release) - Fixed FitControlsToPanel bug: didn't grow controls vertically.
// JP091022, version 6.12 - ListOfChildWindows now returns only windows that can contain controls,
// ResizeControlsHook no longer prevents other resize hooks from being called.
// JP091201, version 6.13 - Uses different technique for enforcing minimum size to avoid multiple Execute/P commands
// JP100922, version 6.20 - Revised comments.
//
// ++++++++ Public Constants
StrConstant ksResizeUserDataName= "ResizeControlsInfo"
StrConstant ksFixedFromLeft = "Left" // aka "Panel Left"
StrConstant ksFixedFromMiddle= "Middle"
StrConstant ksFixedFromRight= "Right"
StrConstant ksFixedFromTop = "Top"
StrConstant ksFixedFromCenter= "Center"
StrConstant ksFixedFromBottom= "Bottom"
// ++++++++ Public Structures
Constant kCurrentResizeInfoVersion= 1
Structure WMResizeInfo
int16 version // usually kCurrentResizeInfoVersion
// saved control or panel position
float originalLeft
float originalTop
float originalWidth
float originalHeight
int16 fixedWidth // for panel resize hook
int16 fixedHeight // for panel resize hook
// how to adjust each control edge after panel resize
char leftMode[64] // default is ksFixedFromLeft WITHOUT any appended ksPopArrowText
char rightMode[64] // default is ksFixedFromLeft
char topMode[64] // default is ksFixedFromTop
char bottomMode[64] // default is ksFixedFromTop
EndStructure
// ++++++++ Static (Private) Constants
// window edge-relative adjustment constants
static Function GetControlResizeInfo(panelName, controlName, resizeInfo)
String panelName, controlName
STRUCT WMResizeInfo &resizeInfo
Variable hadInfo= 0
String userdata = GetUserData(panelName, controlName, ksResizeUserDataName)
if( strlen(userData) )
hadInfo= 1
StructGet/S resizeInfo, userdata
// if( ResizeInfo.version < kCurrentResizeInfoVersion )
// here upgrade the structure to the current version
// endif
endif
// Defaults are (Top/Left)
if( strlen(resizeInfo.leftMode) == 0 )
resizeInfo.leftMode= ksFixedFromLeft
endif
if( strlen(resizeInfo.rightMode) == 0 )
resizeInfo.rightMode= ksFixedFromLeft
endif
if( strlen(resizeInfo.topMode) == 0 )
resizeInfo.topMode= ksFixedFromTop
endif
if( strlen(resizeInfo.bottomMode) == 0 )
resizeInfo.bottomMode= ksFixedFromTop
endif
return hadInfo
End
static Function GetGuideDelta(panelName,moveMode)
String panelName
String moveMode // something like "Guide UGV1"
Variable guideDelta= 0 // how much the guide has moved from its recorded position
String guideName= StringFromList(1,moveMode, " ")
String info= GuideInfo(panelName,guideName)
Variable currentPosition= NumberByKey("POSITION",info)
String userdataGuideInfo = GetUserData(panelName, "", ksResizeUserDataName+guideName) // GuideInfo recorded in userData, see SaveControlPositions
if( strlen(userdataGuideInfo) )
Variable originalPosition=NumberByKey("POSITION",userdataGuideInfo)
guideDelta= currentPosition-originalPosition
endif
return guideDelta
End
Static Function FitControlsToPanel(win)
String win
// We need the original size of window to compare with original positions of controls to generate offsets
STRUCT WMResizeInfo resizeInfo
String userdata = GetUserData(win, "", ksResizeUserDataName)
if( strlen(userdata) == 0 )
return 0
endif
StructGet/S resizeInfo, userdata
Variable originalWinWidth=resizeInfo.originalWidth // pixels
Variable originalWinHeight=resizeInfo.originalHeight // pixels
GetWindow $win wsizeDC // the new window size in pixels
Variable winWidth= V_right-V_left
Variable winHeight= V_bottom-V_top
// adjustment amounts in pixels
Variable deltaWidth= winWidth - originalWinWidth
Variable deltaHeight= winHeight - originalWinHeight
String controls= ControlNameList(win)
Variable i, n= ItemsInList(controls)
for( i=0; i<n; i+=1 )
String ctrlName= StringFromList(i,controls)
if( !GetControlResizeInfo(win, ctrlName, resizeInfo) )
continue
endif
Variable origLeft=resizeInfo.originalLeft
Variable origTop=resizeInfo.originalTop
Variable origWidth=resizeInfo.originalWidth
Variable origHeight=resizeInfo.originalHeight
Variable left= origLeft, top= origTop, width=origWidth, height= origHeight
String leftAdjust= resizeInfo.leftMode
String rightAdjust= resizeInfo.rightMode
String topAdjust= resizeInfo.topMode
String bottomAdjust= resizeInfo.bottomMode
strswitch(leftAdjust)
case ksFixedFromLeft:
break
case ksFixedFromRight:
left += deltaWidth
break
case ksFixedFromMiddle:
left += deltaWidth/2
break
default: // user guide
left +=GetGuideDelta(win,leftAdjust)
break
endswitch
Variable right= origLeft + origWidth
strswitch(rightAdjust)
case ksFixedFromLeft:
break
case ksFixedFromRight:
right += deltaWidth
break
case ksFixedFromMiddle:
right += deltaWidth/2
break
default: // user guide
right +=GetGuideDelta(win,rightAdjust)
break
endswitch
width = right-left
strswitch(topAdjust)
case ksFixedFromTop:
break
case ksFixedFromBottom:
top += deltaHeight
break
case ksFixedFromCenter:
top += deltaHeight/2
break
default: // user guide
top +=GetGuideDelta(win,topAdjust)
break
endswitch
Variable bottom= origTop+origHeight
strswitch(bottomAdjust)
case ksFixedFromTop:
break
case ksFixedFromBottom:
bottom += deltaHeight
break
case ksFixedFromCenter:
bottom += deltaHeight/2
break
default: // user guide
bottom +=GetGuideDelta(win,bottomAdjust)
break
endswitch
height= bottom-top
Variable sizeChange= CmpStr(leftAdjust,rightAdjust) != 0 || CmpStr(topAdjust,bottomAdjust) != 0
if( sizeChange )
ModifyControl $ctrlName, win=$win, pos={left,top},size={width,height}
else
ModifyControl $ctrlName, win=$win, pos={left,top}
endif
endfor
return 1
End
#if Exists("PanelResolution") != 3
Static Function PanelResolution(wName) // For compatibility with Igor 7
String wName
return 72
End
#endif
Static Function ComputeNewPanelSize(panelName,minWidthPixels, maxWidthPixels, minHeightPixels, maxHeightPixels, neededWidthPoints, neededHeightPoints)
String panelName
Variable minWidthPixels, maxWidthPixels, minHeightPixels, maxHeightPixels
Variable &neededWidthPoints, &neededHeightPoints // outputs
Variable resizeNeeded= 0
DoWindow $panelName
if( V_Flag )
Variable minWidthPoints= minWidthPixels * PanelResolution(panelName)/ScreenResolution
Variable maxWidthPoints= maxWidthPixels * PanelResolution(panelName)/ScreenResolution
Variable minHeightPoints= minHeightPixels * PanelResolution(panelName)/ScreenResolution
Variable maxHeightPoints= maxHeightPixels * PanelResolution(panelName)/ScreenResolution
GetWindow $panelName wsize
Variable widthPoints= V_right-V_left
Variable heightPoints= V_bottom-V_top
neededWidthPoints= min(max(widthPoints,minWidthPoints),maxWidthPoints)
neededHeightPoints= min(max(heightPoints,minHeightPoints),maxHeightPoints)
resizeNeeded= (neededWidthPoints != widthPoints) || (neededHeightPoints != heightPoints)
endif
return resizeNeeded
End
Static Function LimitPanelSize(panelName, minWidthPixels, maxWidthPixels, minHeightPixels, maxHeightPixels)
String panelName
Variable minWidthPixels, maxWidthPixels, minHeightPixels, maxHeightPixels
Variable neededWidthPoints,neededHeightPoints
Variable resizePending= ComputeNewPanelSize(panelName,minWidthPixels, maxWidthPixels, minHeightPixels, maxHeightPixels, neededWidthPoints, neededHeightPoints)
if( resizePending )
// Eventually: MoveWindow/W=$win V_left, V_top, V_left+neededWidthPoints, V_top+neededHeightPoints
// To prevent SetPanelSize commands from piling up, we set a flag that the minimizer has been scheduled to run.
// To avoid global variables, we use userdata on the window being resized.
String setPanelSizeScheduledStr= GetUserData(panelName,"","setPanelSizeScheduled") // "" if never set (means "no")
if( strlen(setPanelSizeScheduledStr) == 0 )
SetWindow $panelName, userdata(setPanelSizeScheduled)= "yes"
String cmd
String module= GetIndependentModuleName()+"#ResizeControls#"
sprintf cmd, "%sSetPanelSize(\"%s\",%g,%g,%g,%g)", module, panelName, minWidthPixels, maxWidthPixels, minHeightPixels, maxHeightPixels
Execute/P/Q cmd // after the functions stop executing, the SetPanelSize's call to MoveWindow will provoke another resize event.
endif
endif
return resizePending
End
Static Function SetPanelSize(panelName,minWidthPixels, maxWidthPixels, minHeightPixels, maxHeightPixels)
String panelName
Variable minWidthPixels, maxWidthPixels, minHeightPixels, maxHeightPixels
Variable resizeNeeded= 0
DoWindow $panelName
if( V_Flag )
Variable neededWidthPoints,neededHeightPoints
resizeNeeded= ComputeNewPanelSize(panelName,minWidthPixels, maxWidthPixels, minHeightPixels, maxHeightPixels, neededWidthPoints, neededHeightPoints)
if( resizeNeeded )
GetWindow $panelName wsize
MoveWindow/W=$panelName V_left, V_top, V_left+neededWidthPoints, V_top+neededHeightPoints
endif
SetWindow $panelName, userdata(setPanelSizeScheduled)= "" // allow another call to SetPanelSize().
endif
return resizeNeeded
End
// This is the hook function for resizing controls in client panels.
// We also use it for the editing panel itself
Static Function ResizeControlsHook(hs)
STRUCT WMWinHookStruct &hs
Variable statusCode= 0
String panelName= hs.winName
strswitch(hs.eventName)
case "activate":
case "deactivate":
SetWindow $panelName, userdata(setPanelSizeScheduled)= "" // avoid locking out calls to SetPanelSize().
break
case "resize":
// opposite of SetWindow $panelName userdata($ksResizeUserDataName)=userData
STRUCT WMResizeInfo resizeInfo
String userdata = GetUserData(panelName, "", ksResizeUserDataName)
Variable resizePending= 0
if( strlen(userdata) )
StructGet/S resizeInfo, userdata
Variable minWidth=resizeInfo.originalWidth // pixels
Variable minHeight=resizeInfo.originalHeight // pixels
Variable maxWidth= inf, maxHeight=inf
if( resizeInfo.fixedWidth )
maxWidth= minWidth
endif
if( resizeInfo.fixedHeight )
maxHeight= minHeight
endif
resizePending= LimitPanelSize(panelName,minWidth, maxWidth, minHeight, maxHeight)
endif
if( !resizePending ) // don't bother adjusting controls if another resize event is pending
String windows= ListOfChildWindows(panelName)
Variable i, n= ItemsInList(windows)
for(i=0; i<n; i+=1 )
String win= StringFromList(i,windows)
FitControlsToPanel(win)
endfor
endif
// statusCode=1 // don't shortcircuit other hooks.
break
endswitch
return statusCode
End
// only child windows that can contain controls.
Static Function/S ListOfChildWindows(hostWindow)
String hostWindow
String list= hostWindow+";"
Variable type= WinType(hostWindow)
if( (type == 1) || (type == 7) ) // list only panels and graphs
String subwindows= ChildWindowList(hostWindow)
Variable i, n= ItemsInList(subwindows)
for(i=0; i<n; i+=1 )
String subwindow= hostWindow+"#"+StringFromList(i,subwindows)
type= WinType(subwindow)
if( (type == 1) || (type == 7) ) // list only panels and graphs
list += ListOfChildWindows(subwindow)
endif
endfor
endif
return list
End