-
Notifications
You must be signed in to change notification settings - Fork 1
/
maxguiex.bmx
1715 lines (1541 loc) · 52.8 KB
/
maxguiex.bmx
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
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
Rem
bbdoc: Maxgui Extended Functions
about:
<p>This is a module to add extended functionality to the maxgui module. Most of the functions work for windows and mac (sorry no linux) but please check documentation for each function to confirm support for the platform.</p>
<p><b>Important!</b><br />The module requires the skn3.systemex module and skn3.funcs module.</p>
End Rem
Module skn3.maxguiex
SuperStrict
ModuleInfo "History: 1.06"
ModuleInfo "History: added CreatePanelEx() function which creates an extended panel that can have new cool stuff"
ModuleInfo "History: added SetPanelExGradient() function to set gradient backgrounds for extended panels"
ModuleInfo "History: 1.05"
ModuleInfo "History: added PointOverGadget() function"
ModuleInfo "History: 1.04"
ModuleInfo "History: fixed broken GadgetWindow() function"
ModuleInfo "History: 1.03"
ModuleInfo "History: Added GetAppResourcesPath() and tweaked h files"
ModuleInfo "History: 1.02"
ModuleInfo "History: Added ScrollTextAreaToTop() ScrollTextAreaToBottom() ScrollTextAreaToCursor() functions"
ModuleInfo "History: 1.01"
ModuleInfo "History: Added SetTextAreaLineSpacing() function"
ModuleInfo "History: 1.00"
ModuleInfo "History: Initial Release To Public"
'platform stuff
?Win32
Import brl.map
Import brl.linkedlist
Import maxgui.drivers
Import skn3.systemex
Extern "Win32"
Function skn3_clientToScreen:Int( hwnd:Int, point:Long Var) = "ClientToScreen@8"
Function skn3_loadCursorFromFile:Int(path$w) = "LoadCursorFromFileW@4"
Function skn3_destroyCursor:Int(hcursor:Int) = "DestroyCursor@4"
Function skn3_addFontResourceEx:Int(path$w,fl:Int,pdv:Int) = "AddFontResourceExW@12"
Function skn3_addFontMemResourceEx:Int(pbFont:Byte Ptr,cbFont:Int,pdv:Int,pcFonts:Byte Ptr) = "AddFontMemResourceEx@16"
Function skn3_sendMessagePtr:Int(hwnd:Int,MSG:Int,wParam:Byte Ptr,lParam:Byte Ptr) = "SendMessageW@16"
End Extern
Const BCM_GETIDEALSIZE:Int = BCM_FIRST + 1
Const BCM_GETTEXTMARGIN:Int = BCM_FIRST + 5
Const FR_PRIVATE:Int = 16
Private
Rem
bbdoc: A private type to store the state of a locked listbox.
about:
<b>Supported Platforms</b>
<ul>
<li>Windows</li>
</ul>
<b>Info</b>
<p>See #ListBatchLock, #ListBatchAdd and #ListBatchUnlock.</p>
End Rem
Type Skn3ListBatchLock
Global all:TList
Field refCount:Int
Field listBox:TWindowsListBox
Field index:Int
Field link:TLink
Field it:LVITEMW
Field hwnd:Int
Function Find:Skn3ListBatchLock(Gadget:TGadget)
' --- find existing lock ---
If all = Null Return Null
Local listBoxLock:Skn3ListBatchLock
Local listBoxLockLink:TLink = all.FirstLink()
While listBoxLockLink
'get lock
listBoxLock = Skn3ListBatchLock(listBoxLockLink.value())
'check for already locked
If listBoxLock.listBox = Gadget Return listBoxLock
'next lock
listBoxLock = Skn3ListBatchLock(listBoxLockLink.value())
Wend
End Function
Function add(Lock:Skn3ListBatchLock)
' --- add a new lock ---
If all = Null all = CreateList()
Lock.link = all.AddLast(Lock)
End Function
Function remove(Lock:Skn3ListBatchLock)
' --- remove a lock ---
If Lock
Lock.link.remove()
Lock.listBox = Null
lock.it = Null
EndIf
End Function
End Type
Public
?MacOs
Import "maxguiex.m"
Import brl.map
Import brl.linkedlist
Import maxgui.drivers
Import skn3.systemex
Extern "macos"
Function skn3_absoluteFrom:Int[](gadget:Int)
Function skn3_stringDimensions:Int[](Gadget:Int,text:String,Width:Float)
Function skn3_setWindowAlwaysOnTop(Window:Int,State:Int)
Function skn3_bringWindowToTop(Window:Int)
Function skn3_focusWindow(Window:Int)
Function skn3_setReadOnly(gadget:Int,yes:Int)
Function skn3_setMaxLength(gadget:Int,length:Int)
Function skn3_getMaxLength:Int(gadget:Int)
Function skn3_loadCustomPointer:Int(path:String,cursorX:Int,cursorY:Int)
Function skn3_setCustomPointer:Int(cursor:Int)
Function skn3_freeCustomPointer:Int(cursor:Int)
Function skn3_currentCursor:Int()
Function skn3_setColorPickerCustomColors(colors:Int[])
Function skn3_removeScrollViewBorder(Gadget:Int)
Function skn3_removeTextFieldBorder(Gadget:Int)
Function skn3_installFontFromFileWithATS:Int(text:String)
Function skn3_installFontFromFileWithCT:Int(text:String)
Function skn3_setTextViewLineSpacing:Int(Gadget:Int,spacing:Float)
Function skn3_scrollTextAreaToTop(Gadget:Int)
Function skn3_scrollTextAreaToBottom(Gadget:Int)
Function skn3_scrollTextAreaToCursor(Gadget:Int)
Function skn3_getBundlePath:String()
Function skn3_panelExInit(gadget:TNSGadget)
Function skn3_panelExSetGradient(gadget:TNSGadget,on:Int,r1:Int,g1:Int,b1:Int,r2:Int,g2:Int,b2:Int,vertical:Int)
EndExtern
?
Rem
bbdoc: An object that stores a custom cursor file.
about:
<b>Supported Platforms</b>
<ul>
<li>Windows</li>
<li>Mac</li>
</ul>
<b>Info</b>
<p>This should be passed to #SetCustomPointer and #FreeCustomPointer.</p>
End Rem
Type Skn3CustomPointer
Global all:TMap
Field path:String
Field pointer:Int
Field refCount:Int
End Type
Private
Rem
bbdoc: A windows data structure.
about:
<b>Supported Platforms</b>
<ul>
<li>Windows</li>
</ul>
<b>Info</b>
<p>This is for modifying the rich edit control.</p>
End Rem
Type PARAFORMAT2
Field cbSize:Int
Field dwMask:Int
Field wNumbering:Short
Field wEffects:Short
Field dxStartIndent:Int
Field dxRightIndent:Int
Field dxOffset:Int
Field wAlignment:Short
Field cTabCount:Short = 32
Field rgxTabs00:Int,rgxTabs01:Int,rgxTabs02:Int,rgxTabs03:Int
Field rgxTabs10:Int,rgxTabs11:Int,rgxTabs12:Int,rgxTabs13:Int
Field rgxTabs20:Int,rgxTabs21:Int,rgxTabs22:Int,rgxTabs23:Int
Field rgxTabs30:Int,rgxTabs31:Int,rgxTabs32:Int,rgxTabs33:Int
Field rgxTabs40:Int,rgxTabs41:Int,rgxTabs42:Int,rgxTabs43:Int
Field rgxTabs50:Int,rgxTabs51:Int,rgxTabs52:Int,rgxTabs53:Int
Field rgxTabs60:Int,rgxTabs61:Int,rgxTabs62:Int,rgxTabs63:Int
Field rgxTabs70:Int,rgxTabs71:Int,rgxTabs72:Int,rgxTabs73:Int
Field dySpaceBefore:Int
Field dySpaceAfter:Int
Field dyLineSpacing:Int
Field sStyle:Short
Field bLineSpacingRule:Byte
Field bOutlineLevel:Byte
Field wShadingWeight:Short
Field wShadingStyle:Short
Field wNumberingStart:Short
Field wNumberingStyle:Short
Field wNumberingTab:Short
Field wBorderSpace:Short
Field wBorderWidth:Short
Field wBorders:Short
End Type
Public
'internal functions
Private
Function TrimAndFixPath:String(path:String,slash:String="/",keepRootSlash:Int=False)
'--- fix a path ---
'check for no path
If path.Length = 0 Return ""
'fix slashes
path = path.Replace("\","/")
If slash <> "/" path = path.Replace("/",slash)
'trim slashes
Local index:Int
Local startIndex:Int = 0
Local hasRootSlash:Int = False
Local slashAsc:Int = Asc(slash)
For index = 0 Until path.length
If path[index] <> 32 And path[index] <> slashAsc Exit
startIndex = index+1
hasRootSlash = True
Next
Local length:Int = path.length-startIndex
For index = path.Length-1 To 0 Step -1
If path[index] <> 32 And path[index] <> slashAsc Exit
length :- 1
Next
If length <= 0 Return ""
'build new path
path = path[startIndex..startIndex+Length]
If hasRootSlash And keepRootSlash path = slash+path
'return the result
Return path
End Function
Function IncBinToDisk:String(path:String)
' --- just a helper function for copying an incbin to disk ---
If path[0..8].Tolower() = "incbin::"
'setup real path
Local pathBase:String = TrimAndFixPath(GetTempDirectory(),"/",True)+"/"
Local pathCount:String = ""
Local pathFile:String = StripDir(path[8..])
While FileType(pathBase+pathCount+pathFile)
pathCount = Int(pathCount)+1
Wend
'create final path
Local path2:String = pathBase+pathCount+pathFile
'copy file to temporary location
Local in:TStream = ReadStream(path)
If in = Null Return ""
Local out:TStream = WriteStream(path2)
If out = Null
CloseStream(in)
Return ""
EndIf
CopyStream(in,out)
CloseFile(out)
CloseStream(in)
'return temp path
Return path2
EndIf
'Return fail
Return ""
End Function
Function PointInRect:Int(pointX:Float,pointY:Float,rectX:Float,rectY:Float,rectWidth:Float,rectHeight:Float)
' --- returns true if point is inside rect ---
Return pointX >= rectX And pointX < rectX + rectwidth And pointY >= rectY And pointY < rectY + rectHeight
End Function
Public
'api functions
Rem
bbdoc: Request the size of the scrollbars for the current operating system. <b>[Win Mac Linux]</b>
returns: An int.
about:
<b>Supported Platforms</b>
<ul>
<li>Windows</li>
<li>Mac</li>
<li>Linux</li>
</ul>
<b>Info</b>
<p>This function currently uses a hard coded value.</p>
End Rem
Function RequestScrollbarSize:Int()
' --- return the scrollbar size ---
'just hardcode this for now
Return 18
End Function
Rem
bbdoc: Change the height of a combobox. <b>[Win]</b>
about:
<b>Supported Platforms</b>
<ul>
<li>Windows</li>
</ul>
<b>Info</b>
<p>This changes the height of the combobox gadget.</p>
End Rem
Function SetComboBoxHeight(comboBox:TGadget,Height:Int)
' --- resize a combo box to exact proportions ---
?Win32
'windows 7 + vista combobox height should be -6 (not tested on XP)
SendMessageA(QueryGadget(comboBox,1),CB_SETITEMHEIGHT,-1,Height-6)
RedrawGadget(comboBox)
?
End Function
Rem
bbdoc: Get the screen position of a gadget. <b>[Win Mac]</b>
returns: An int array with 2 elements. 0 = x, 1 = y
about:
<b>Supported Platforms</b>
<ul>
<li>Windows</li>
<li>Mac</li>
</ul>
<b>Info</b>
<p>This function gets the desktop x,y position of a given gadget.</p>
End Rem
Function GadgetScreenPosition:Int[](gadget:TGadget,client:Int=False)
' --- get the screen position of a gadget ---
?Win32
Local point:Long
If client
skn3_clientToScreen(Gadget.Query(QUERY_HWND_CLIENT),point)
Else
skn3_clientToScreen(Gadget.Query(QUERY_HWND),point)
EndIf
Local Position:Int[2]
Position[0] = Int Ptr( Varptr point)[0]
Position[1] = Int Ptr( Varptr point)[1]
?MacOs
Local Position:Int[] = skn3_absoluteFrom(QueryGadget(gadget,QUERY_NSVIEW_CLIENT))
?
Return Position
End Function
Rem
bbdoc: Determin if a point is over a gadget. <b>[Win]</b>
returns: True if over the target gadget.
about:
<b>Supported Platforms</b>
<ul>
<li>Windows</li>
<li>Mac</li>
</ul>
<b>Info</b>
<p>If a source gadget is provided it is assumed that the pointX and pointY are local coordinates for that source gadget (for example: local coordinates given in EVENT_MOUSEMOVE).</p>
<p>If no source is provided teh function will assume the point is already in screen coordinates.</p>
End Rem
Function PointOverGadget:Int(pointX:Int,pointY:Int,targetGadget:TGadget,sourceGadget:TGadget=Null)
' --- returns true if the point is over the gadget ---
'check for skipping
If targetGadget = Null Or GadgetHidden(targetGadget) Return False
'calculate point if source gadget is provided
If sourceGadget
Local sourcePosition:Int[] = GadgetScreenPosition(sourceGadget)
pointX = sourcePosition[0] + pointX
pointY = sourcePosition[1] + pointY
EndIf
'get dimensions for gadget
Local targetPosition:Int[] = GadgetScreenPosition(targetGadget)
'test
Return PointInRect(pointX,pointY,targetPosition[0],targetPosition[1],GadgetWidth(targetGadget),GadgetHeight(targetGadget))
End Function
Rem
bbdoc: Disable redrawing of a gadget. <b>[Win]</b>
returns: True if operation was supported by system.
about:
<b>Supported Platforms</b>
<ul>
<li>Windows</li>
</ul>
<b>Info</b>
<p>This will disable any redraw operations on the gadget. This call must be followed by #EnableGadgetRedraw to reenable painting.</p>
<p>It is not required to disable gadget redrawing on mac as this is partly handled by the operating system anyway!</p>
End Rem
Function DisableGadgetRedraw:Int(gadget:TGadget)
' --- change a gadget repaint ability ---
'returns true if the system allowed the operation
?Win32
SendMessageW(QueryGadget(gadget,QUERY_HWND),WM_SETREDRAW,False,0)
Return True
?
End Function
Rem
bbdoc: Enable redraw of the specified gadget. <b>[Win]</b>
returns: True if operation was supported by system.
about:
<b>Supported Platforms</b>
<ul>
<li>Windows</li>
</ul>
<b>Info</b>
<p>This will renable redraw operations on a gadget. Remember to call RedrawGadget(gadget) after this so that your gadget paints any changes you have made. A good way to code this in a cross platform fashion is to see if #EnableGadgetRedraw returns true in which case the operating system allowed the operation and the gadget needs repainting. Redrawing can be disabled using #DisableGadgetRedraw.</p>
End Rem
Function EnableGadgetRedraw:Int(gadget:TGadget)
' --- change a gadget repaint ability ---
'returns true if the system allowed the operation
?Win32
SendMessageW(QueryGadget(gadget,QUERY_HWND),WM_SETREDRAW,True,0)
Return True
?
End Function
Rem
bbdoc: Open a system message box with title and message. <b>[Win Mac Linux]</b>
about:
<b>Supported Platforms</b>
<ul>
<li>Windows</li>
<li>Mac</li>
<li>Linux</li>
</ul>
<b>Info</b>
<p>This uses the built in blitzmax Notify command but changes the apptitle to enable custom titles.</p>
End Rem
Function MessageBox(title:String,message:String,parent:TGadget=Null)
' --- create a system message box ---
'For now we will just fake it
Local oldTitle:String = AppTitle
AppTitle = title
Notify(message,False)
AppTitle = oldTitle
End Function
Rem
bbdoc: Get the size a gadget should be with the given text and max width. <b>[Win Mac]</b>
returns: An int array with 2 elements. 0 = x, 1 = y
about:
<b>Supported Platforms</b>
<ul>
<li>Windows</li>
<li>Mac</li>
</ul>
<b>Info</b>
<p>This function is very powerful and will let you resize your gadgets according to the text within! If you provide a max width then the function will work out the width and height for your gadget confined to that max width. If no max width is provided then the function will return a very wide gadget dimension</p>
<p>If this function is used with a button that has images then this will be taken into account. The function currently is well supported for buttons and labels! Other gadgets may not work as well!</p>
End Rem
Function GadgetSizeForString:Int[](gadget:TGadget,text:String,maxWidth:Int=0)
' --- get dimensions of a string using the gadget as a context ---
?Win32
'get device context to the gadget
Local hwnd:Int = QueryGadget(gadget,QUERY_HWND)
'do stuff based on gadget class
Select GadgetClass(gadget)
Case GADGET_BUTTON
'button, we can use the windows ideal button size message which incorporates images as well!
Local size:Int[] = [maxWidth,0]
'disable redraw on gadget
SendMessageW(hwnd,WM_SETREDRAW,False,0)
'change text of gadget
Local oldText:String = GadgetText(gadget)
SetGadgetText(gadget,text)
'test for ideal size
SendMessageW(hwnd,BCM_GETIDEALSIZE,0,Int Byte Ptr(size))
'restore the gadget
SetGadgetText(Gadget,oldText)
SendMessageW(hwnd,WM_SETREDRAW,True,0)
'return the result
Return size
Default
'default action is to use the DrawText operation to figure out size
Local dc :Int = GetDC(hwnd)
'get and set font used by the control
Local font:Int = SendMessageW(hwnd,WM_GETFONT,0,0)
SelectObject(dc,font)
'get the client rect (doing this just because its worth it)
Local rect:Int[] = [0,0,maxWidth,0]
'text rect flags
Local flags:Int = DT_CALCRECT | DT_NOCLIP
If maxWidth > 0 flags :| DT_WORDBREAK
'calculate the bounding
DrawTextW(dc,text,-1,rect,flags)
'release device context
ReleaseDC(hwnd,dc)
'return the result
Return [rect[2],rect[3]]
End Select
?MacOs
Local result:Int[] = skn3_stringDimensions(QueryGadget(gadget,QUERY_NSVIEW_CLIENT),text,maxWidth)
Return result
?
End Function
Rem
bbdoc: This is mainly for use with custom proxy gadget constructor functions to get the real parent gadget/proxy of a given gadget/proxy. <b>[Win Mac Linux]</b>
returns: A TGadget.
about:
<b>Supported Platforms</b>
<ul>
<li>Windows</li>
<li>Mac</li>
<li>Linux</li>
</ul>
<b>Info</b>
<p>This is just a copy of the private function in maxgui.</p>
End Rem
Function GetCreationGroup:TGadget(Gadget:TGadget)
Local tmpProxy:TProxyGadget = TProxyGadget(gadget)
If tmpProxy Then Return GetCreationGroup(tmpProxy.proxy)
Return gadget
EndFunction
Rem
bbdoc: Change a gadget to be readonly. <b>[Win Mac]</b>
about:
<b>Supported Platforms</b>
<ul>
<li>Windows</li>
<li>Mac</li>
</ul>
<b>Info</b>
<p>This currently works on textfields and textareas and sets the gadgets to be readonly without having a disabled style.</p>
End Rem
Function SetGadgetReadOnly(gadget:TGadget,yes:Int)
' --- set a gadget readonly state ---
'this only works for text entry gadgets
Select GadgetClass(gadget)
Case GADGET_TEXTAREA,GADGET_TEXTFIELD
?Win32
Local hwnd:Int = QueryGadget(gadget,QUERY_HWND)
SendMessageW(hwnd,EM_SETREADONLY,yes,0)
?MacOs
skn3_setReadOnly(QueryGadget(gadget,QUERY_NSVIEW),yes = False)
?
End Select
End Function
Rem
bbdoc: Set the maximum number of characters a gadget can contain. <b>[Win Mac]</b>
about:
<b>Supported Platforms</b>
<ul>
<li>Windows</li>
<li>Mac</li>
</ul>
<b>Info</b>
<p>This function currently works with textfields and textareas and allows you to specify a maximum number of characters the user can enter. This will work on the os level so you dont have to manually limit text with blitz events. Use #GetGadgetMaxLength to get the current max length value.</p>
End Rem
Function SetGadgetMaxLength(gadget:TGadget,length:Int=0)
' --- change the max length of a gadget ---
Select GadgetClass(gadget)
Case GADGET_TEXTFIELD,GADGET_TEXTAREA
?Win32
If length < 0 length = 0
SendMessageW(QueryGadget(gadget,QUERY_HWND),EM_SETLIMITTEXT,length,0)
?MacOs
If length < 0 length = 0
skn3_setMaxLength(QueryGadget(gadget,QUERY_NSVIEW),length)
?
End Select
End Function
Rem
bbdoc: Get the maximum number of characters a gadget can contain. <b>[Win Mac]</b>
returns: An int.
about:
<b>Supported Platforms</b>
<ul>
<li>Windows</li>
<li>Mac</li>
</ul>
<b>Info</b>
<p>This function currently works with textfields and text areas.</p>
End Rem
Function GetGadgetMaxLength:Int(gadget:TGadget)
' --- get the max length of a gadget ---
Select GadgetClass(gadget)
Case GADGET_TEXTFIELD,GADGET_TEXTAREA
?Win32
Return SendMessageW(QueryGadget(gadget,QUERY_HWND),EM_GETLIMITTEXT,0,0)
?MacOs
Return skn3_getMaxLength(QueryGadget(gadget,QUERY_NSVIEW))
?
Default
Return 0
End Select
End Function
Rem
bbdoc: Load a custom pointer file from disk or incbin. <b>[Win Mac]</b>
returns: A #Skn3CustomPointer object.
about:
<b>Supported Platforms</b>
<ul>
<li>Windows</li>
<li>Mac</li>
</ul>
<b>Info</b>
<p>This will attempt to load a <b>.cur</b> file and return an object to represent it. The cursor file should contain a single cursor and be of the <b>.cur</b> filetype. A cursor hotspot is supported on both windows and mac so you can have a center that is not 0,0. You must use your cursor creation software to set a hotspot. Use #SetCustomPointer to set the current pointer to this and #FreeCustomPointer() to free it.</p>
End Rem
Function LoadCustomPointer:Skn3CustomPointer(path:String)
' --- this will load a cursor ---
Local pointer:Skn3CustomPointer
Local path2:String = IncBinToDisk(path)
Local deletePath2:Int = False
If path2.length = 0
path2 = path
Else
deletePath2 = True
EndIf
'check for cache
If Skn3CustomPointer.all = Null
' make sure the cursor store is created
Skn3CustomPointer.all = CreateMap()
Else
'check existance
pointer = Skn3CustomPointer(Skn3CustomPointer.all.ValueForKey(path))
EndIf
'create new pointer
If pointer = Null
'create custom pointer
pointer = New Skn3CustomPointer
pointer.path = path
Skn3CustomPointer.all.Insert(path,pointer)
'load in os (using path2)
?Win32
pointer.pointer = skn3_loadCursorFromFile(path2)
?MacOs
'first get the offset
Local offset:Int[] = ExtractCursorHotspot(path2)
'now load the pointer
pointer.pointer = skn3_loadCustomPointer(path2,offset[0],offset[1])
?
End If
'delete temp file?
If deletePath2 DeleteFile(path2)
'return pointer
If pointer.pointer <> 0
'increase reference count
pointer.refCount :+ 1
Return pointer
EndIf
End Function
Rem
bbdoc: Set the current pointer to a custom pointer loaded with LoadCustomPointer. <b>[Win Mac]</b>
about:
<b>Supported Platforms</b>
<ul>
<li>Windows</li>
<li>Mac</li>
</ul>
<b>Info</b>
<p>On mac please make sure you do not call this function at the start of execution as it will not work. Calling this function must be done in response to something else happening for example when the mouse enters a canvas. Use #LoadCustomCursor to load a cursor file and #FreeCustomCursor to free your loaded cursor.</p>
End Rem
Function SetCustomPointer(pointer:Skn3CustomPointer)
' --- set the pointer up in os ---
If pointer
lastPointer = -1
?Win32
SetCursor(pointer.pointer)
TWindowsGUIDriver._cursor = pointer.pointer
If TWindowsTextArea._oldCursor Then TWindowsTextArea._oldCursor = pointer.pointer
?MacOs
skn3_setCustomPointer(pointer.pointer)
?
EndIf
End Function
Rem
bbdoc: Free a Skn3CustomCursor custom cursor object. <b>[Win Mac]</b>
about:
<b>Supported Platforms</b>
<ul>
<li>Windows</li>
<li>Mac</li>
</ul>
<b>Info</b>
<p>Frees a custom cursor previously loaded with #LoadCustomCursor.</p>
End Rem
Function FreeCustomPointer(pointer:Skn3CustomPointer)
' --- free the pointer ---
If pointer
'decrease ref coutn then check
pointer.refCount :- 1
If pointer.refCount = 0
'free in maxguiex
Skn3CustomPointer.all.remove(pointer.path)
'free in os
?Win32
'check if we need to reset in maxgui
If TWindowsGUIDriver._cursor = pointer.pointer SetPointer(POINTER_DEFAULT)
skn3_destroyCursor(pointer.pointer)
pointer.pointer = 0
?MacOs
If skn3_currentCursor() = pointer.pointer SetPointer(POINTER_DEFAULT)
skn3_freeCustomPointer(pointer.pointer)
?
EndIf
EndIf
End Function
Rem
bbdoc: Utility for extracting x,y representing the hotspot of a .cur file. <b>[Win Mac Linux]</b>
returns: An int array with 2 elements. 0 = x, 1 = y
about:
<b>Supported Platforms</b>
<ul>
<li>Windows</li>
<li>Mac</li>
<li>Linux</li>
</ul>
<b>Info</b>
<p>This function will open the <b>.cur</b> file and extract the x,y offset from the file data.</p>
End Rem
Function ExtractCursorHotspot:Int[](path:String,index:Int=0)
' --- function to extract the hotspot x,y from a cursor ---
Local result:Int[2]
Local file:TStream = ReadFile("littleendian::"+path)
If file
'reserved
file.seek(2)
'only process cursor types
Local temp:Int = file.ReadShort()
If temp = 2
'only process if valid index
temp = file.ReadShort()
If index < temp
'only process if offset isnt beyond file length
temp = 6+(12*index)+4
If temp < file.size()
file.seek(temp)
result[0] = file.ReadShort()
result[1] = file.ReadShort()
EndIf
EndIf
EndIf
'close the stream
file.close()
EndIf
'return the result
Return result
End Function
Rem
bbdoc: Lock a listbox and start a batch add operation. <b>[Win]</b>
about:
<b>Supported Platforms</b>
<ul>
<li>Windows</li>
</ul>
<b>Info</b>
<p>This function is used to prepare a locking session and lock a listbox gadget so items can be added to it in batch. See #ListBatchAdd and #ListBatchUnlock for additional info.</p>
End Rem
Function ListBatchLock(Gadget:TGadget)
' --- lock a particular gadget for mass item update ---
?Win32
'check if already locked
Local Lock:Skn3ListBatchLock = Skn3ListBatchLock.Find(Gadget)
If Lock
'increase ref count only!
Lock.refCount :+ 1
Return
EndIf
'check this is a windows listbox
Local listBox:TWindowsListBox = TWindowsListBox(Gadget)
If listBox = Null Return
'creat a new lock
Lock = New Skn3ListBatchLock
Lock.refCount = 1
Lock.listBox = listBox
Lock.index = listBox.items.Length
Lock.it = New LVITEMW
Lock.hwnd = QueryGadget(listBox,QUERY_HWND)
'prepare the listbox
listBox.DeSensitize()
'add to locks
Skn3ListBatchLock.add(Lock)
?
End Function
Rem
bbdoc: Add an item to a listbox in batch mode. <b>[Win]</b>
about:
<b>Supported Platforms</b>
<ul>
<li>Windows</li>
</ul>
<b>Info</b>
<p>If you call this in an unsupported platform then the default maxgui behaviour will be used</p>
<p>When a lsitbox has been locked with #ListBatchLock you can then use this function to add gadget items. The items wont properly appear in the listbox until #ListBatchUnlock is called. Lock attempts are reference counted so can be nested</p>
End Rem
Function ListBatchAdd(Gadget:TGadget,text:String,flags:Int,icon:Int,tip:String,extra:Object=Null)
' --- add an item to a locked gadget ---
?Win32
'check if the gadget is locked
Local Lock:Skn3ListBatchLock = Skn3ListBatchLock.Find(Gadget)
'check for maxgui action (as not locked)
If Lock = Null
AddGadgetItem(Gadget,text,flags,icon,tip,extra)
Return
End If
'so now lets do the add operation
'create the gadget item
Local item:TGadgetItem = New TGadgetItem
item.Set(text,tip,icon,extra,flags)
'add item to maxgui gadget
Gadget.items = Gadget.items[..Lock.index+1]
Gadget.items[Lock.index] = item
'add item to os
Lock.it.Mask = LVIF_TEXT|LVIF_DI_SETITEM
Lock.it.iItem = Lock.index
Lock.it.pszText = item.text.toWString()
'If icon>=0 Then
Lock.it.mask:|LVIF_IMAGE
Lock.it.iImage = item.icon
'EndIf
SendMessageW(Lock.hwnd,LVM_INSERTITEMW,0,Int Byte Ptr(Lock.it))
MemFree(Lock.it.pszText)
'increase index for next item
Lock.index :+ 1
?Not Win32
'revert to built in maxgui action
AddGadgetItem(Gadget,text,flags,icon,tip,extra)
?
End Function
Rem
bbdoc: Unlock a listbox and update for any items that were added with #ListBatchAdd. <b>[Win]</b>
about:
<b>Supported Platforms</b>
<ul>
<li>Windows</li>
</ul>
<b>Info</b>
<p>The locking is reference counted so the listbox will only unlock when its reference count reaches 0. Each call to #ListBatchLock must be matched with #ListbatchUnlock. See #ListBatchLock and #ListBatchLock for more info.</p>
End Rem
Function ListBatchUnlock(Gadget:TGadget)
' --- unlock a particular item for mass item update ---
?Win32
'check if locked
Local Lock:Skn3ListBatchLock = Skn3ListBatchLock.Find(Gadget)
If Lock = Null Return
'decrease refcount
Lock.refCount :- 1
'check if ref count means proper unlock
If Lock.refCount = 0
'do the unlock in os
SendMessageW(Lock.hwnd,LVM_SETCOLUMNWIDTH,0,-2)
If Not Lock.listBox.IsSingleSelect() Then Lock.listBox.SelectionChanged()
Lock.listBox.Sensitize()
'remove the lock
Skn3ListBatchLock.remove(Lock)
EndIf
?
End Function
Rem
bbdoc: Find the first parent window the provided gadget belongs to. <b>[Win Mac Linux]</b>
returns: A TGadget or Null.
about:
<b>Supported Platforms</b>
<ul>
<li>Windows</li>
<li>Mac</li>
<li>Linux</li>
</ul>
<b>Info</b>
<p>This function will walk the parent tree to find the window the given gadget belogns to.</p>
End Rem
Function GadgetWindow:TGadget(Gadget:TGadget)
' --- this will locate a gadgets window ---
Local parent:TGadget = GadgetGroup(Gadget)
While parent
If GadgetClass(parent) = GADGET_WINDOW Return parent
parent = GadgetGroup(parent)
Wend
End Function
Rem
bbdoc: Force a window to always be on the top of other windows. <b>[Win Mac]</b>
about:
<b>Supported Platforms</b>
<ul>
<li>Windows</li>
<li>Mac</li>
</ul>
<b>Info</b>
<p>This is like sticking a post it note on your monitor and will make your window stay above any other running applications.</p>
End Rem
Function SetWindowAlwaysOnTop(Window:TGadget,State:Int=False)
' --- set a window to stay on top ---
?Win32
Local hwnd:Int = QueryGadget(Window,QUERY_HWND)
If hwnd
If State
'on top
SetWindowPos(hwnd,HWND_TOPMOST,0,0,0,0,SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE)
Else
SetWindowPos(hwnd,HWND_NOTOPMOST,0,0,0,0,SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE)
EndIf
EndIf
?MacOs
skn3_setWindowAlwaysOnTop(QueryGadget(Window,QUERY_NSVIEW),State)
?
End Function
Rem
bbdoc: Bring the provided window to the top of the screen (but dont stick it there). <b>[Win Mac]</b>
about:
<b>Supported Platforms</b>
<ul>
<li>Windows</li>
<li>Mac</li>
</ul>
<b>Info</b>
<p>This is useful if you need to force focus your window to the top of the desktop.</p>
End Rem
Function BringWindowToTop(Window:TGadget)
' --- brings the window to the top of the z order ---
?Win32
Local hwnd:Int = QueryGadget(Window,QUERY_HWND)
If hwnd SetWindowPos(hwnd,HWND_TOP,0,0,0,0,SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE)
?MacOs
skn3_bringWindowToTop(QueryGadget(Window,QUERY_NSVIEW))
?
End Function
Rem
bbdoc: Forces a window to be focused. <b>[Win Mac]</b>
about:
<b>Supported Platforms</b>
<ul>
<li>Windows</li>
<li>Mac</li>
</ul>
<b>Info</b>
<p>This forces the provided window to be set to focused via HWND or NSVIEW and bypasses the maxgui internals. There are sometimes issues with the built in maxgui gadget focus/activation commands so this is a clean way of solving it.</p>
End Rem
Function FocusWindow(Window:TGadget)
' --- set a window to focus and bypass weird maxgui stuff---
?Win32
Local hwnd:Int = QueryGadget(Window,QUERY_HWND)
If hwnd SetFocus(hwnd)
?MacOs
'cocoa maxgui already does this alright...
skn3_focusWindow(QueryGadget(Window,QUERY_NSVIEW))
?
End Function
Rem
bbdoc: Helper function to turn a gadget into its respective os handle. <b>[Win Mac Linux]</b>