forked from Bobbar/AttendanceVacation
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbasFormSize.bas
537 lines (346 loc) · 16.8 KB
/
basFormSize.bas
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
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
Attribute VB_Name = "basFormSize"
Option Explicit
' FormLayout()
' Resize a form and all its controls based on screen resolution.
' All controls are resized in TabIndex order. Advanced positioning lets you
' position a control based on the previous (in TabIndex order) control's
' newly resized coordinates. Set any control's Tag property to one of the
' following (without the quotes) to engage advanced positioning.
' "Fixed"
' The control will not be resized, but it will be repositioned.
' "Multiline"
' Some controls (Label, OptionButton, TextBox) are autosized
' based on the font width and/or height instead of the overall ratio,
' causing problems for multi-line controls that use word wrap. Use
' this to skip the font-based resizing and just use generic resizing.
' "Left"
' If the previous control is an OptionButton or CheckBox, align with
' its caption left. This lets you align "subitems".
' "Right"
' Position this control to the right of the previous control on the
' same line. If the control is a TextBox and the previous control is a
' Label, this setting will line them up vertically as well.
' "Label"
' If the previous control is a Label, this setting will move the label down
' slightly to align the text bottom.
' "Etched"
' Signifies an Etched label, which simulates the etched effect on
' disabled controls like checkboxes. To use this effect, set the main
' label's background to transparent, add a new label with the same
' caption, set its ForeColor to white, set its ZOrder behind the main
' label (send to back), and set its Tag property to Etched. Be sure
' the etched label is immediately after the main label in TabOrder.
' Parameters:
' pfrm
' The form to be resized.
' psngFontSize can be either:
' - The new font size for the form and all its controls. Font sizes can
' be multiples of 0.25.
' - A negative value (eg: -46) to calculate the new font size based on how
' many lines of text can fit on a full screen in the current resolution.
' 46 lines (-46) results in nice compact text. 41 lines (-41) results
' in a nice looking larger font. This is a great setting to expose to
' the user in some way. (But don't show them negatives!)
'
' Sample usage:
'
' Private Sub Form_Load()
' FormLayout Me, 2
' End Sub
'
Public Sub FormLayout(pfrm As Form, Optional ByVal psngFontSize As Single = -46)
Const Spacer = " "
Const OptionSpacer = "o"
Const CaptionLeftChar = " "
Const CaptionLeftOffset = 14
Dim sngOriginalFontSize As Single
Dim enScaleMode As ScaleModeConstants
Dim lngScaleLeft As Long
Dim lngScaleTop As Long
Dim lngScaleWidth As Long
Dim lngScaleHeight As Long
Dim lngLeft As Long
Dim lngTop As Long
Dim lngWidth As Long
Dim lngHeight As Long
Dim sngX As Single
Dim sngY As Single
Dim lngOldWidth As Long
Dim lngOldHeight As Long
Dim lngExtraWidth As Long
Dim lngExtraHeight As Long
Dim lngScreenHeight As Long
Dim lngLines As Long
Dim lngTabIndex() As Long
Dim i As Long
Dim iMax As Long
Dim ctl As Control
Dim ctlPrev As Control
Dim ctlEtched As Control
Dim lngSSTab As Long
Dim strCaption As String
Dim strCaptionPrev As String
Dim lngComboHeight As Long
With pfrm
' Remember starting font size (do nothing if it doesn't end up changing)
sngOriginalFontSize = .FontSize
' Save scale settings so we can set ScaleMode to Twips, greatly simplifying things
enScaleMode = .ScaleMode
If enScaleMode = vbUser Then
lngScaleLeft = .ScaleLeft
lngScaleTop = .ScaleTop
lngScaleWidth = .ScaleWidth
lngScaleHeight = .ScaleHeight
End If
.ScaleMode = vbTwips
' Get existing dimensions
lngOldWidth = .TextWidth(Spacer)
lngOldHeight = .TextHeight(Spacer)
lngExtraWidth = .Width - .ScaleWidth
lngExtraHeight = .Height - .ScaleHeight
' Calculate new font size based on lines of text per screen
If psngFontSize < 0 Then
lngLines = Abs(psngFontSize)
lngScreenHeight = Screen.Height
.FontSize = 6 ' Arbitrary minimum size
' Grow font until the screen holds < requested number of lines (one size too big)
' (psngFontSize retains the previous value, so it'll end up with the correct size)
Do
psngFontSize = .FontSize
' Font sizes have erratic increments; identify the next size up
.FontSize = .FontSize + 0.25
If psngFontSize = .FontSize Then .FontSize = .FontSize + 0.5
If psngFontSize = .FontSize Then .FontSize = .FontSize + 0.75
If psngFontSize = .FontSize Then .FontSize = .FontSize + 1
If psngFontSize = .FontSize Then Exit Do
Loop Until lngScreenHeight \ .TextHeight(Spacer) < lngLines
End If
' Commit to the new font size
.FontSize = psngFontSize
End With
' Do nothing if font size hasn't changed
If pfrm.FontSize <> sngOriginalFontSize Then
With pfrm
' Calculate ratios based on change in font size
sngX = .TextWidth(Spacer) / lngOldWidth
sngY = .TextHeight(Spacer) / lngOldHeight
' Resize form
lngWidth = .ScaleWidth * sngX + lngExtraWidth
lngHeight = .ScaleHeight * sngY + lngExtraHeight
' Center form if it was already centered, otherwise don't move it
If .Left <> (Screen.Width - .Width) \ 2 Then lngLeft = .Left Else lngLeft = (Screen.Width - lngWidth) \ 2
If .Top <> (Screen.Height - .Height) \ 2 Then lngTop = .Top Else lngTop = (Screen.Height - lngHeight) \ 2
.Move lngLeft, lngTop, lngWidth, lngHeight
' Identify TabIndex order
iMax = .Controls.Count - 1
End With
If iMax >= 0 Then
ReDim lngTabIndex(iMax)
For Each ctl In pfrm.Controls
' Resize lines & shapes now because they don't have a TabIndex
With ctl
Select Case TypeName(ctl)
Case "Line"
' Identify left offset (used for controls on an inactive SSTab tab)
If TypeName(.Container) = "SSTab" And .X1 < -1500 Then lngSSTab = 75000 Else lngSSTab = 0
.X1 = (.X1 + lngSSTab) * sngX - lngSSTab
.X2 = (.X2 + lngSSTab) * sngX - lngSSTab
.Y1 = .Y1 * sngY
.Y2 = .Y2 * sngY
iMax = iMax - 1
Case "Shape", "Image"
' Identify left offset (used for controls on an inactive SSTab tab)
If TypeName(.Container) = "SSTab" And .Left < -1500 Then lngSSTab = 75000 Else lngSSTab = 0
.Move (.Left + lngSSTab) * sngX - lngSSTab, .Top * sngY, .Width * sngX, .Height * sngY
iMax = iMax - 1
Case Else
On Error Resume Next
lngTabIndex(.TabIndex) = i
If Err.Number <> 0 Then iMax = iMax - 1
On Error GoTo 0
' Identify ComboBox height
If TypeOf ctl Is ComboBox And lngComboHeight = 0 Then
.FontSize = pfrm.FontSize
lngComboHeight = ctl.Height
End If
End Select
End With
i = i + 1
Next
' Identify standard textbox height now to speed up loop
If lngComboHeight = 0 Then lngComboHeight = pfrm.TextHeight(Spacer) + 4 * Screen.TwipsPerPixelY
' Iterate controls in TabIndex order
For i = 0 To iMax
Set ctl = pfrm.Controls(lngTabIndex(i))
Select Case TypeName(ctl)
Case "OptionButton", "CheckBox": strCaption = Replace(Replace(Replace(ctl.Caption, "&&", "~"), "&", ""), "~", "&")
End Select
If i <> 0 Then
Set ctlPrev = pfrm.Controls(lngTabIndex(i - 1))
Select Case TypeName(ctlPrev)
Case "OptionButton", "CheckBox": strCaptionPrev = Replace(Replace(Replace(ctlPrev.Caption, "&&", "~"), "&", ""), "~", "&")
End Select
If ctl.Tag = "Etched" Then Set ctlEtched = pfrm.Controls(lngTabIndex(i - 1))
End If
With ctl
' Identify left offset (used for controls on an inactive SSTab tab)
If TypeName(.Container) = "SSTab" And .Left < -1500 Then lngSSTab = 75000 Else lngSSTab = 0
' Identify current dimensions
lngLeft = .Left + lngSSTab
lngTop = .Top
lngWidth = .Width
lngHeight = .Height
' LEFT
Select Case .Tag
Case "Left"
Select Case TypeName(ctlPrev)
Case "OptionButton", "CheckBox": lngLeft = ctlPrev.Left + CaptionLeftOffset * Screen.TwipsPerPixelX + pfrm.TextWidth(CaptionLeftChar)
Case Else: lngLeft = ctlPrev.Left
End Select
Case "Right"
Select Case TypeName(ctlPrev)
Case "OptionButton", "CheckBox": lngLeft = ctlPrev.Left + (CaptionLeftOffset + 1) * Screen.TwipsPerPixelX + pfrm.TextWidth(strCaptionPrev) + pfrm.TextWidth(OptionSpacer)
Case Else: lngLeft = ctlPrev.Left + ctlPrev.Width + pfrm.TextWidth(Spacer)
End Select
Case "Etched": lngLeft = ctlPrev.Left + Screen.TwipsPerPixelX
Case Else: lngLeft = lngLeft * sngX
End Select
' TOP
Select Case .Tag
Case "Etched": lngTop = ctlPrev.Top + Screen.TwipsPerPixelY
Case Else: lngTop = lngTop * sngY
End Select
' WIDTH
Select Case .Tag
Case "Fixed"
Case "MultiLine": lngWidth = lngWidth * sngX
Case "Etched": lngWidth = ctlPrev.Width
Case Else
Select Case TypeName(ctl)
Case "OptionButton", "CheckBox": lngWidth = CaptionLeftOffset * Screen.TwipsPerPixelX + 2 * pfrm.TextWidth(CaptionLeftChar) + pfrm.TextWidth(strCaption)
Case "TextBox": If .MaxLength <> 0 Then lngWidth = pfrm.TextWidth("8") * (.MaxLength + 1) Else lngWidth = lngWidth * sngX
Case Else: lngWidth = lngWidth * sngX
End Select
End Select
' HEIGHT
Select Case .Tag
Case "Fixed"
Case "MultiLine": lngHeight = lngHeight * sngY
Case "Etched": lngHeight = ctlPrev.Height
Case Else
Select Case TypeName(ctl)
Case "OptionButton", "CheckBox": lngHeight = lngComboHeight
Case "ListBox"
lngLines = ctl.Height \ lngOldHeight
lngHeight = pfrm.TextHeight(Spacer) * lngLines + ctl.Height - (lngLines * lngOldHeight)
Case "TextBox": lngHeight = lngComboHeight
Case Else: lngHeight = lngHeight * sngY
End Select
End Select
' Apply new formatting
On Error Resume Next
.Font.Size = pfrm.FontSize
On Error GoTo 0
Select Case TypeName(ctl)
Case "Label"
Select Case .Tag
Case "MultiLine", "Etched"
Case Else
.AutoSize = True
lngHeight = .Height
Select Case .Alignment
Case vbRightJustify: If lngWidth < .Width Then lngLeft = lngLeft - (.Width - lngWidth)
Case vbCenter: If lngWidth < .Width Then lngLeft = lngLeft - (.Width - lngWidth) \ 2
End Select
lngWidth = .Width
End Select
.Move lngLeft, lngTop, lngWidth, lngHeight
Case "ComboBox"
lngComboHeight = .Height
.Move lngLeft, lngTop, lngWidth
Case Else
.Move lngLeft, lngTop, lngWidth, lngHeight
End Select
' Check for vertical align
If i <> 0 Then
If TypeOf ctlPrev Is Label Then
Select Case .Tag
Case "Label", "Right"
' If previous control is an Etched label, move both labels
If ctlPrev.Tag = "Etched" Then
ctlEtched.Top = ctl.Top + 3 * Screen.TwipsPerPixelY
ctlPrev.Top = ctlEtched.Top + Screen.TwipsPerPixelY
Else
ctlPrev.Top = ctl.Top + 3 * Screen.TwipsPerPixelY
End If
End Select
End If
End If
End With
Set ctl = Nothing
Next
Set ctlPrev = Nothing
Set ctlEtched = Nothing
End If
End If
' Reset ScaleMode to original settings
With pfrm
If enScaleMode = vbUser Then
.ScaleLeft = lngScaleLeft
.ScaleTop = lngScaleTop
.ScaleWidth = lngScaleWidth
.ScaleHeight = lngScaleHeight
Else
.ScaleMode = enScaleMode
End If
End With
End Sub
Public Function GetOptionCaptionLeft(popt As OptionButton) As Long
Const Pixels = 15
Const Char = " "
GetOptionCaptionLeft = popt.Left + Pixels * Screen.TwipsPerPixelX + popt.Parent.TextWidth(Char)
End Function
Public Function GetOptionHeight(popt As OptionButton) As Long
Const Pixels = 4
Const Char = "Q"
With popt.Parent
GetOptionHeight = Pixels * Screen.TwipsPerPixelX + .TextHeight(Char)
End With
End Function
Public Function GetOptionRight(popt As OptionButton) As Long
Const Pixels = 15
Const Char = " "
Dim strCaption As String
strCaption = popt.Caption & Char
strCaption = Replace(strCaption, "&&", "~")
strCaption = Replace(strCaption, "&", "")
strCaption = Replace(strCaption, "~", "&")
With popt.Parent
GetOptionRight = popt.Left + Pixels * Screen.TwipsPerPixelX + .TextWidth(strCaption)
End With
End Function
Public Function GetOptionWidth(popt As OptionButton) As Long
Const Pixels = 14
Const Char = " "
Dim strCaption As String
strCaption = popt.Caption & Char
strCaption = Replace(strCaption, "&&", "~")
strCaption = Replace(strCaption, "&", "")
strCaption = Replace(strCaption, "~", "&")
With popt.Parent
GetOptionWidth = Pixels * Screen.TwipsPerPixelX + .TextWidth(strCaption)
End With
End Function
Public Function OptionButtonCaptionLeft(popt As OptionButton) As Long
Const Pixels = 14
Const Char = " "
OptionButtonCaptionLeft = popt.Left + (Pixels * Screen.TwipsPerPixelX) + popt.Parent.TextWidth(Char)
End Function
Public Function StripAcceleratorKeys(pstrCaption As String) As String
Dim strReturn As String
strReturn = pstrCaption
strReturn = Replace(strReturn, "&&", "~")
strReturn = Replace(strReturn, "&", "")
strReturn = Replace(strReturn, "~", "&")
StripAcceleratorKeys = strReturn
End Function