forked from FAForever/fa
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathuiutil.lua
1052 lines (926 loc) · 40.5 KB
/
uiutil.lua
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
--*****************************************************************************
--* File: lua/modules/ui/uiutil.lua
--* Author: Chris Blackwell
--* Summary: Various utility functions to make UI scripts easier and more consistent
--*
--* Copyright � 2005 Gas Powered Games, Inc. All rights reserved.
--*****************************************************************************
local LazyVar = import('/lua/lazyvar.lua')
local LayoutHelpers = import('/lua/maui/layouthelpers.lua')
local Group = import('/lua/maui/group.lua').Group
local Text = import('/lua/maui/text.lua').Text
local MultiLineText = import('/lua/maui/multilinetext.lua').MultiLineText
local Button = import('/lua/maui/button.lua').Button
local Edit = import('/lua/maui/edit.lua').Edit
local Checkbox = import('/lua/maui/Checkbox.lua').Checkbox
local RadioButtons = import('/lua/maui/radiobuttons.lua').RadioButtons
local Scrollbar = import('/lua/maui/scrollbar.lua').Scrollbar
local Bitmap = import('/lua/maui/bitmap.lua').Bitmap
local Cursor = import('/lua/maui/cursor.lua').Cursor
local Prefs = import('/lua/user/prefs.lua')
local Border = import('/lua/maui/border.lua').Border
local ItemList = import('/lua/maui/itemlist.lua').ItemList
local Layouts = import('/lua/skins/layouts.lua')
--* Handy global variables to assist skinning
buttonFont = import('/lua/lazyvar.lua').Create() -- default font used for button faces
factionFont = import('/lua/lazyvar.lua').Create() -- default font used for dialog button faces
dialogButtonFont = import('/lua/lazyvar.lua').Create() -- default font used for dialog button faces
bodyFont = import('/lua/lazyvar.lua').Create() -- font used for all other text
fixedFont = import('/lua/lazyvar.lua').Create() -- font used for fixed width characters
titleFont = import('/lua/lazyvar.lua').Create() -- font used for titles and labels
fontColor = import('/lua/lazyvar.lua').Create() -- common font color
fontOverColor = import('/lua/lazyvar.lua').Create() -- common font color
fontDownColor = import('/lua/lazyvar.lua').Create() -- common font color
tooltipTitleColor = import('/lua/lazyvar.lua').Create() -- common font color
tooltipBorderColor = import('/lua/lazyvar.lua').Create() -- common font color
bodyColor = import('/lua/lazyvar.lua').Create() -- common color for dialog body text
dialogCaptionColor = import('/lua/lazyvar.lua').Create() -- common color for dialog titles
dialogColumnColor = import('/lua/lazyvar.lua').Create() -- common color for column headers in a dialog
dialogButtonColor = import('/lua/lazyvar.lua').Create() -- common color for buttons in a dialog
highlightColor = import('/lua/lazyvar.lua').Create() -- text highlight color
disabledColor = import('/lua/lazyvar.lua').Create() -- text disabled color
panelColor = import('/lua/lazyvar.lua').Create() -- default color when drawing a panel
transparentPanelColor = import('/lua/lazyvar.lua').Create() -- default color when drawing a transparent panel
consoleBGColor = import('/lua/lazyvar.lua').Create() -- console background color
consoleFGColor = import('/lua/lazyvar.lua').Create() -- console foreground color (text)
consoleTextBGColor = import('/lua/lazyvar.lua').Create() -- console text background color
menuFontSize = import('/lua/lazyvar.lua').Create() -- font size used on main in game escape menu
-- table of layouts supported by this skin, not a lazy var as we don't need updates
layouts = nil
--* other handy variables!
consoleDepth = false -- in order to get the console to always be on top, assign this number and never go over
networkBool = import('/lua/lazyvar.lua').Create() -- boolean whether the game is local or networked
-- Default scenario for skirmishes / MP Lobby
defaultScenario = '/maps/scmp_039/scmp_039_scenario.lua'
--* These values MUST NOT CHANGE! They syncronize with values in UIManager.h and are used to
--* specify a render pass
-- render before the world is rendered
UIRP_UnderWorld = 1
-- reserved for world views
UIRP_World = 2
-- render with glow (note, won't render when world isn't visible)
UIRP_Glow = 4
-- render without glow
UIRP_PostGlow = 8
--* useful key codes, weirdly inconsistent, some are MSW vk codes, some are wxW codes :(
VK_BACKSPACE = 8
VK_TAB = 9
VK_ENTER = 13
VK_ESCAPE = 27
VK_SPACE = 32
VK_PRIOR = 33
VK_NEXT = 34
VK_UP = 38
VK_DOWN = 40
VK_PAUSE = 310
local currentSkin = import('/lua/lazyvar.lua').Create()
currentLayout = false
changeLayoutFunction = false -- set this function to get called with the new layout name when layout changes
local UIFileCache = {}
local FileCache = {}
local oldDiskGetFileInfo = DiskGetFileInfo
function DiskGetFileInfo(file)
if FileCache[file] == nil then
local info = oldDiskGetFileInfo(file)
if(info) then
FileCache[file] = info
else
FileCache[file] = false
end
end
return FileCache[file]
end
--* layout control, sets current layout preference
function SetCurrentLayout(layout)
if not layout then return end
-- make sure this skin contains the layout, otherwise do nothing
local foundLayout = false
for index, complayout in layouts do
if layout == complayout then
foundLayout = true
break
end
end
if not foundLayout then return end
currentLayout = layout
Prefs.SetToCurrentProfile("layout", currentLayout)
SelectUnits(nil)
if changeLayoutFunction then changeLayoutFunction(layout) end
end
function GetNetworkBool()
local sessionClientsTable = GetSessionClients()
local networkBool = false
local sessionBool = true
if sessionClientsTable ~= nil then
networkBool = SessionIsMultiplayer()
else
sessionBool = false
end
return networkBool, sessionBool
end
function GetAnimationPrefs()
return true
end
function GetLayoutFilename(key)
if Layouts[currentLayout][key] then
return Layouts[currentLayout][key]
else
WARN('No layout file for \'', key, '\' in the current layout. Expect layout errors.')
return false
end
end
function UpdateWorldBorderState(skin, isOn)
if skin == nil then
skin = currentSkin()
end
if SessionIsActive() then
if isOn == nil then
isOn = Prefs.GetOption('world_border')
end
if isOn then
local skins = import('/lua/skins/skins.lua').skins
if skins[skin].imagerMesh then
MapBorderClear()
--Set the world mesh to the skins world mesh
local size = SessionGetScenarioInfo().size
if size[1] == 2048 and size[2] == 1024 then
MapBorderAdd(skins[skin].imagerMeshHorz)
if skins[skin].imagerMeshDetailsHorz then
MapBorderAdd(skins[skin].imagerMeshDetailsHorz)
end
else
MapBorderAdd(skins[skin].imagerMesh)
if skins[skin].imagerMeshDetails then
MapBorderAdd(skins[skin].imagerMeshDetails)
end
end
end
else
MapBorderClear()
end
end
end
--* skin control, sets the current skin table
function SetCurrentSkin(skin)
local skins = import('/lua/skins/skins.lua').skins
if skins[skin] == nil then
skin = 'uef'
end
currentSkin:Set(skin)
tooltipTitleColor:Set(skins[skin].tooltipTitleColor or skins['default'].tooltipTitleColor)
tooltipBorderColor:Set(skins[skin].tooltipBorderColor or skins['default'].tooltipBorderColor)
buttonFont:Set(skins[skin].buttonFont or skins['default'].buttonFont)
factionFont:Set(skins[skin].factionFont or skins['default'].factionFont)
dialogButtonFont:Set(skins[skin].dialogButtonFont or skins['default'].dialogButtonFont)
bodyFont:Set(skins[skin].bodyFont or skins['default'].bodyFont)
fixedFont:Set(skins[skin].fixedFont or skins['default'].fixedFont)
titleFont:Set(skins[skin].titleFont or skins['default'].titleFont)
bodyColor:Set(skins[skin].bodyColor or skins['default'].bodyColor)
fontColor:Set(skins[skin].fontColor or skins['default'].fontColor)
fontOverColor:Set(skins[skin].fontOverColor or skins['default'].fontOverColor)
fontDownColor:Set(skins[skin].fontDownColor or skins['default'].fontDownColor)
dialogCaptionColor:Set(skins[skin].dialogCaptionColor or skins['default'].dialogCaptionColor)
dialogColumnColor:Set(skins[skin].dialogColumnColor or skins['default'].dialogColumnColor)
dialogButtonColor:Set(skins[skin].dialogButtonColor or skins['default'].dialogButtonColor)
highlightColor:Set(skins[skin].highlightColor or skins['default'].highlightColor)
disabledColor:Set(skins[skin].disabledColor or skins['default'].disabledColor)
panelColor:Set(skins[skin].panelColor or skins['default'].panelColor)
transparentPanelColor:Set(skins[skin].transparentPanelColor or skins['default'].transparentPanelColor)
consoleBGColor:Set(skins[skin].consoleBGColor or skins['default'].consoleBGColor)
consoleFGColor:Set(skins[skin].consoleFGColor or skins['default'].consoleFGColor)
consoleTextBGColor:Set(skins[skin].consoleTextBGColor or skins['default'].consoleTextBGColor)
menuFontSize:Set(skins[skin].menuFontSize or skins['default'].menuFontSize)
layouts = skins[skin].layouts or skins['default'].layouts
UpdateWorldBorderState(skin)
local curLayout = Prefs.GetFromCurrentProfile("layout")
if not curLayout then
SetCurrentLayout(layouts[1])
else
local validLayout = false
for i, layoutName in layouts do
if layoutName == curLayout then
validLayout = true
break
end
end
if validLayout then
SetCurrentLayout(curLayout)
else
SetCurrentLayout(layouts[1])
end
end
Prefs.SetToCurrentProfile("skin", skin)
end
--* cycle through all available skins
function RotateSkin(direction)
if not SessionIsActive() or import('/lua/ui/game/gamemain.lua').IsNISMode() then
return
end
local skins = import('/lua/skins/skins.lua').skins
-- build an array of skin names
local skinNames = {}
for skin in skins do
table.insert(skinNames, skin)
end
local dir
if direction == '+' then
dir = 1
else
dir = -1
end
-- Find the next skin from our current skin, skipping default/randomfaction: they're not really
-- skins note that if the skin table is updated while running, the order of the table might change
-- so your cycle may be different. No big deal, just be aware it's a side effect.
local numSkins = table.getn(skinNames)
for index, skinName in skinNames do
if skinName == currentSkin() then
local nextSkinIndex = index + dir
if nextSkinIndex > numSkins then nextSkinIndex = 1 end
if nextSkinIndex < 1 then nextSkinIndex = numSkins end
if skinNames[nextSkinIndex] == 'default' or skinNames[nextSkinIndex] == 'random' then -- skip default entry as it's not really a skin
nextSkinIndex = nextSkinIndex + dir
if nextSkinIndex > numSkins then nextSkinIndex = 1 end
if nextSkinIndex < 1 then nextSkinIndex = numSkins end
end
LOG('attempting to set skin to: ', skinNames[nextSkinIndex])
SetCurrentSkin(skinNames[nextSkinIndex])
break
end
end
end
--* cycle through all available layouts
function RotateLayout(direction)
-- disable when in Screen Capture mode
if import('/lua/ui/game/gamemain.lua').gameUIHidden then
return
end
local dir
if direction == '+' then
dir = 1
else
dir = -1
end
local numLayouts = table.getn(layouts)
for index, layoutName in layouts do
if layoutName == currentLayout then
local nextLayoutIndex = index + dir
if nextLayoutIndex > numLayouts then nextLayoutIndex = 1 end
if nextLayoutIndex < 1 then nextLayoutIndex = numLayouts end
SetCurrentLayout(layouts[nextLayoutIndex])
break
end
end
end
--* given a path and name relative to the skin path, returns the full path based on the current skin
function UIFile(filespec)
local skins = import('/lua/skins/skins.lua').skins
local useSkin = currentSkin()
local currentPath = skins[useSkin].texturesPath
if useSkin == nil or currentPath == nil then
return nil
end
if not UIFileCache[currentPath .. filespec] then
local found = false
if useSkin == 'default' then
found = currentPath .. filespec
else
while not found and useSkin do
found = currentPath .. filespec
if not DiskGetFileInfo(found) then
found = false
useSkin = skins[useSkin].default
if useSkin then
currentPath = skins[useSkin].texturesPath
end
end
end
end
if found then
if not UIFileCache[useSkin] then UIFileCache[useSkin] = {} end
UIFileCache[useSkin][filespec] = found
else
LOG("Warning: Unable to find file ", filespec)
return filespec
end
end
return UIFileCache[useSkin][filespec]
end
--* return the filename as a lazy var function to allow triggering of OnDirty
function SkinnableFile(filespec)
return function()
return UIFile(filespec)
end
end
--* each UI screen needs something to be responsible for parenting all its controls so
--* placement and destruction can occur. This creates a group which fills the screen.
function CreateScreenGroup(root, debugName)
if not root then return end
local screenGroup = Group(root, debugName or "screenGroup")
LayoutHelpers.FillParent(screenGroup, root)
return screenGroup
end
--* Get cursor information for a given cursor ID
function GetCursor(id)
local skins = import('/lua/skins/skins.lua').skins
local cursors = skins[currentSkin()].cursors or skins['default'].cursors
if not cursors[id] then
LOG("Requested cursor not found: " .. id)
end
return cursors[id][1], cursors[id][2], cursors[id][3], cursors[id][4], cursors[id][5]
end
--* create the one cursor used by the game
function CreateCursor()
local cursor = Cursor(GetCursor('DEFAULT'))
return cursor
end
--* return a text object with the appropriate font set
function CreateText(parent, label, pointSize, font, dropshadow)
label = LOC(label) or LOC("<LOC uiutil_0000>[no text]")
font = font or buttonFont
local text = Text(parent, "Text: " .. label)
text:SetFont(font, pointSize)
text:SetColor(fontColor)
text:SetText(label)
if dropshadow then
text:SetDropShadow(true)
end
return text
end
function SetupEditStd(control, foreColor, backColor, highlightFore, highlightBack, fontFace, fontSize, charLimit)
if charLimit then
control:SetMaxChars(charLimit)
end
if foreColor then
control:SetForegroundColor(foreColor)
end
if backColor then
control:SetBackgroundColor(backColor)
end
if highlightFore then
control:SetHighlightForegroundColor(highlightFore)
end
if highlightBack then
control:SetHighlightBackgroundColor(highlightBack)
end
if fontFace and fontSize then
control:SetFont(fontFace, fontSize)
end
control.OnCharPressed = function(self, charcode)
if charcode == VK_TAB then
return true
end
local charLim = self:GetMaxChars()
if STR_Utf8Len(self:GetText()) >= charLim then
local sound = Sound({Cue = 'UI_Menu_Error_01', Bank = 'Interface',})
PlaySound(sound)
end
end
end
--* return a button set up with a text overlay and a click sound
function CreateButton(parent, up, down, over, disabled, label, pointSize, textOffsetVert, textOffsetHorz, clickCue, rolloverCue, dropshadow)
textOffsetVert = textOffsetVert or 0
textOffsetHorz = textOffsetHorz or 0
if clickCue == "NO_SOUND" then
clickCue = nil
else
clickCue = clickCue or "UI_Menu_MouseDown_Sml"
end
if rolloverCue == "NO_SOUND" then
rolloverCue = nil
else
rolloverCue = rolloverCue or "UI_Menu_Rollover_Sml"
end
if type(up) == 'string' then
up = SkinnableFile(up)
end
if type(down) == 'string' then
down = SkinnableFile(down)
end
if type(over) == 'string' then
over = SkinnableFile(over)
end
if type(disabled) == 'string' then
disabled = SkinnableFile(disabled)
end
local button = Button(parent, up, down, over, disabled, clickCue, rolloverCue)
button:UseAlphaHitTest(true)
if label and pointSize then
button.label = CreateText(button, label, pointSize, buttonFont, dropshadow)
LayoutHelpers.AtCenterIn(button.label, button, textOffsetVert, textOffsetHorz)
button.label:DisableHitTest()
-- if text exists, set up to grey it out
button.OnDisable = function(self)
Button.OnDisable(self)
button.label:SetColor(disabledColor)
end
button.OnEnable = function(self)
Button.OnEnable(self)
button.label:SetColor(fontColor)
end
button.OnRolloverEvent = function(self, event)
if event == 'enter' then
button.label:SetColor(fontOverColor)
elseif event == 'exit' then
button.label:SetColor(fontColor)
elseif event == 'down' then
button.label:SetColor(fontDownColor)
end
end
end
return button
end
--* create a button with standardized texture names
--* given a path and button name prefix, generates the four button asset file names according to the naming convention
function CreateButtonStd(parent, filename, label, pointSize, textOffsetVert, textOffsetHorz, clickCue, rolloverCue)
return CreateButton(parent
, filename .. "_btn_up.dds"
, filename .. "_btn_down.dds"
, filename .. "_btn_over.dds"
, filename .. "_btn_dis.dds"
, label
, pointSize
, textOffsetVert
, textOffsetHorz
, clickCue
, rolloverCue
)
end
function CreateButtonWithDropshadow(parent, filename, label, textOffsetVert, textOffsetHorz, clickCue, rolloverCue)
return CreateButton(parent
, filename .. "_btn_up.dds"
, filename .. "_btn_down.dds"
, filename .. "_btn_over.dds"
, filename .. "_btn_dis.dds"
, label
, 11
, textOffsetVert
, textOffsetHorz
, clickCue
, rolloverCue
, true
)
end
function CreateCheckbox(parent, up, upsel, over, oversel, dis, dissel, clickCue, rollCue)
local clickSound = clickCue or 'UI_Mini_MouseDown'
local rollSound = rollCue or 'UI_Mini_Rollover'
local checkbox = Checkbox( parent, up, upsel, over, oversel, dis, dissel, clickSound, rollSound)
checkbox:UseAlphaHitTest(true)
return checkbox
end
function CreateCheckboxStd(parent, filename, clickCue, rollCue)
local checkbox = CreateCheckbox( parent,
SkinnableFile(filename .. '-d_btn_up.dds'),
SkinnableFile(filename .. '-s_btn_up.dds'),
SkinnableFile(filename .. '-d_btn_over.dds'),
SkinnableFile(filename .. '-s_btn_over.dds'),
SkinnableFile(filename .. '-d_btn_dis.dds'),
SkinnableFile(filename .. '-s_btn_dis.dds'),
clickCue, rollCue)
return checkbox
end
function CreateRadioButtonsStd(parent, filename, title, buttons, default)
local radioButton = RadioButtons(parent, title, buttons, default, "Arial", 14, fontColor,
SkinnableFile(filename .. '-d_btn_up.dds'),
SkinnableFile(filename .. '-s_btn_up.dds'),
SkinnableFile(filename .. '-d_btn_over.dds'),
SkinnableFile(filename .. '-s_btn_over.dds'),
SkinnableFile(filename .. '-d_btn_dis.dds'),
SkinnableFile(filename .. '-s_btn_dis.dds'),
"")
return radioButton
end
function CreateDialogButtonStd(parent, filename, label, pointSize, textOffsetVert, textOffsetHorz, clickCue, rolloverCue)
local button = CreateButtonStd(parent,filename,label,pointSize,textOffsetVert,textOffsetHorz, clickCue, rolloverCue)
button.label:SetFont( dialogButtonFont, pointSize )
button.label:SetColor( dialogButtonColor )
return button
end
--* return the standard scrollbar
function CreateVertScrollbarFor(attachto, offset_right, filename, offset_bottom, offset_top)
offset_right = offset_right or 0
offset_bottom = offset_bottom or 0
offset_top = offset_top or 0
local textureName = filename or '/small-vert_scroll/'
local scrollbg = textureName..'back_scr_mid.dds'
local scrollbarmid = textureName..'bar-mid_scr_over.dds'
local scrollbartop = textureName..'bar-top_scr_up.dds'
local scrollbarbot = textureName..'bar-bot_scr_up.dds'
if filename then
scrollbg = textureName..'back_scr_mid.dds'
scrollbarmid = textureName..'bar-mid_scr_up.dds'
scrollbartop = textureName..'bar-top_scr_up.dds'
scrollbarbot = textureName..'bar-bot_scr_up.dds'
end
local scrollbar = Scrollbar(attachto, import('/lua/maui/scrollbar.lua').ScrollAxis.Vert)
scrollbar:SetTextures( SkinnableFile(scrollbg)
,SkinnableFile(scrollbarmid)
,SkinnableFile(scrollbartop)
,SkinnableFile(scrollbarbot))
local scrollUpButton = Button( scrollbar
, SkinnableFile(textureName..'arrow-up_scr_up.dds')
, SkinnableFile(textureName..'arrow-up_scr_over.dds')
, SkinnableFile(textureName..'arrow-up_scr_down.dds')
, SkinnableFile(textureName..'arrow-up_scr_dis.dds')
, "UI_Arrow_Click")
local scrollDownButton = Button( scrollbar
, SkinnableFile(textureName..'arrow-down_scr_up.dds')
, SkinnableFile(textureName..'arrow-down_scr_over.dds')
, SkinnableFile(textureName..'arrow-down_scr_down.dds')
, SkinnableFile(textureName..'arrow-down_scr_dis.dds')
, "UI_Arrow_Click")
scrollbar.Left:Set(function() return attachto.Right() + offset_right end)
scrollbar.Top:Set(scrollUpButton.Bottom)
scrollbar.Bottom:Set(scrollDownButton.Top)
scrollUpButton.Left:Set(scrollbar.Left)
scrollUpButton.Top:Set(function() return attachto.Top() + offset_top end)
scrollDownButton.Left:Set(scrollbar.Left)
scrollDownButton.Bottom:Set(function() return attachto.Bottom() + offset_bottom end)
scrollbar.Right:Set(scrollUpButton.Right)
scrollbar:AddButtons(scrollUpButton, scrollDownButton)
scrollbar:SetScrollable(attachto)
return scrollbar
end
function CreateLobbyVertScrollbar(attachto, offset_right, filename, offset_bottom, offset_top)
return CreateVertScrollbarFor(attachto, offset_right, "/SCROLLBAR_VERT/", offset_bottom, offset_top)
end
function CreateHorzScrollbarFor(attachto, offset)
offset = offset or 0
local scrollbar = Scrollbar(attachto, import('/lua/maui/scrollbar.lua').ScrollAxis.Horz)
local scrollRightButton = Button( scrollbar
, SkinnableFile('/widgets/large-h_scr/arrow-right_scr_up.dds')
, SkinnableFile('/widgets/large-h_scr/arrow-right_scr_down.dds')
, SkinnableFile('/widgets/large-h_scr/arrow-right_scr_over.dds')
, SkinnableFile('/widgets/large-h_scr/arrow-right_scr_dis.dds'))
scrollRightButton.Right:Set(attachto.Right)
scrollRightButton.Bottom:Set(function() return attachto.Top() + offset end)
local scrollLeftButton = Button( scrollbar
, SkinnableFile('/widgets/large-h_scr/arrow-left_scr_up.dds')
, SkinnableFile('/widgets/large-h_scr/arrow-left_scr_down.dds')
, SkinnableFile('/widgets/large-h_scr/arrow-left_scr_over.dds')
, SkinnableFile('/widgets/large-h_scr/arrow-left_scr_dis.dds'))
scrollLeftButton.Left:Set(attachto.Left)
scrollLeftButton.Bottom:Set(function() return attachto.Top() + offset end)
scrollbar:SetTextures( UIFile('/widgets/back_scr/back_scr_mid.dds')
,UIFile('/widgets/large-h_scr/bar-mid_scr_over.dds')
,UIFile('/widgets/large-h_scr/bar-right_scr_over.dds')
,UIFile('/widgets/large-h_scr/bar-left_scr_over.dds'))
scrollbar.Left:Set(scrollLeftButton.Right)
scrollbar.Right:Set(scrollRightButton.Left)
scrollbar.Top:Set(scrollRightButton.Top)
scrollbar.Bottom:Set(scrollRightButton.Bottom)
scrollbar:AddButtons(scrollLeftButton, scrollRightButton)
scrollbar:SetScrollable(attachto)
return scrollbar
end
-- cause a dialog to get input focus, optional functions to perform when the user hits enter or escape
-- functions signature is: function()
function MakeInputModal(control, onEnterFunc, onEscFunc)
AddInputCapture(control)
local oldOnDestroy = control.OnDestroy
control.OnDestroy = function(self)
RemoveInputCapture(control)
oldOnDestroy(self)
end
if onEnterFunc or onEscFunc then
control.oldHandleEvent = control.HandleEvent
control.HandleEvent = function(self, event)
if event.Type == 'KeyDown' then
if event.KeyCode == VK_ESCAPE then
if onEscFunc then
onEscFunc()
return true
end
elseif event.KeyCode == VK_ENTER then
if onEnterFunc then
onEnterFunc()
return true
end
end
end
if control.oldHandleEvent then
return control.oldHandleEvent(self, event)
end
return true
end
end
end
-- create and manage an info dialog
-- parent: the control to parent the dialog to
-- dialogText: the text to display in the dialog
-- button1Text: text for the first button (opt)
-- button1Callback: callback function for the first button, signature function() (opt)
-- button2Text: text for the second button (opt)
-- button2Callback: callback function for the second button, signature function() (opt)
-- button3Text: text for the second button (opt)
-- button3Callback: callback function for the second button, signature function() (opt)
-- destroyOnCallback: if true, destroy when any button is pressed (if false, you must destroy) (opt)
-- modalInfo: Sets up modal info for dialog using a table in the form:
-- escapeButton = int 1-3 : the button function to mimic when the escape button is pressed
-- enterButton = int 1-3 : the button function to mimic when the enterButton is pressed
-- worldCover = bool : control if a world cover should be shown
function QuickDialog(parent, dialogText, button1Text, button1Callback, button2Text, button2Callback, button3Text, button3Callback, destroyOnCallback, modalInfo)
-- if there is a callback and destroy not specified, assume destroy
if (destroyOnCallback == nil) and (button1Callback or button2Callback or button3Callback) then
destroyOnCallback = true
end
local dialog = Group(parent, "quickDialogGroup")
LayoutHelpers.AtCenterIn(dialog, parent)
dialog.Depth:Set(GetFrame(parent:GetRootFrame():GetTargetHead()):GetTopmostDepth() + 1)
local background = Bitmap(dialog, SkinnableFile('/dialogs/dialog/panel_bmp_m.dds'))
dialog._background = background
dialog.Width:Set(background.Width)
dialog.Height:Set(background.Height)
LayoutHelpers.FillParent(background, dialog)
local textLine = {}
textLine[1] = CreateText(dialog, "", 18, titleFont)
textLine[1].Top:Set(background.Top)
LayoutHelpers.AtHorizontalCenterIn(textLine[1], dialog)
local textBoxWidth = (dialog.Width() - 80)
local tempTable = import('/lua/maui/text.lua').WrapText(LOC(dialogText), textBoxWidth,
function(text)
return textLine[1]:GetStringAdvance(text)
end)
local tempLines = table.getn(tempTable)
local prevControl = false
for i, v in tempTable do
if i == 1 then
textLine[1]:SetText(v)
prevControl = textLine[1]
else
textLine[i] = CreateText(dialog, v, 18, titleFont)
LayoutHelpers.Below(textLine[i], prevControl)
LayoutHelpers.AtHorizontalCenterIn(textLine[i], dialog)
prevControl = textLine[i]
end
end
background:SetTiled(true)
background.Bottom:Set(textLine[tempLines].Bottom)
local backgroundTop = Bitmap(dialog, SkinnableFile('/dialogs/dialog/panel_bmp_T.dds'))
backgroundTop.Bottom:Set(background.Top)
backgroundTop.Left:Set(background.Left)
local backgroundBottom = Bitmap(dialog, SkinnableFile('/dialogs/dialog/panel_bmp_b.dds'))
backgroundBottom.Top:Set(background.Bottom)
backgroundBottom.Left:Set(background.Left)
background.brackets = CreateDialogBrackets(background, 35, 65, 35, 115, true)
if not modalInfo or modalInfo.worldCover then
CreateWorldCover(dialog)
end
local function MakeButton(text, callback)
local button = CreateButtonStd( background
, '/scx_menu/small-btn/small'
, text
, 14
, 2)
if callback then
button.OnClick = function(self)
callback()
if destroyOnCallback then
dialog:Destroy()
end
end
else
button.OnClick = function(self)
dialog:Destroy()
end
end
return button
end
dialog._button1 = false
dialog._button2 = false
dialog._button3 = false
if button1Text then
dialog._button1 = MakeButton(button1Text, button1Callback)
LayoutHelpers.Below(dialog._button1, background, 0)
end
if button2Text then
dialog._button2 = MakeButton(button2Text, button2Callback)
LayoutHelpers.Below(dialog._button2, background, 0)
end
if button3Text then
dialog._button3 = MakeButton(button3Text, button3Callback)
LayoutHelpers.Below(dialog._button3, background, 0)
end
if dialog._button3 then
-- center each button to one third of the dialog
LayoutHelpers.AtHorizontalCenterIn(dialog._button2, dialog)
LayoutHelpers.LeftOf(dialog._button1, dialog._button2, -8)
LayoutHelpers.ResetLeft(dialog._button1)
LayoutHelpers.RightOf(dialog._button3, dialog._button2, -8)
backgroundTop:SetTexture(SkinnableFile('/dialogs/dialog_02/panel_bmp_T.dds'))
backgroundBottom:SetTexture(SkinnableFile('/dialogs/dialog_02/panel_bmp_b.dds'))
background:SetTexture(SkinnableFile('/dialogs/dialog_02/panel_bmp_m.dds'))
elseif dialog._button2 then
-- center each button to half the dialog
dialog._button1.Left:Set(function()
return dialog.Left() + (((dialog.Width() / 2) - dialog._button1.Width()) / 2) + 8
end)
dialog._button2.Left:Set(function()
local halfWidth = dialog.Width() / 2
return dialog.Left() + halfWidth + ((halfWidth - dialog._button2.Width()) / 2) - 8
end)
elseif dialog._button1 then
LayoutHelpers.AtHorizontalCenterIn(dialog._button1, dialog)
else
backgroundBottom:SetTexture(UIFile('/dialogs/dialog/panel_bmp_alt_b.dds'))
background.brackets:Hide()
end
if modalInfo and not modalInfo.OnlyWorldCover then
local function OnEnterFunc()
if modalInfo.enterButton then
if modalInfo.enterButton == 1 then
if dialog._button1 then
dialog._button1.OnClick(dialog._button1)
end
elseif modalInfo.enterButton == 2 then
if dialog._button2 then
dialog._button2.OnClick(dialog._button2)
end
elseif modalInfo.enterButton == 3 then
if dialog._button3 then
dialog._button3.OnClick(dialog._button3)
end
end
end
end
local function OnEscFunc()
if modalInfo.escapeButton then
if modalInfo.escapeButton == 1 then
if dialog._button1 then
dialog._button1.OnClick(dialog._button1)
end
elseif modalInfo.escapeButton == 2 then
if dialog._button2 then
dialog._button2.OnClick(dialog._button2)
end
elseif modalInfo.escapeButton == 3 then
if dialog._button3 then
dialog._button3.OnClick(dialog._button3)
end
end
end
end
MakeInputModal(dialog, OnEnterFunc, OnEscFunc)
end
return dialog
end
function CreateWorldCover(parent, colorOverride)
local NumFrame = GetNumRootFrames() - 1
local worldCovers = {}
for i = 0, NumFrame do
local index = i
if GetFrame(index) == parent:GetRootFrame() then
worldCovers[index] = Bitmap(parent)
worldCovers[index].ID = index
worldCovers[index].OnDestroy = function(self)
for h, x in worldCovers do
if x and h ~= self.ID then
x:Destroy()
end
end
end
worldCovers[index].OnHide = function(self, hidden)
for h, x in worldCovers do
if x and h ~= self.ID then
x:SetHidden(hidden)
end
end
end
else
worldCovers[index] = Bitmap(GetFrame(index))
end
worldCovers[index]:SetSolidColor(colorOverride or 'ff000000')
LayoutHelpers.FillParent(worldCovers[index], GetFrame(index))
worldCovers[index].Depth:Set(function() return parent.Depth() - 2 end)
worldCovers[index]:SetAlpha(0)
worldCovers[index]:SetNeedsFrameUpdate(true)
worldCovers[index].OnFrame = function(self, delta)
local targetAlpha = self:GetAlpha() + (delta * 1.5)
if targetAlpha < .8 then
self:SetAlpha(targetAlpha)
else
self:SetAlpha(.8)
self:SetNeedsFrameUpdate(false)
end
end
end
return worldCovers
end
function ShowInfoDialog(parent, dialogText, buttonText, buttonCallback, destroyOnCallback)
local dlg = QuickDialog(parent, dialogText, buttonText, buttonCallback, nil, nil, nil, nil, destroyOnCallback, {worldCover = false, enterButton = 1, escapeButton = 1})
return dlg
end
-- create a table of sequential file names (useful for loading animations)
function CreateSequentialFilenameTable(root, ext, first, last, numPlaces)
local retTable = {}
local formatString = string.format("%%s%%0%dd.%%s", numPlaces)
for index = first, last do
retTable[(index - first) + 1] = SkinnableFile(string.format(formatString, root, index, ext))
end
return retTable
end
-- create a box which is controlled by its external borders, and gives access to the "client" area as well
function CreateBox(parent)
local border = Border(parent)
border:SetTextures(
SkinnableFile('/game/generic_brd/generic_brd_vert_l.dds'),
SkinnableFile('/game/generic_brd/generic_brd_horz_um.dds'),
SkinnableFile('/game/generic_brd/generic_brd_ul.dds'),
SkinnableFile('/game/generic_brd/generic_brd_ur.dds'),
SkinnableFile('/game/generic_brd/generic_brd_ll.dds'),
SkinnableFile('/game/generic_brd/generic_brd_lr.dds'))
local clientArea = Bitmap(parent, SkinnableFile('/game/generic_brd/generic_brd_m.dds'))
border:LayoutControlInside(clientArea)
clientArea.Width:Set(function() return clientArea.Right() - clientArea.Left() end)
clientArea.Height:Set(function() return clientAreat.Bottom() - clientArea.Top() end)
return border, clientArea
end
-- create borders around a control, with optional background
function CreateBorder(parent, addBg)
local border = Border(parent)
border:SetTextures(
SkinnableFile('/game/generic_brd/generic_brd_vert_l.dds'),
SkinnableFile('/game/generic_brd/generic_brd_horz_um.dds'),
SkinnableFile('/game/generic_brd/generic_brd_ul.dds'),
SkinnableFile('/game/generic_brd/generic_brd_ur.dds'),
SkinnableFile('/game/generic_brd/generic_brd_ll.dds'),
SkinnableFile('/game/generic_brd/generic_brd_lr.dds'))
border:LayoutAroundControl(parent)
local bg = nil
if addBg then
bg = Bitmap(parent, SkinnableFile('/game/generic_brd/generic_brd_m.dds'))
border:LayoutControlInside(bg)
bg.Width:Set(function() return bg.Right() - bg.Left() end)
bg.Height:Set(function() return bg.Bottom() - bg.Top() end)
end
return border, bg
end
function GetFactionIcon(factionIndex)
return import('/lua/factions.lua').Factions[factionIndex + 1].Icon
end
-- make sure you lay out text box before you attempt to set text
function CreateTextBox(parent)
local box = ItemList(parent)
box:SetFont(bodyFont, 14)
box:SetColors(bodyColor, "black", highlightColor, "white")
CreateVertScrollbarFor(box)
return box
end
function SetTextBoxText(textBox, text)
textBox:DeleteAllItems()
local wrapped = import('/lua/maui/text.lua').WrapText(LOC(text), textBox.Width(), function(curText) return textBox:GetStringAdvance(curText) end)
for i, line in wrapped do
textBox:AddItem(line)
end
end
function CreateDialogBrackets(parent, leftOffset, topOffset, rightOffset, bottomOffset, altTextures)
local ret = Group(parent)
local texturePath
if altTextures then
texturePath = "/scx_menu/panel-brackets-small"
else
texturePath = "/scx_menu/panel-brackets"
end
ret.topleft = Bitmap(ret, UIFile(texturePath .. '/bracket-ul_bmp.dds'))
ret.topright = Bitmap(ret, UIFile(texturePath .. '/bracket-ur_bmp.dds'))
ret.bottomleft = Bitmap(ret, UIFile(texturePath .. '/bracket-ll_bmp.dds'))